Device-WxM2

 view release on metacpan or  search on metacpan

WxM2.pm  view on Meta::CPAN

Note: I found that I had to fiddle with a parameter in the SerialPort,
called 'read_const_time', which is like a timeout value when
waiting for read data.  I found that the value needed to be
increased significantly for the WxM2.  I use 5000 (units are
milliseconds) and this is the default setting in this package.
Should you need to change it, use
B<&setSerialPortReadTime>(time_in_millseconds).  Then call
B<&configPort>, which puts the new setting into effect.

If you want to change to archive period, use B<&setArchivePeriod> and
B<&getArchivePeriod>.  Just remember that if you screw up the values,
you station's archive will behave strangely until you fix it.

Use B<&getLastArcTime> and B<&setLastArcTime> to establish the time at which
the archives are captured into the weather station's archive
memory.

=head2 Individual Access Functions 

There are a bunch of individual functions that retrieve one weather
value from the weather station, such as b<&getOutsideTemp>.  These are
fairly self-explanatory.

=head2 Archive Retrieval and Logging Functions

There are 2 primary archive retrieval functions:  

  &getArcImg       - get Archive Image
  &getSensorImage  - get the "live" sensor data image

B<&getArcImg> retrieves the archive image at the address given to it as
a parameter.  To retrieve the most recent archived image, use this:

  my $lastPtr = $ws->getLastPtr;
  my @archiveData = $ws->getArcImg($lastPtr);

B<&getArcImg> takes the archive data, reformats it where necessary,
stores the results in class variables, and returns an array of the
data.

	@array= ($avgInsideTempInArchivePeriod, 
                 $averageOutsideTempInArchivePeriod, 
		 $outsideTempMaximumInPeriod, 
		 $outsideTempMinimumInPeriod, 
		 $barometricPressure,
		 $avgWindSpeedInPeriod, 
		 $avgWindDirInPeriod, 
		 $maxWindGustInPeriod, 
		 $rainInPeriod, 
		 $insideHumidity,
		 $outsideHumidity, 
		 $monthOfSample, 
		 $dayOfSample, 
		 $hourOfSample, 
		 $minuteOfSample, 
		 $outsideTempHumIndex, 
		 $outsideTempHumIndexMaximum,
		 $avgWindChill, 
		 $windChillMinimum);

B<&getSensorImage> enables a continuous streaming of "live" weather
data from the Davis Wx Station.  I've found this stream to be very
easy to get out of sync, so this funcion reads a single block, stops
the streaming, and flushes the serial receive buffer.  The data
returned by this function are the current values and not average
values within a sample period, like &getArcImg returns.  The array
returned is as follows:

    @array = ($insideTemp, 
	      $outsideTemp, 
	      $windSpeed, 
	      $windDirection, 
	      $barometricPressure, 
	      $insideHumidity, 
	      $outsideHumidity, 
	      $totalRainfallToday); 

There are 4 configuration functions for logging the archive data:

  &setArchiveLogFilename  - set the name of the log file to write
			    archive data
  &getArchiveLogFilename  - returns the name of the log file
  &setStationDescription  - sets the station description text (used by
                            &printRawLogHeader)
  &getStationDescription  - returns the station description string

Use B<&setArchiveLogFilename> to set the log file name.  It is used by
    all logging function calls in the class.

There are two logging functions:
  
  &archiveCurImage   - Writes the periodic data samples to a file
  &printRawLogHeader - Prints Header for the periodic samples log file

B<&archiveCurImage> writes the data samples held in the class variables
to a filename passed in as its only parameter.  For example,

  $ws->archiveCurImage();

will write the data samples as 1 line of data in the file
B<&getArchiveLogFilename>.

B<&printRawLogHeader> writes a header for the data samples into the
filename in B<&getArchiveLogFilename>.  The second line of the header for your
weather station description.  Set it with
B<&setStationDescription>("description").  Typically it contains the
name and location of the weather station.

The function B<&batchRetrieveArchives> is handy for retrieving multiple
archived images from the WxM2's archive memory.  I use it primarily
after an extended power outage, but there are lots of other reasons to
use it.  Us is at follows:

  $ws->batchRetrieveArchives($number, $filename);

where $number is the number of archives to retrieve starting with the most
recent and counting back.  And $filename is the string for the file to
write all the archive to.

The function B<&updateArchiveFromPtr> is a low-level function that retrieves archives from an initial pointer value.  B<&batchRetrieveArchives> is a user-friendly front-end for this funtion.  In most all cases B<&batchRetrieveArchives> should be used...

  $ws->updateArchiveFromPtr($lastArchivePtr, $file);

where $lastArchivePtr is the address of the last archive image that

