successfully decoding loop pkts with Mojo
authorDirk Koopman <djk@tobit.co.uk>
Fri, 11 Jul 2014 22:41:37 +0000 (23:41 +0100)
committerDirk Koopman <djk@tobit.co.uk>
Fri, 11 Jul 2014 22:41:37 +0000 (23:41 +0100)
a.pl [new file with mode: 0755]
dirk-ae.pl [new file with mode: 0755]
dumpraw.pl [new file with mode: 0755]
loop.pl [new file with mode: 0755]

diff --git a/a.pl b/a.pl
new file mode 100755 (executable)
index 0000000..51a503c
--- /dev/null
+++ b/a.pl
@@ -0,0 +1,545 @@
+#!/usr/bin/perl
+
+use DBI;
+use strict;
+use Device::SerialPort;
+use Time::HiRes;
+
+my $devname = "/dev/davis";
+my $dbsort = "SQLite";
+my $db="weather.db";
+my $host="";
+my $userid="";
+my $passwd="";
+my $connectionInfo="dbi:$dbsort:$db";
+$connectionInfo .= ":$host" if $host;
+
+# make connection to database
+my %attr = ( PrintError => 0, RaiseError => 0 );
+my $dbh = DBI->connect($connectionInfo,$userid,$passwd,\%attr) or die "Couldn't connect to database: " . DBI->errstr;
+
+
+my ($count, $result);
+my %hsh;
+my @crc_table=();
+my %bar_trend=();
+load_crc_table();
+
+my $ob = Device::SerialPort->new ($devname) || die;
+
+$ob->user_msg(1);                              # misc. warnings
+$ob->error_msg(1);                             # hardware and data errors
+
+$ob->baudrate(19200);
+$ob->parity("none");
+#$ob->parity_enable(1);        # for any parity except "none"
+$ob->databits(8);
+$ob->stopbits(1);
+$ob->handshake('none');
+$ob->read_const_time(15000);   # ultimate timeout (15 seconds)
+$ob->write_settings||die"setting failed";
+
+
+my $awake=0;
+my $attempts=0;
+$ob->write("\n");                              # initial wake
+
+while ($awake==0) {
+       $ob->write("\n");                                  # wake for real
+       $ob->read_interval(600);                   # wait for a max of 600ms
+       ($count, $result) = $ob->read(10); # read up to 10 chars
+       if ($result eq "\n\r") {
+               print "awoke on attempt $attempts :)\n";
+               $awake=1;
+       } else {
+               print "wake error on attempt $attempts :(\n";
+       }
+       $attempts++;
+       dienice("failed to wake device - tried $attempts times") unless $attempts<6;
+}
+
+$ob->write("LAMPS 0\n");
+$ob->read_interval(300);                 # wait for a max of 300ms
+($count, $result) = $ob->read(8); # read up to 8 chars
+$result=~s/(\r|\n)//g;
+if ($result eq "OK") {
+       print "lamps on :)\n";
+} else {
+       dienice("lamp error '$result'");
+}
+
+
+
+my $ref=gettime();
+$ref->[5]+=1900;
+print "$ref->[2]:$ref->[1]:$ref->[0] $ref->[3]/$ref->[4]/$ref->[5]\n";
+
+#settime();
+
+#do_dmpaft();
+
+while (1) {
+       get_loop();     # if you do anything after here - you need to wake up the device again
+       print "** do something else\n";
+       sleep 5;
+       $ob->write("\r");                                               #  wake
+       $ob->read_interval(500);                                # wait for a max of 300ms
+       my ($count, $result) = $ob->read(4096); # read any crap up to 4096 chars
+}
+
+#print "count=$count $result\n";
+#for(my $i=0; $i<$count; $i++)
+#{ printf("%02d ",ord(substr($result,$i,1))); }
+
+#$ob->write("WRD\x12\x4d\n");
+
+undef $ob;
+exit 0;
+
+sub dienice
+{
+       my $err=shift;
+       print "$err\n";
+       undef $ob;
+       exit 9;
+}
+
+sub parse_loop_blck
+{
+       my $blk = shift;
+       my $loo =  substr $blk,0,3;
+       unless ( $loo eq 'LOO') {
+               warn("Block invalid loo -> $loo\n"); return "";
+       }
+       my $t;
+
+       #$hsh{'next_rec'}     = unpack("s", substr $blk,5,2);
+
+       $hsh{'Barometric_Trend'}    = unpack("C", substr $blk,3,1);
+       $hsh{'Barometric_Trend_txt'} = $bar_trend{$hsh{'Barometric_Trend'}};
+       $t = unpack("s", substr $blk,7,2) / 1000;
+       #       $hsh{'Barometric_Press_hg'}          = $t;
+       $hsh{'Barometric_Press_mb'} = sprintf("%.2f",$t*33.8637526);
+
+
+       $t = unpack("s", substr $blk,9,2) / 10;
+       #       $hsh{'Air_Temp_Inside_f'}      = $t;
+       $hsh{'Air_Temp_Inside_c'} = sprintf("%.1f",($t - 32) * 5/9);
+       my $tf  = unpack("s", substr $blk,12,2) / 10;
+       #       $hsh{'Air_Temp_Outside_f'}     = $tf;
+       $hsh{'Air_Temp_Outside_c'}  = sprintf("%.1f",($tf - 32) * 5/9);
+
+       $hsh{'Wind_Speed_mph'}   = unpack("C", substr $blk,14,1);
+       #       $hsh{'Wind_Speed_mps'} = sprintf("%.1f",$hsh{'Wind_Speed_mph'}*0.44704);
+       $hsh{'Wind_Speed_10min_Avg_mph'} = unpack("C", substr $blk,15,1);
+       #       $hsh{'Wind_Speed_10min_Avg_mps'} = sprintf("%.1f",$hsh{'Wind_Speed_10min_Avg_mph'}*0.44704);
+       $hsh{'Wind_Dir'}     = unpack("s", substr $blk,16,2);
+
+
+       $hsh{'Humidity_Outside'} = unpack("C", substr $blk,33,1);
+       $hsh{'Humidity_Inside'}  = unpack("C", substr $blk,11,1);
+       $hsh{'Dew_Point'}  = dew_point($tf, $hsh{'Humidity_Outside'});
+
+       #       $hsh{'UV'}         = unpack("C", substr $blk,43,1);
+       #       $hsh{'Solar'}  = unpack("s", substr $blk,44,2); # watt/m**2
+
+       $hsh{'Rain_Rate'}  = (unpack("s", substr $blk,41,2) / 100) * 25.4; # Inches per hr converted to mm
+       $hsh{'Rain_Storm'} = (unpack("s", substr $blk,46,2) / 100) * 25.4; # Inches per storm
+       #$hsh{'Storm_Date'} = unpack("s", substr $blk,48,2);  # Need to parse data (not sure what this is)
+       $hsh{'Rain_Day'}   = (unpack("s", substr $blk,50,2)/100) * 25.4;
+       $hsh{'Rain_Month'}  = (unpack("s", substr $blk,52,2)/100) * 25.4;
+       $hsh{'Rain_Year'}  = (unpack("s", substr $blk,54,2)/100) * 25.4;
+
+       $hsh{'ET_Day'}   = unpack("s", substr $blk,56,2)/1000;
+       $hsh{'ET_Month'}  = unpack("s", substr $blk,58,2)/100;
+       $hsh{'ET_Year'}  = unpack("s", substr $blk,60,2)/100;
+
+       #$hsh{'Alarms_Inside'}  = unpack("b8", substr $blk,70,1);
+       #$hsh{'Alarms_Rain'}  = unpack("b8", substr $blk,70,1);
+       #$hsh{'Alarms_Outside'}  = unpack("b8", substr $blk,70,1);
+
+       $hsh{'Batt_Transmitter'}  = unpack("C", substr $blk,86,1); #  * 0.005859375
+       $hsh{'Batt_Console'}  = unpack("s", substr $blk,87,2) * 0.005859375;
+
+       $hsh{'Forecast_Icon'}  = unpack("C", substr $blk,89,1);
+       $hsh{'Forecast_Rule'}  = unpack("C", substr $blk,90,1);
+
+       $hsh{'Sunrise'}  = sprintf( "%04d", unpack("S", substr $blk,91,2) );
+       $hsh{'Sunrise'}  =~ s/(\d{2})(\d{2})/$1:$2/;
+       $hsh{'Sunset'}   = sprintf( "%04d", unpack("S", substr $blk,93,2) );
+       $hsh{'Sunset'}  =~ s/(\d{2})(\d{2})/$1:$2/;
+
+       #my $nl  =  ord substr $blk,95,1;
+       #my $cr  =  ord substr $blk,96,1;
+
+       my $crc = unpack "%n", substr($blk,97,2);
+       my $crc_calc = CRC_CCITT($blk);
+
+       if ($crc_calc==0) {
+               return 0;
+       }
+       else {
+               print "CRC check failed for LOOP data!\n";
+               return 1;
+       }
+       #delete @hsh{'crc', 'crc_calc', 'next_rec'};
+       #delete($hsh{crc})||die"cant delete crc";
+       #delete($hsh{crc_calc})||die"cant delete crc_calc";
+       #delete($hsh{next_rec})||die"cant delete next_rec";
+
+}
+
+sub dew_point
+{
+       my $temp = shift @_;
+       my $rh   = shift @_;
+
+       #  Using the simplified approximation for dew point
+       #  Accurate to 1 degree C for humidities > 50 %
+       #  http://en.wikipedia.org/wiki/Dew_point
+
+       my $dew_point = $temp - ( (100 - $rh)/5 );
+
+       return $dew_point;
+}
+
+sub CRC_CCITT
+{
+    # Expects packed data...
+    my $data_str = shift @_;
+
+       my $crc = 0;
+       my @lst = split //, $data_str;
+       foreach my $data (@lst) {
+               my $data = unpack("c",$data);
+
+               my $crc_prev = $crc;
+               my $index = $crc >> 8 ^ $data;
+               my $lhs = $crc_table[$index];
+               #print "lhs=$lhs, crc=$crc\n";
+               my $rhs = ($crc << 8) & 0xFFFF;
+               $crc = $lhs ^ $rhs;
+
+
+       }
+
+       return $crc;
+}
+
+sub load_crc_table
+{
+
+       @crc_table = (
+                                 0x0, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+                                 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+                                 0x1231, 0x210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+                                 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+                                 0x2462, 0x3443, 0x420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+                                 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+                                 0x3653, 0x2672, 0x1611, 0x630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+                                 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+                                 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x840, 0x1861, 0x2802, 0x3823,
+                                 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+                                 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0xa50, 0x3a33, 0x2a12,
+                                 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+                                 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0xc60, 0x1c41,
+                                 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+                                 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0xe70,
+                                 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+                                 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+                                 0x1080, 0xa1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+                                 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+                                 0x2b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+                                 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+                                 0x34e2, 0x24c3, 0x14a0, 0x481, 0x7466, 0x6447, 0x5424, 0x4405,
+                                 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+                                 0x26d3, 0x36f2, 0x691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+                                 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+                                 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x8e1, 0x3882, 0x28a3,
+                                 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+                                 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0xaf1, 0x1ad0, 0x2ab3, 0x3a92,
+                                 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+                                 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0xcc1,
+                                 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+                                 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0xed1, 0x1ef0
+                                );
+
+       $bar_trend{-60} = "Falling Rapidly";
+       $bar_trend{196} = "Falling Rapidly";
+       $bar_trend{-20} = "Falling Slowly";
+       $bar_trend{236} = "Falling Slowly";
+       $bar_trend{0} = "Steady";
+       $bar_trend{20} = "Rising Slowly";
+       $bar_trend{60} = "Rising Rapidly";
+}
+
+sub gettime
+{
+    $ob->write("GETTIME\n");
+       $ob->read_interval(200);
+       my($cnt_in, $str) = $ob->read(9);
+       if ($cnt_in==0) {
+               dienice("read error cnt_in=$cnt_in, str='$str'");
+       }
+
+       my $ck = CRC_CCITT(substr($str,1,9));
+       if ( $ck ) {
+               warn "checksum error"; return 0;
+       }
+       my @rsp_lst =  split //, $str;
+       shift @rsp_lst;
+       @rsp_lst = map ord, @rsp_lst;
+    return \@rsp_lst;
+}
+
+sub settime
+{
+    my $s_time = [ localtime() ];
+    $s_time->[4] += 1;
+
+       $ob->write("SETTIME\n");
+       $ob->read_interval(300);
+       my ($cnt_in, $str) = $ob->read(1);
+       my $ack = ord $str;
+       if ( $ack != 6 ) {
+               warn "SETTIME not set ack $ack !"; return 0;
+       }
+       my ($sec, $min, $hour, $day, $mon, $yr) = @{$s_time};
+       $str = join "", map chr, ($sec, $min, $hour, $day, $mon, $yr);
+       my $ck = CRC_CCITT($str);
+       $str = $str . pack("n",$ck);
+       $ob->write($str);
+       ($cnt_in, $str) = $ob->read(1);
+       if ( ord($str) != 6 ) {
+               warn "SETTIME not set!"; return 0;
+       }
+       sleep 3;                  # The console seems to need to some time here...
+}
+
+sub get_loop
+{
+       print "** get loop at ", scalar localtime, "\n";
+       my $loops=1;
+       $ob->write("LOOP $loops\n");
+       $ob->read_interval(0);
+       ($count, $result) = $ob->read(1);
+       for (my $i=0; $i<$loops; $i+=1) {
+               my $rc=loop_dump();
+               if ($rc!=0) {
+                       last;
+               }
+       }
+       return;
+
+}
+
+sub loop_dump
+{
+       $ob->read_interval(0);
+       ($count, $result) = $ob->read(99);
+       if ($count != 99) {
+               print "loop error - got $count bytes, expected 99\n";
+               return 1;
+       }
+       print "LOOP data received\n";
+
+       if (ord(substr($result,0,1))==6) {
+               $result=substr($result,1);
+       }
+
+       my $rc=parse_loop_blck($result);
+       if ($rc!=0) {
+               return;
+       }                                                       # bad crc so goto next
+       foreach my $key (sort keys %hsh) {
+               print "$key = $hsh{$key}\n";
+       }
+
+       my $stmt = 'INSERT INTO current (Date_Time,' . join(',', keys %hsh) . ') VALUES (NOW(),' . join(',', ('?') x keys %hsh) . ')';
+
+       $dbh->do( $stmt, undef, values %hsh);
+
+       %hsh=();
+       return 0;
+}
+
+
+sub do_dmpaft
+{
+       #my $self = shift @_;
+       open(DMP,">dump.txt");
+       my $vDateStamp = shift @_;
+       my $vTimeStamp = shift @_;
+
+       # If not date/time stamp then assume 0 which will down load the entire archive
+       unless ( $vDateStamp ) {
+               $vDateStamp = 0;
+       }
+       unless ( $vTimeStamp ) {
+               $vTimeStamp = 0;
+       }
+
+       #my $port_obj = $self->{'port_obj'};
+
+       my $datetime = pack("ss",$vDateStamp, $vTimeStamp);
+
+       my $crc = CRC_CCITT($datetime);
+       my $cmd = pack("ssn",$vDateStamp,$vTimeStamp,$crc);
+
+       #-----------------------
+       #my $str = unpack("H*", $cmd);
+       #$str =~ s/(\w{2})/$1 /g;
+       # Documentation is wrong! The example should be <0xC6><0x06><0xA2><0x03> in section X
+       #print "cmd : $str \n";exit;
+       #-----------------------
+
+       #sleep 2; # Needed after loop
+       #$self->wake_up();
+
+       # Ok let's start the communication sequence....
+       my $cnt_out = $ob->write("DMPAFT\n");
+       unless ($cnt_out) {
+               warn "write failed\n";
+       }
+       ;
+
+       $ob->read_interval(300);
+       my ($cnt_in, $str) = $ob->read(1);
+
+       my $ack = ord $str;
+       unless ($ack == 6) {
+               warn "Ack not received on DMPAFT command: $ack"; exit -1;
+       }
+
+       $cnt_out = $ob->write($cmd);
+       unless ($cnt_out) {
+               warn "write failed\n";
+       }
+       ;
+       ($cnt_in, $str) = $ob->read(7);
+
+       $ack = ord substr($str,0,1);
+
+       my $ls = unpack("H20",substr($str,1,4) );
+       $ls =~ s/(\w{2})/$1 /g;
+
+       my $pages = unpack("s",substr($str,1,2) );
+       my $rec_start = unpack("s",substr($str,3,2) );
+
+       $crc = CRC_CCITT(substr($str,1,6) );
+
+       print "Pages = $pages : rec = $rec_start Datestamp $vDateStamp $crc\n";
+
+       $cnt_out = $ob->write( pack("h", 0x06) );
+
+       #if ($pages == 513 ) { return -1 }
+
+       my @arc_rec_lst;
+       foreach my $page (1..$pages) {
+               my $page_sz = 267;
+               $ob->read_interval(0);
+               my ($cnt_in, $str) = $ob->read($page_sz); #,3
+               printf("len=%s\n",length($str));
+               if ($cnt_in!=$page_sz) {
+                       dienice("hmm, dmpaft only got $cnt_in bytes. was expecting $page_sz");
+               }
+               print "Page $page\n";
+               #print DMP $str,"\n";
+               #print "ACK receipt of page $page\n";
+               #$ob->write( pack("h", 0x06) );
+               #next;
+               my $calc_crc = CRC_CCITT($str);
+               my $crc = unpack "%n", substr($str,265,2);
+               print "page crc=$crc, calc_crc=$calc_crc\n";
+               my $rec_sz = 52;
+               my $date_prev = 0;
+               my %hsh;
+
+               foreach my $rec ( 0..4 ) {
+                       if ( ($page == 1) && ($rec < $rec_start ) ) {
+                               next;
+                       }                                       # Find the right starting point...
+
+                       my $start_ptr = 1 + ($rec * $rec_sz );
+                       my $rec_str = substr($str, $start_ptr ,52);
+
+                       #print "$start_ptr \t > " . unpack( "h*", $rec_str) . "\n";
+
+                       my $date = substr($rec_str,0,2);
+                       my $date_curr =  unpack "s", $date;
+
+                       # Check if we have wrapped...
+                       if ( $date_curr < $date_prev ) {
+                               last;
+                       }
+                       $date_prev = $date_curr;
+
+                       $hsh{'date_stamp'} =  $date_curr;
+                       $hsh{'time_stamp'} =  unpack "s", substr($rec_str,2,2);
+
+                       $hsh{'day'}    = unpack( "c", $date & pack("c",0x1F) );
+                       $hsh{'month'}  = ( $hsh{'date_stamp'} >> 5) & 0xF;
+                       $hsh{'year'}  =  ( $hsh{'date_stamp'} >> 9) + 2000;
+
+                       $hsh{'hour'}  = sprintf("%02d", int ( $hsh{'time_stamp'} / 100 ));
+
+                       $hsh{'min'}  =  $hsh{'time_stamp'} - ($hsh{'hour'} * 100);
+                       $hsh{'min'}  =  sprintf("%02d", $hsh{'min'});
+
+                       $hsh{'time_stamp_fmt'}  =  "$hsh{'hour'}:$hsh{'min'}:00";
+                       $hsh{'date_stamp_fmt'}  =  "$hsh{'year'}_$hsh{'month'}_$hsh{'day'}";
+
+                       #$hsh{'unixtime'} = timelocal(0,$hsh{min}, $hsh{hour}, $hsh{day}, $hsh{month}-1, $hsh{year}-1900);
+
+                       $hsh{'Air_Temp'} = unpack("s", substr($rec_str,4,2)) / 10;
+                       $hsh{'Air_Temp_Hi'} = unpack("s", substr($rec_str,6,2)) / 10;
+                       $hsh{'Air_Temp_Lo'} = unpack("s", substr($rec_str,8,2)) / 10;
+                       $hsh{'Rain_Clicks'} = unpack("s", substr($rec_str,10,2));
+                       $hsh{'Rain_Rate'}   = unpack("s", substr($rec_str,12,2)) / 100; # Inches per hour
+                       $hsh{'Barometric_Press'}   = unpack("s", substr $rec_str,14,2) / 1000;
+                       $hsh{'Solar'}   = unpack("s", substr $rec_str,16,2); # watt/m**2
+                       $hsh{'Wind_Samples'}  = unpack("s", substr $rec_str,18,2);
+                       $hsh{'Air_Temp_Inside'}  = unpack("s", substr $rec_str,20,2) / 10;
+
+                       $hsh{'Relative_Humidity_Inside'}  = unpack("C", substr $rec_str,22,1);
+                       $hsh{'Relative_Humidity'} = unpack("C", substr $rec_str,23,1);
+
+                       $hsh{'Wind_Speed'}    =  unpack("C", substr($rec_str,24,1));
+                       $hsh{'Wind_Gust_Max'} = unpack("C", substr($rec_str,25,1));
+                       $hsh{'Wind_Dir_Max'}  = unpack("C", substr($rec_str,26,1));
+                       $hsh{'Wind_Dir'}      = unpack("C", substr($rec_str,27,1));
+
+                       $hsh{'UV'} = unpack("C", substr($rec_str,28,1)) / 10;
+                       $hsh{'ET'} = unpack("C", substr($rec_str,29,1)) / 1000;
+
+                       $hsh{'Solar_Max'} = unpack("s", substr($rec_str,30,2));
+                       $hsh{'UV_Max'} = unpack("C", substr($rec_str,32,1));
+
+                       $hsh{'Forecast_Rule'} = unpack("C", substr($rec_str,33,1));
+
+                       #                       $hsh{'Dew_Point'}  = _dew_point($hsh{'Air_Temp'},$hsh{'Relative_Humidity'});
+
+                       # Miscellaneous others omitted for now
+
+                       print "date> $hsh{'Air_Temp'} $hsh{'time_stamp'} $hsh{'time_stamp_fmt'}  $hsh{'date_stamp'} $hsh{'date_stamp_fmt'}\n";
+                       #print Dumper \%hsh;
+
+                       push @arc_rec_lst, {%hsh};
+               }
+
+               #$in = <STDIN>; # Testing step through facility
+               #if ($in =~ /q/i ) {  $port_obj->write( pack("h", 0x1B) ); last; }
+               #else              {  $port_obj->write( pack("h", 0x06) ); }
+               print "ACK receipt of page\n";
+               $ob->write( pack("h", 0x06) );
+
+       }
+       close DMP;
+}
+
+package Device::SerialPort;
+
+sub read_interval
+{
+
+}
diff --git a/dirk-ae.pl b/dirk-ae.pl
new file mode 100755 (executable)
index 0000000..7ad9d5b
--- /dev/null
@@ -0,0 +1,562 @@
+#!/usr/bin/perl
+
+use DBI;
+use strict;
+use Device::SerialPort;
+use Time::HiRes;
+use AnyEvent;
+
+my $devname = "/dev/davis";
+my $dbsort = "SQLite";         
+my $db="weather.db";
+my $host="";
+my $userid="";
+my $passwd="";
+my $connectionInfo="dbi:$dbsort:$db";
+$connectionInfo .= ":$host" if $host;
+
+# make connection to database
+my %attr = ( PrintError => 0, RaiseError => 0 );
+my $dbh = DBI->connect($connectionInfo,$userid,$passwd,\%attr) or die "Couldn't connect to database: " . DBI->errstr;
+
+
+my ($count, $result);
+my %hsh;
+my @crc_table=();
+my %bar_trend=();
+load_crc_table();
+
+my $ob = Device::SerialPort->new ($devname) || die;
+
+$ob->user_msg(1);                              # misc. warnings
+$ob->error_msg(1);                             # hardware and data errors
+
+$ob->baudrate(19200);
+$ob->parity("none");
+#$ob->parity_enable(1);        # for any parity except "none"
+$ob->databits(8);
+$ob->stopbits(1);
+$ob->handshake('none');
+$ob->read_const_time(15000);   # ultimate timeout (15 seconds)
+$ob->write_settings||die"setting failed";
+
+my $cv = AE::cv;
+
+my $hdl = new AnyEvent::Handle(
+                                                        fh => $ob->{HANDLE},
+                                                        on_error => sub {
+                                                                my ($hdl, $fatal, $msg) = @_;
+                                                                AE::log error => $msg;
+                                                                $hdl->destroy;
+                                                                $cv->send;
+                                                        },
+                                                       );
+
+$hdl->push_write("\n");                        # kick the serial port
+my $awake=0;
+my $attempts=0;
+#$ob->write("\n");                             # initial wake
+
+while ($awake==0) {
+       
+       $hdl->push_write("\n");                 # wake for real
+       $hdl->push_read(regex => qr<\n\r>, timeout => sub )
+       $ob->read_interval(600);        # wait for a max of 600ms
+       ($count, $result) = $ob->read(10); # read up to 10 chars
+       if ($result eq "\n\r") {
+               print "awoke on attempt $attempts :)\n"; 
+               $awake=1;
+       }
+       else {
+               print "wake error on attempt $attempts :(\n";
+       }
+       $attempts++;
+       dienice("failed to wake device - tried $attempts times") unless $attempts<6;
+}
+
+$ob->write("LAMPS 0\n");
+$ob->read_interval(300);               # wait for a max of 300ms
+($count, $result) = $ob->read(8); # read up to 8 chars
+$result=~s/(\r|\n)//g;
+if ($result eq "OK") {
+       print "lamps on :)\n";
+}
+else {
+       dienice("lamp error '$result'");
+}
+
+
+
+my $ref=gettime();
+$ref->[5]+=1900;
+print "$ref->[2]:$ref->[1]:$ref->[0] $ref->[3]/$ref->[4]/$ref->[5]\n";
+
+#settime();
+
+#do_dmpaft();
+
+while (1) {
+       get_loop();                                     # if you do anything after here - you need to wake up the device again
+       print "** do something else\n";
+       sleep 5;
+       $ob->write("\r");                       #  wake
+       $ob->read_interval(500);        # wait for a max of 300ms
+       my ($count, $result) = $ob->read(4096); # read any crap up to 4096 chars
+}
+
+#print "count=$count $result\n";
+#for(my $i=0; $i<$count; $i++)
+#{ printf("%02d ",ord(substr($result,$i,1))); }
+
+#$ob->write("WRD\x12\x4d\n");
+
+undef $ob; 
+exit 0;
+
+sub dienice
+{
+       my $err=shift;
+       print "$err\n";
+       undef $ob;
+       exit 9;
+}
+
+sub parse_loop_blck 
+{
+       my $blk = shift; 
+       my $loo =  substr $blk,0,3;  
+       unless ( $loo eq 'LOO') {
+               warn("Block invalid loo -> $loo\n"); return "";
+       } 
+       my $t;
+    
+       #$hsh{'next_rec'}     = unpack("s", substr $blk,5,2);  
+  
+       $hsh{'Barometric_Trend'}    = unpack("C", substr $blk,3,1);
+       $hsh{'Barometric_Trend_txt'} = $bar_trend{$hsh{'Barometric_Trend'}};
+       $t = unpack("s", substr $blk,7,2) / 1000; 
+#      $hsh{'Barometric_Press_hg'}          = $t;
+       $hsh{'Barometric_Press_mb'} = sprintf("%.2f",$t*33.8637526); 
+  
+
+       $t = unpack("s", substr $blk,9,2) / 10;
+#      $hsh{'Air_Temp_Inside_f'}      = $t;
+       $hsh{'Air_Temp_Inside_c'} = sprintf("%.1f",($t - 32) * 5/9);
+       my $tf  = unpack("s", substr $blk,12,2) / 10; 
+#      $hsh{'Air_Temp_Outside_f'}     = $tf;
+       $hsh{'Air_Temp_Outside_c'}  = sprintf("%.1f",($tf - 32) * 5/9);
+  
+       $hsh{'Wind_Speed_mph'}   = unpack("C", substr $blk,14,1); 
+#      $hsh{'Wind_Speed_mps'} = sprintf("%.1f",$hsh{'Wind_Speed_mph'}*0.44704);
+       $hsh{'Wind_Speed_10min_Avg_mph'} = unpack("C", substr $blk,15,1);
+#      $hsh{'Wind_Speed_10min_Avg_mps'} = sprintf("%.1f",$hsh{'Wind_Speed_10min_Avg_mph'}*0.44704);
+       $hsh{'Wind_Dir'}     = unpack("s", substr $blk,16,2);
+  
+  
+       $hsh{'Humidity_Outside'} = unpack("C", substr $blk,33,1);
+       $hsh{'Humidity_Inside'}  = unpack("C", substr $blk,11,1);
+       $hsh{'Dew_Point'}  = dew_point($tf, $hsh{'Humidity_Outside'});
+  
+#      $hsh{'UV'}         = unpack("C", substr $blk,43,1);
+#      $hsh{'Solar'}  = unpack("s", substr $blk,44,2); # watt/m**2
+  
+       $hsh{'Rain_Rate'}  = (unpack("s", substr $blk,41,2) / 100) * 25.4; # Inches per hr converted to mm
+       $hsh{'Rain_Storm'} = (unpack("s", substr $blk,46,2) / 100) * 25.4; # Inches per storm
+       #$hsh{'Storm_Date'} = unpack("s", substr $blk,48,2);  # Need to parse data (not sure what this is)
+       $hsh{'Rain_Day'}   = (unpack("s", substr $blk,50,2)/100) * 25.4;  
+       $hsh{'Rain_Month'}  = (unpack("s", substr $blk,52,2)/100) * 25.4;  
+       $hsh{'Rain_Year'}  = (unpack("s", substr $blk,54,2)/100) * 25.4; 
+  
+       $hsh{'ET_Day'}   = unpack("s", substr $blk,56,2)/1000;  
+       $hsh{'ET_Month'}  = unpack("s", substr $blk,58,2)/100;  
+       $hsh{'ET_Year'}  = unpack("s", substr $blk,60,2)/100;  
+  
+       #$hsh{'Alarms_Inside'}  = unpack("b8", substr $blk,70,1);  
+       #$hsh{'Alarms_Rain'}  = unpack("b8", substr $blk,70,1);  
+       #$hsh{'Alarms_Outside'}  = unpack("b8", substr $blk,70,1);  
+  
+       $hsh{'Batt_Transmitter'}  = unpack("C", substr $blk,86,1); #  * 0.005859375
+       $hsh{'Batt_Console'}  = unpack("s", substr $blk,87,2) * 0.005859375; 
+  
+       $hsh{'Forecast_Icon'}  = unpack("C", substr $blk,89,1);  
+       $hsh{'Forecast_Rule'}  = unpack("C", substr $blk,90,1); 
+  
+       $hsh{'Sunrise'}  = sprintf( "%04d", unpack("S", substr $blk,91,2) );  
+       $hsh{'Sunrise'}  =~ s/(\d{2})(\d{2})/$1:$2/; 
+       $hsh{'Sunset'}   = sprintf( "%04d", unpack("S", substr $blk,93,2) );  
+       $hsh{'Sunset'}  =~ s/(\d{2})(\d{2})/$1:$2/;
+  
+       #my $nl  =  ord substr $blk,95,1;  
+       #my $cr  =  ord substr $blk,96,1;   
+
+       my $crc = unpack "%n", substr($blk,97,2); 
+       my $crc_calc = CRC_CCITT($blk); 
+  
+       if ($crc_calc==0) {
+               return 0;
+       }
+       else {
+               print "CRC check failed for LOOP data!\n";
+               return 1;
+       }
+       #delete @hsh{'crc', 'crc_calc', 'next_rec'};
+       #delete($hsh{crc})||die"cant delete crc";
+       #delete($hsh{crc_calc})||die"cant delete crc_calc";
+       #delete($hsh{next_rec})||die"cant delete next_rec";
+  
+}
+
+sub dew_point
+{
+       my $temp = shift @_; 
+       my $rh   = shift @_; 
+  
+       #  Using the simplified approximation for dew point 
+       #  Accurate to 1 degree C for humidities > 50 %  
+       #  http://en.wikipedia.org/wiki/Dew_point
+
+       my $dew_point = $temp - ( (100 - $rh)/5 ); 
+    
+       return $dew_point; 
+}
+
+sub CRC_CCITT
+{
+    # Expects packed data... 
+    my $data_str = shift @_;
+
+       my $crc = 0;
+       my @lst = split //, $data_str;
+       foreach my $data (@lst) {
+               my $data = unpack("c",$data); 
+       
+               my $crc_prev = $crc;
+               my $index = $crc >> 8 ^ $data;
+               my $lhs = $crc_table[$index];
+               #print "lhs=$lhs, crc=$crc\n";
+               my $rhs = ($crc << 8) & 0xFFFF;
+               $crc = $lhs ^ $rhs;
+       
+          
+       }
+               
+       return $crc;
+}
+
+sub load_crc_table
+{
+
+       @crc_table = (
+                                 0x0, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+                                 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+                                 0x1231, 0x210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+                                 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+                                 0x2462, 0x3443, 0x420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+                                 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+                                 0x3653, 0x2672, 0x1611, 0x630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+                                 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+                                 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x840, 0x1861, 0x2802, 0x3823,
+                                 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+                                 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0xa50, 0x3a33, 0x2a12,
+                                 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+                                 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0xc60, 0x1c41,
+                                 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+                                 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0xe70,
+                                 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+                                 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+                                 0x1080, 0xa1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+                                 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+                                 0x2b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+                                 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+                                 0x34e2, 0x24c3, 0x14a0, 0x481, 0x7466, 0x6447, 0x5424, 0x4405,
+                                 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+                                 0x26d3, 0x36f2, 0x691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+                                 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+                                 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x8e1, 0x3882, 0x28a3,
+                                 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+                                 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0xaf1, 0x1ad0, 0x2ab3, 0x3a92,
+                                 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+                                 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0xcc1,
+                                 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+                                 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0xed1, 0x1ef0
+                                );
+
+       $bar_trend{-60} = "Falling Rapidly"; 
+       $bar_trend{196} = "Falling Rapidly";
+       $bar_trend{-20} = "Falling Slowly"; 
+       $bar_trend{236} = "Falling Slowly";
+       $bar_trend{0} = "Steady";
+       $bar_trend{20} = "Rising Slowly";
+       $bar_trend{60} = "Rising Rapidly";
+}
+
+sub gettime
+{
+    $ob->write("GETTIME\n");
+       $ob->read_interval(200);
+       my($cnt_in, $str) = $ob->read(9);
+       if ($cnt_in==0) {
+               dienice("read error cnt_in=$cnt_in, str='$str'");
+       }
+       
+       my $ck = CRC_CCITT(substr($str,1,9));
+       if ( $ck ) {
+               warn "checksum error"; return 0;
+       }
+       my @rsp_lst =  split //, $str;
+       shift @rsp_lst; 
+       @rsp_lst = map ord, @rsp_lst; 
+    return \@rsp_lst; 
+}
+
+sub settime
+{
+    my $s_time = [ localtime() ]; 
+    $s_time->[4] += 1; 
+    
+       $ob->write("SETTIME\n");
+       $ob->read_interval(300);
+       my ($cnt_in, $str) = $ob->read(1);
+       my $ack = ord $str; 
+       if ( $ack != 6 ) {
+               warn "SETTIME not set ack $ack !"; return 0;
+       }
+       my ($sec, $min, $hour, $day, $mon, $yr) = @{$s_time};
+       $str = join "", map chr, ($sec, $min, $hour, $day, $mon, $yr);  
+       my $ck = CRC_CCITT($str);
+       $str = $str . pack("n",$ck); 
+       $ob->write($str);
+       ($cnt_in, $str) = $ob->read(1);
+       if ( ord($str) != 6 ) {
+               warn "SETTIME not set!"; return 0;
+       }
+       sleep 3;                                        # The console seems to need to some time here... 
+}
+
+sub get_loop
+{
+       print "** get loop at ", scalar localtime, "\n";
+       my $loops=1;
+       $ob->write("LOOP $loops\n");
+       $ob->read_interval(0);
+       ($count, $result) = $ob->read(1);
+       for (my $i=0; $i<$loops; $i+=1) {
+               my $rc=loop_dump(); 
+               if ($rc!=0) {
+                       last;
+               }
+       }
+       return;
+
+}
+
+sub loop_dump
+{
+       $ob->read_interval(0);
+       ($count, $result) = $ob->read(99);
+       if ($count != 99) {
+               print "loop error - got $count bytes, expected 99\n";
+               return 1;
+       }
+       print "LOOP data received\n";
+
+       if (ord(substr($result,0,1))==6) {
+               $result=substr($result,1);
+       }
+
+       my $rc=parse_loop_blck($result);
+       if ($rc!=0) {
+               return;
+       }                                                       # bad crc so goto next
+       foreach my $key (sort keys %hsh) {
+               print "$key = $hsh{$key}\n";
+       }
+
+       my $stmt = 'INSERT INTO current (Date_Time,' . join(',', keys %hsh) . ') VALUES (NOW(),' . join(',', ('?') x keys %hsh) . ')';
+
+       $dbh->do( $stmt, undef, values %hsh);
+
+       %hsh=();
+       return 0;
+}
+
+
+sub do_dmpaft
+{
+       #my $self = shift @_;
+       open(DMP,">dump.txt");
+       my $vDateStamp = shift @_;
+       my $vTimeStamp = shift @_; 
+
+       # If not date/time stamp then assume 0 which will down load the entire archive
+       unless ( $vDateStamp ) {
+               $vDateStamp = 0;
+       } 
+       unless ( $vTimeStamp ) {
+               $vTimeStamp = 0;
+       } 
+       #my $port_obj = $self->{'port_obj'}; 
+  
+       my $datetime = pack("ss",$vDateStamp, $vTimeStamp); 
+       my $crc = CRC_CCITT($datetime);
+       my $cmd = pack("ssn",$vDateStamp,$vTimeStamp,$crc); 
+
+       #-----------------------  
+       #my $str = unpack("H*", $cmd); 
+       #$str =~ s/(\w{2})/$1 /g; 
+       # Documentation is wrong! The example should be <0xC6><0x06><0xA2><0x03> in section X
+       #print "cmd : $str \n";exit; 
+       #-----------------------  
+
+       #sleep 2; # Needed after loop 
+       #$self->wake_up();  
+       # Ok let's start the communication sequence.... 
+       my $cnt_out = $ob->write("DMPAFT\n");
+       unless ($cnt_out) {
+               warn "write failed\n";
+       }
+       ;
+       $ob->read_interval(300);
+       my ($cnt_in, $str) = $ob->read(1);
+  
+       my $ack = ord $str; 
+       unless ($ack == 6) {
+               warn "Ack not received on DMPAFT command: $ack"; exit -1;
+       }
+       $cnt_out = $ob->write($cmd);
+       unless ($cnt_out) {
+               warn "write failed\n";
+       }
+       ;
+       ($cnt_in, $str) = $ob->read(7); 
+       $ack = ord substr($str,0,1);    
+    
+       my $ls = unpack("H20",substr($str,1,4) ); 
+       $ls =~ s/(\w{2})/$1 /g; 
+       my $pages = unpack("s",substr($str,1,2) ); 
+       my $rec_start = unpack("s",substr($str,3,2) ); 
+  
+       $crc = CRC_CCITT(substr($str,1,6) );
+
+       print "Pages = $pages : rec = $rec_start Datestamp $vDateStamp $crc\n"; 
+       
+       $cnt_out = $ob->write( pack("h", 0x06) );
+       #if ($pages == 513 ) { return -1 }
+       my @arc_rec_lst;          
+       foreach my $page (1..$pages) {
+               my $page_sz = 267;      
+               $ob->read_interval(0);
+               my ($cnt_in, $str) = $ob->read($page_sz); #,3
+               printf("len=%s\n",length($str));
+               if ($cnt_in!=$page_sz) {
+                       dienice("hmm, dmpaft only got $cnt_in bytes. was expecting $page_sz");
+               }
+               print "Page $page\n"; 
+               #print DMP $str,"\n";
+               #print "ACK receipt of page $page\n";
+               #$ob->write( pack("h", 0x06) );
+               #next;
+               my $calc_crc = CRC_CCITT($str);
+               my $crc = unpack "%n", substr($str,265,2);
+               print "page crc=$crc, calc_crc=$calc_crc\n";
+               my $rec_sz = 52;
+               my $date_prev = 0;      
+               my %hsh;
+         
+               foreach my $rec ( 0..4 ) {
+                       if ( ($page == 1) && ($rec < $rec_start ) ) {
+                               next;
+                       }                                       # Find the right starting point... 
+
+                       my $start_ptr = 1 + ($rec * $rec_sz );    
+                       my $rec_str = substr($str, $start_ptr ,52);
+                 
+                       #print "$start_ptr \t > " . unpack( "h*", $rec_str) . "\n"; 
+                 
+                       my $date = substr($rec_str,0,2);  
+                       my $date_curr =  unpack "s", $date;
+                 
+                       # Check if we have wrapped... 
+                       if ( $date_curr < $date_prev ) {
+                               last;
+                       }       
+                       $date_prev = $date_curr;       
+                 
+                       $hsh{'date_stamp'} =  $date_curr; 
+                       $hsh{'time_stamp'} =  unpack "s", substr($rec_str,2,2); 
+                  
+                       $hsh{'day'}    = unpack( "c", $date & pack("c",0x1F) ); 
+                       $hsh{'month'}  = ( $hsh{'date_stamp'} >> 5) & 0xF; 
+                       $hsh{'year'}  =  ( $hsh{'date_stamp'} >> 9) + 2000; 
+               
+                       $hsh{'hour'}  = sprintf("%02d", int ( $hsh{'time_stamp'} / 100 )); 
+                 
+                       $hsh{'min'}  =  $hsh{'time_stamp'} - ($hsh{'hour'} * 100);  
+                       $hsh{'min'}  =  sprintf("%02d", $hsh{'min'}); 
+               
+                       $hsh{'time_stamp_fmt'}  =  "$hsh{'hour'}:$hsh{'min'}:00"; 
+                       $hsh{'date_stamp_fmt'}  =  "$hsh{'year'}_$hsh{'month'}_$hsh{'day'}"; 
+
+                       #$hsh{'unixtime'} = timelocal(0,$hsh{min}, $hsh{hour}, $hsh{day}, $hsh{month}-1, $hsh{year}-1900);
+                                 
+                       $hsh{'Air_Temp'} = unpack("s", substr($rec_str,4,2)) / 10; 
+                       $hsh{'Air_Temp_Hi'} = unpack("s", substr($rec_str,6,2)) / 10; 
+                       $hsh{'Air_Temp_Lo'} = unpack("s", substr($rec_str,8,2)) / 10;
+                       $hsh{'Rain_Clicks'} = unpack("s", substr($rec_str,10,2));
+                       $hsh{'Rain_Rate'}   = unpack("s", substr($rec_str,12,2)) / 100; # Inches per hour
+                       $hsh{'Barometric_Press'}   = unpack("s", substr $rec_str,14,2) / 1000;  
+                       $hsh{'Solar'}   = unpack("s", substr $rec_str,16,2); # watt/m**2
+                       $hsh{'Wind_Samples'}  = unpack("s", substr $rec_str,18,2);   
+                       $hsh{'Air_Temp_Inside'}  = unpack("s", substr $rec_str,20,2) / 10;  
+
+                       $hsh{'Relative_Humidity_Inside'}  = unpack("C", substr $rec_str,22,1);
+                       $hsh{'Relative_Humidity'} = unpack("C", substr $rec_str,23,1);
+
+                       $hsh{'Wind_Speed'}    =  unpack("C", substr($rec_str,24,1)); 
+                       $hsh{'Wind_Gust_Max'} = unpack("C", substr($rec_str,25,1));
+                       $hsh{'Wind_Dir_Max'}  = unpack("C", substr($rec_str,26,1));
+                       $hsh{'Wind_Dir'}      = unpack("C", substr($rec_str,27,1));
+
+                       $hsh{'UV'} = unpack("C", substr($rec_str,28,1)) / 10;
+                       $hsh{'ET'} = unpack("C", substr($rec_str,29,1)) / 1000;
+
+                       $hsh{'Solar_Max'} = unpack("s", substr($rec_str,30,2)); 
+                       $hsh{'UV_Max'} = unpack("C", substr($rec_str,32,1));
+                 
+                       $hsh{'Forecast_Rule'} = unpack("C", substr($rec_str,33,1));
+               
+#                      $hsh{'Dew_Point'}  = _dew_point($hsh{'Air_Temp'},$hsh{'Relative_Humidity'}); 
+                                       
+                       # Miscellaneous others omitted for now
+                                       
+                       print "date> $hsh{'Air_Temp'} $hsh{'time_stamp'} $hsh{'time_stamp_fmt'}  $hsh{'date_stamp'} $hsh{'date_stamp_fmt'}\n";                  
+                       #print Dumper \%hsh; 
+                 
+                       push @arc_rec_lst, {%hsh}; 
+               }       
+                 
+               #$in = <STDIN>; # Testing step through facility
+               #if ($in =~ /q/i ) {  $port_obj->write( pack("h", 0x1B) ); last; }
+               #else              {  $port_obj->write( pack("h", 0x06) ); }
+               print "ACK receipt of page\n";
+               $ob->write( pack("h", 0x06) );
+         
+       }
+       close DMP;
+}
+
+package Device::SerialPort;
+
+sub read_interval
+{
+
+}
diff --git a/dumpraw.pl b/dumpraw.pl
new file mode 100755 (executable)
index 0000000..8e639fc
--- /dev/null
@@ -0,0 +1,133 @@
+#!/usr/bin/perl
+
+use DBI;
+use strict;
+use Time::HiRes;
+use Serial;
+use Device::SerialPort;
+use Mojo::IOLoop;
+use Mojo::IOLoop::Stream;
+
+my $devname = "/dev/davis";
+
+#my $ob = Serial->new ($devname, 19200) || die;
+my $ob = Device::SerialPort->new ($devname) || die;
+
+$ob->user_msg(1);                              # misc. warnings
+$ob->error_msg(1);                             # hardware and data errors
+
+$ob->baudrate(19200);
+$ob->parity("none");
+#$ob->parity_enable(1);        # for any parity except "none"
+$ob->databits(8);
+$ob->stopbits(1);
+$ob->handshake('none');
+$ob->read_const_time(15000);   # ultimate timeout (15 seconds)
+$ob->write_settings||die"setting failed";
+
+$ob->read_char_time(0);
+$ob->read_const_time(300);
+
+my $awake=0;
+my $attempts=0;
+$ob->write("\n");                              # initial wak
+
+my $awake = 0;
+my $attempts;
+
+while ($awake==0) {
+       $ob->write("\n");                                  # wake for real
+       my ($count, $result) = $ob->read(10); # read up to 10 chars
+       if ($result eq "\n\r") {
+               print "awoke on attempt $attempts :)\n";
+               $awake=1;
+       } else {
+               print "wake error on attempt $attempts :(\n";
+       }
+       $attempts++;
+       die("failed to wake device - tried $attempts times\n") unless $attempts<6;
+}
+
+$ob->write("STRMON\n");
+
+my $end;
+
+$SIG{TERM} = $SIG{INT} = sub {++$end; print "\nending $end\n";};
+
+while (!$end) {
+
+#      print "end: $end\n";
+       
+       my ($count, $l) = $ob->read(255); 
+       next unless $count;
+
+       s|\cM|<CR>|g;
+       s|\cJ|<NL>|g;
+       s|\cI|<TAB>|g;
+       
+       my @l = split /[\cJ\cM]/, $l;
+       my ($wspeed, $wdir, $val1, $val2, $sort, $batt);
+
+       my @hex;
+       
+       for (@l) {
+               next unless $_;
+               my ($k, $v) = $_ =~ /^(\d)\s+=\s+([\dabcdef]+)/;
+               next unless defined $k && defined $v;
+               my $h = hex $v;
+               push @hex, $h;
+               if ($k == 0) {
+                       if (($h & 0xf0) == 0x80) {
+                               $sort = "T";
+                       } elsif (($h & 0xf0) == 0xa0) {
+                               $sort = 'H';
+                       } elsif (($h & 0xf0) == 0xe0) {
+                               $sort = 'R';
+                       } elsif (($h & 0xf0) == 0x50) {
+                               $sort = 'P';
+                       } else {
+                               $sort = 'W';    # wind only
+                       }
+                       if ($h & 0x08) {        # new battery required
+                               $batt = ' NB';
+                       }
+               } elsif ($k == 1) {
+                       $wspeed = $h;
+               } elsif ($k == 2) {
+                       $wdir = int($h * 360 / 255);
+               } elsif ($k == 3) {
+                       $val2 = $val1 = $h;
+               } elsif ($k == 4) {
+                       if ($sort eq 'H') {
+                               $val2 = (($h >> 4) << 8) | $val2;
+                       } elsif ($sort eq 'T') {
+                               $val2 = ($h << 8) | $val2;
+                       } else {
+                               $val2 = ($val2 << 8) | $h;
+                       }
+               }
+       }
+       if ($sort) {
+               printf("%02X ", $_) for (@hex);
+               if ($sort eq 'T') {     
+                       printf "$sort$batt %3d %3d %0.1f\n", $wspeed, $wdir, (($val2/160) - 32) * 5/9;
+               } elsif ($sort eq 'H') {
+                       printf "$sort$batt %3d %3d %0.1f\n", $wspeed, $wdir, $val2/10;
+               } elsif ($sort eq 'P') {
+                       printf "$sort$batt %3d %3d %0.2f\n", $wspeed, $wdir, $val2 / 1000;
+               } elsif ($sort eq 'R') {
+                       printf "$sort$batt %3d %3d $val1\n", $wspeed, $wdir;
+               } elsif ($sort eq 'W') {
+                       printf "$sort$batt %3d %3d\n", $wspeed, $wdir, $val2;
+               } else {
+                       print "\n";
+               }
+       }
+}
+
+$ob->write("STRMOFF\n");
+$ob->read(255);
+exit(0);
+
+
+
diff --git a/loop.pl b/loop.pl
new file mode 100755 (executable)
index 0000000..ef0c4e0
--- /dev/null
+++ b/loop.pl
@@ -0,0 +1,252 @@
+#!/usr/bin/perl
+use strict;
+
+use v5.10.1;
+
+use DBI;
+use Serial;
+use Mojo::IOLoop;
+use Mojo::IOLoop::Stream;
+
+my $devname = "/dev/davis";
+my $tid;
+my $rid;
+my $count;
+my $state = "ready";
+my $buf;
+
+our    @crc_table = (
+                                 0x0, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+                                 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+                                 0x1231, 0x210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+                                 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+                                 0x2462, 0x3443, 0x420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+                                 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+                                 0x3653, 0x2672, 0x1611, 0x630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+                                 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+                                 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x840, 0x1861, 0x2802, 0x3823,
+                                 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+                                 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0xa50, 0x3a33, 0x2a12,
+                                 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+                                 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0xc60, 0x1c41,
+                                 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+                                 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0xe70,
+                                 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+                                 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+                                 0x1080, 0xa1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+                                 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+                                 0x2b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+                                 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+                                 0x34e2, 0x24c3, 0x14a0, 0x481, 0x7466, 0x6447, 0x5424, 0x4405,
+                                 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+                                 0x26d3, 0x36f2, 0x691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+                                 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+                                 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x8e1, 0x3882, 0x28a3,
+                                 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+                                 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0xaf1, 0x1ad0, 0x2ab3, 0x3a92,
+                                 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+                                 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0xcc1,
+                                 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+                                 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0xed1, 0x1ef0
+                                );
+
+our %bar_trend;
+
+$bar_trend{-60} = "Falling Rapidly";
+$bar_trend{196} = "Falling Rapidly";
+$bar_trend{-20} = "Falling Slowly";
+$bar_trend{236} = "Falling Slowly";
+$bar_trend{0} = "Steady";
+$bar_trend{20} = "Rising Slowly";
+$bar_trend{60} = "Rising Rapidly";
+
+#$SIG{TERM} = $SIG{INT} = sub {Mojo::IOLoop->reset if Mojo::IOLoop->is_running && !$DB::VERSION};
+
+my $s = do_open($devname);
+start_loop();
+
+Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
+
+exit 0;
+
+sub on_read
+{
+       my ($str, $d) = @_;
+       $buf .= $d;
+       $d =~ s/([\%\x00-\x1f\x7f-\xff])/sprintf("%%%02X", ord($1))/eg; 
+#      say "read added '$d' buf lth=" . length $buf;
+       if ($state eq 'waitnl' && $buf =~ /[\cJ\cM]+/) {
+               undef $tid;
+               undef $buf;
+               $s->write("LOOP 1\n");
+               chgstate("waitloop");
+       } elsif ($state eq "waitloop") {
+               if ($buf =~ /\x06/) {
+                       chgstate('waitlooprec');
+                       undef $buf;
+               }
+       } elsif ($state eq 'waitlooprec') {
+               if (length $buf >= 99) {
+                       say "got loop record\n";
+                       chgstate('');
+                       process($buf);
+                       undef $buf;
+               }
+       }
+}
+
+sub start_loop
+{
+       say "writing \\n";
+       $s->write("\n");
+       $tid = Mojo::IOLoop->timer(0.6 => sub {say "writing \\n"; $s->write("\n")});
+       chgstate("waitnl");
+}
+
+sub chgstate
+{
+       say "state '$state' -> '$_[0]'";
+       $state = $_[0];
+}
+
+sub do_open
+{
+       my $name = shift;
+       my $ob = Serial->new($name, 19200) || die "$name $!\n";
+       say "streaming $name fileno(", fileno($ob), ")";
+       my $str = Mojo::IOLoop::Stream->new($ob);
+       $str->on(error=>sub {say "serial $_[1]"; undef $s; Mojo::IOLoop->reset;});
+       $str->on(close=>sub {say "serial closing"; undef $s;  Mojo::IOLoop->reset;});
+       $str->on(timeout=>sub {say "serial timeout";});
+       $str->on(read=>sub {on_read(@_)});
+       $str->start;
+
+       $rid = Mojo::IOLoop->recurring(2.5 => sub {start_loop() if !$state || $state eq "waitnl";});
+
+       return $str;
+}
+
+sub process
+{
+       my $blk = shift;
+       my $loo =  substr $blk,0,3;
+       unless ( $loo eq 'LOO') {
+               say "Block invalid loo -> $loo"; return;
+       }
+
+       my $t;
+       my %hsh;
+
+
+       #$hsh{'next_rec'}     = unpack("s", substr $blk,5,2);
+
+       $hsh{'Barometric_Trend'}    = unpack("C", substr $blk,3,1);
+       $hsh{'Barometric_Trend_txt'} = $bar_trend{$hsh{'Barometric_Trend'}};
+       $t = unpack("s", substr $blk,7,2) / 1000;
+       #       $hsh{'Barometric_Press_hg'}          = $t;
+       $hsh{'Barometric_Press_mb'} = sprintf("%.2f",$t*33.8637526);
+
+
+       $t = unpack("s", substr $blk,9,2) / 10;
+       #       $hsh{'Air_Temp_Inside_f'}      = $t;
+       $hsh{'Air_Temp_Inside_c'} = sprintf("%.1f",($t - 32) * 5/9);
+       my $tf  = unpack("s", substr $blk,12,2) / 10;
+       #       $hsh{'Air_Temp_Outside_f'}     = $tf;
+       $hsh{'Air_Temp_Outside_c'}  = sprintf("%.1f",($tf - 32) * 5/9);
+
+       $hsh{'Wind_Speed_mph'}   = unpack("C", substr $blk,14,1);
+       #       $hsh{'Wind_Speed_mps'} = sprintf("%.1f",$hsh{'Wind_Speed_mph'}*0.44704);
+       $hsh{'Wind_Speed_10min_Avg_mph'} = unpack("C", substr $blk,15,1);
+       #       $hsh{'Wind_Speed_10min_Avg_mps'} = sprintf("%.1f",$hsh{'Wind_Speed_10min_Avg_mph'}*0.44704);
+       $hsh{'Wind_Dir'}     = unpack("s", substr $blk,16,2);
+
+
+       $hsh{'Humidity_Outside'} = unpack("C", substr $blk,33,1);
+       $hsh{'Humidity_Inside'}  = unpack("C", substr $blk,11,1);
+       $hsh{'Dew_Point'}  = dew_point($tf, $hsh{'Humidity_Outside'});
+
+       #       $hsh{'UV'}         = unpack("C", substr $blk,43,1);
+       #       $hsh{'Solar'}  = unpack("s", substr $blk,44,2); # watt/m**2
+
+       $hsh{'Rain_Rate'}  = (unpack("s", substr $blk,41,2) / 100) * 25.4; # Inches per hr converted to mm
+       $hsh{'Rain_Storm'} = (unpack("s", substr $blk,46,2) / 100) * 25.4; # Inches per storm
+       #$hsh{'Storm_Date'} = unpack("s", substr $blk,48,2);  # Need to parse data (not sure what this is)
+       $hsh{'Rain_Day'}   = (unpack("s", substr $blk,50,2)/100) * 25.4;
+       $hsh{'Rain_Month'}  = (unpack("s", substr $blk,52,2)/100) * 25.4;
+       $hsh{'Rain_Year'}  = (unpack("s", substr $blk,54,2)/100) * 25.4;
+
+       $hsh{'ET_Day'}   = unpack("s", substr $blk,56,2)/1000;
+       $hsh{'ET_Month'}  = unpack("s", substr $blk,58,2)/100;
+       $hsh{'ET_Year'}  = unpack("s", substr $blk,60,2)/100;
+
+       #$hsh{'Alarms_Inside'}  = unpack("b8", substr $blk,70,1);
+       #$hsh{'Alarms_Rain'}  = unpack("b8", substr $blk,70,1);
+       #$hsh{'Alarms_Outside'}  = unpack("b8", substr $blk,70,1);
+
+       $hsh{'Batt_Transmitter'}  = unpack("C", substr $blk,86,1); #  * 0.005859375
+       $hsh{'Batt_Console'}  = unpack("s", substr $blk,87,2) * 0.005859375;
+
+       $hsh{'Forecast_Icon'}  = unpack("C", substr $blk,89,1);
+       $hsh{'Forecast_Rule'}  = unpack("C", substr $blk,90,1);
+
+       $hsh{'Sunrise'}  = sprintf( "%04d", unpack("S", substr $blk,91,2) );
+       $hsh{'Sunrise'}  =~ s/(\d{2})(\d{2})/$1:$2/;
+       $hsh{'Sunset'}   = sprintf( "%04d", unpack("S", substr $blk,93,2) );
+       $hsh{'Sunset'}  =~ s/(\d{2})(\d{2})/$1:$2/;
+
+       #my $nl  =  ord substr $blk,95,1;
+       #my $cr  =  ord substr $blk,96,1;
+
+       my $crc = unpack "%n", substr($blk,97,2);
+       my $crc_calc = CRC_CCITT($blk);
+
+       if ($crc_calc==0) {
+               say "inside: $hsh{Air_Temp_Inside_c} degC $hsh{Humidity_Inside}\% outside: $hsh{Air_Temp_Outside_c} degC $hsh{Humidity_Outside}\% wind: $hsh{Wind_Speed_mph} $hsh{Wind_Dir} deg $hsh{Barometric_Press_mb} mB";
+               
+       } else {
+               print "CRC check failed for LOOP data!\n";
+               return 1;
+       }
+       #delete @hsh{'crc', 'crc_calc', 'next_rec'};
+       #delete($hsh{crc})||die"cant delete crc";
+       #delete($hsh{crc_calc})||die"cant delete crc_calc";
+       #delete($hsh{next_rec})||die"cant delete next_rec";
+}
+
+sub dew_point
+{
+       my $temp = shift @_;
+       my $rh   = shift @_;
+
+       #  Using the simplified approximation for dew point
+       #  Accurate to 1 degree C for humidities > 50 %
+       #  http://en.wikipedia.org/wiki/Dew_point
+
+       my $dew_point = $temp - ( (100 - $rh)/5 );
+
+       return $dew_point;
+}
+
+sub CRC_CCITT
+{
+    # Expects packed data...
+    my $data_str = shift @_;
+
+       my $crc = 0;
+       my @lst = split //, $data_str;
+       foreach my $data (@lst) {
+               my $data = unpack("c",$data);
+
+               my $crc_prev = $crc;
+               my $index = $crc >> 8 ^ $data;
+               my $lhs = $crc_table[$index];
+               #print "lhs=$lhs, crc=$crc\n";
+               my $rhs = ($crc << 8) & 0xFFFF;
+               $crc = $lhs ^ $rhs;
+
+
+       }
+
+       return $crc;
+}
+