WxM2.pm  view on Meta::CPAN

    # 21 bytes does not divide evenly into 32K bytes.  The last valid
    # pointer address is 0x7fe3.  The next pointer would be 0x7ff8,
    # but it would not have the full 21 bytes before wrapping to
    # address 0x0.  So an additional 8 bytes are subtracted when
    # calculating the wrap address.
    my $firstPtr;
    if ($sizeOfBatch > $lastPtr) {
	$firstPtr = ($lastPtr - $sizeOfBatch - 8) & 0x7fff;
    } else {
	$firstPtr = $lastPtr - $sizeOfBatch;
    }
    printf "firstPtr=%d lastPtr=%d\n", $firstPtr, $lastPtr;
    return $self->updateArchiveFromPtr($firstPtr, $file);
}

sub updateArchiveFromPtr {
    my ($self, $lastArchivedPtr, $file) = @_;
    my $i;
    my $rdFailed = 0;
    my $newPtrHex = $self->getNewPtr();
    return 0 unless defined $newPtrHex;
    my $newPtr = hex($newPtrHex) - 21;
    
    $lastArchivedPtr += 21;
    if ($lastArchivedPtr > 0x7FFF) {
	$lastArchivedPtr -= 0x7FFF;
    }

    # Push $file using local
    local $self->{archiveLogFile} = $file;
    
    printf "Update from %x to %x\n", $lastArchivedPtr, $newPtr 
	if $DEBUG > 0;
    # test for address wrapping here
    if ($newPtr < $lastArchivedPtr) {
	#  Last valid ptr addr = 0x7fe3.  0x7ff8 is NOT valid.
	for ($i=$lastArchivedPtr; $i < 0x7FF8; $i+=21) {
	    unless ($self->getArcImg($i)) {
		$rdFailed = 1;
		last;
	    }
	    $self->archiveCurImage();
	    printf "Archived address %x\n",$i if $DEBUG > 0;
	}
	$lastArchivedPtr = 0;
    }

    return 0 if $rdFailed;
    for ($i=$lastArchivedPtr; $i <= $newPtr; $i+=21) {
	$self->getArcImg($i);
	#unless ($self->getArcImg($i)) {
#	    return 0;
	#}
	$self->archiveCurImage();
	printf "Archived address %x\n",$i if $DEBUG > 0;
    }
    return 1;
}

##
## `getSensorImage' enables a continuous streaming of 18 byte chunks of 
## weather data from the Davis Wx Station.  I've found this stream to be
## very easy to get out of sync, so this funcion read a single 18 byte chunk, 
## stops the streaming, and flushes the serial Rx buffer
##
sub getSensorImage {
    ##### LOOP ######
    #  Monitor, Wizard, and Perception Sensor Image:
    #       start of block                     1 byte
    #       inside temperature                 2 bytes
    #       outside temperature                2 bytes
    #       wind speed                         1 byte
    #       wind direction                     2 bytes
    #       barometer                          2 bytes
    #       inside humidity                    1 byte
    #       outside humidity                   1 byte
    #       total rain                         2 bytes
    #       not used                           2 bytes
    #       CRC checksum                       2 bytes
    #                                         --------
    #                                         18 bytes
    #################
    my $self = shift;

    $wxPort->write("LOOP");
#    $wxPort->write(pack "C2", 65535);  # doesn't work in perl 5.8
    $wxPort->write(pack "C2", 255, 255); 
    $wxPort->write(pack "C", 0xD);

    return undef unless ($self->_get_ack());

    my ($count, $string_in) = $wxPort->read(16);
    warn "read unsuccessful\n" unless (($count == 16) && ($DEBUG > 0));

    my @str_in = unpack "C16", $string_in;
    my $inTemp = $self->tempConv($str_in[1], $str_in[2]);
    my $outTemp = $self->tempConv($str_in[3], $str_in[4]);
    my $baro = ($str_in[9]*256 + $str_in[8])/1000;
    if ($self->{isBaroCalSet}) {
	# subtract baroCal, to compensate for lower absolute pressure at 
	# higher altitudes
	$baro -= $self->{baroCal};
    }
    my $tot_rain = ($str_in[13]*256 + $str_in[12])/100;
    my $wind = $str_in[5];
    my $windAdjDir = ($str_in[7]*256 + $str_in[6] + 11) % 360;
    my $windDirDegree = $windAdjDir;
    my $windDirDeg16 = int $windDirDegree/22.5;
    my $windDir = $compass_rose[$windDirDeg16];
    my $inHum = $str_in[10];
    my $outHum = $str_in[11];
    if ($DEBUG > 1) {
	printf "Inside Temp is %f Degrees F\n", $inTemp;
	printf "Outside Temp is %f Degrees F\n", $outTemp;
	printf "Wind speed is %d\n", $wind;
	printf "Wind dir is %d\n", $windDir;
	printf "Barometer reads %f\n", $baro;
	printf "Inside Humidity is %d%\n", $inHum;
	printf "Outside Humidity is %d%\n", $outHum;
	printf "Total rainfall is %f\n", $tot_rain;
    }
    my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
    $self->{outTemp} = sprintf("%02.1f", $outTemp);
    $self->{inTemp} = sprintf("%02.1f",$inTemp);



( run in 1.445 second using v1.01-cache-2.11-cpan-39bf76dae61 )