line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Device::VantagePro; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
48077
|
use 5.008008; |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
42
|
|
4
|
1
|
|
|
1
|
|
7
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
37
|
|
5
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
98
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
require Exporter; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our $VERSION = '0.25'; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
#-#use Win32::SerialPort qw(:STAT 0.19 ); |
14
|
1
|
|
|
1
|
|
1392
|
use Device::SerialPort qw(:STAT 0.19 ); |
|
1
|
|
|
|
|
48357
|
|
|
1
|
|
|
|
|
285
|
|
15
|
|
|
|
|
|
|
|
16
|
1
|
|
|
1
|
|
1076
|
use Time::HiRes qw(usleep gettimeofday time); |
|
1
|
|
|
|
|
1823
|
|
|
1
|
|
|
|
|
5
|
|
17
|
1
|
|
|
1
|
|
1382
|
use Data::Dumper; |
|
1
|
|
|
|
|
28938
|
|
|
1
|
|
|
|
|
79
|
|
18
|
|
|
|
|
|
|
|
19
|
1
|
|
|
1
|
|
9
|
use POSIX qw(:errno_h :fcntl_h strftime); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
10
|
|
20
|
|
|
|
|
|
|
|
21
|
1
|
|
|
1
|
|
1743
|
use Time::Local; |
|
1
|
|
|
|
|
1930
|
|
|
1
|
|
|
|
|
4061
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); |
24
|
|
|
|
|
|
|
our @EXPORT_OK = qw(); |
25
|
|
|
|
|
|
|
our @EXPORT = qw(); |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
our $Verbose = 0; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - |
30
|
|
|
|
|
|
|
sub new |
31
|
|
|
|
|
|
|
{ |
32
|
0
|
|
|
0
|
1
|
|
my $caller = shift @_; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# In case someone wants to sub-class |
35
|
0
|
|
|
|
|
|
my $caller_is_obj = ref($caller); |
36
|
0
|
|
0
|
|
|
|
my $class = $caller_is_obj || $caller; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# Passing reference or hash |
39
|
0
|
|
|
|
|
|
my %arg_hsh; |
40
|
0
|
0
|
|
|
|
|
if ( ref($_[0]) eq "HASH" ) { %arg_hsh = %{ shift @_ } } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
41
|
0
|
|
|
|
|
|
else { %arg_hsh = @_ } |
42
|
|
|
|
|
|
|
|
43
|
0
|
|
0
|
|
|
|
my $port = $arg_hsh{'port'} || "/dev/ttyS0"; |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
#my $conf = $arg_hsh{'conf'} || 'Conf.ini'; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
#my $port_obj = new Win32::SerialPort ($port) || die "Can't open $port: $^E\n"; |
48
|
0
|
|
0
|
|
|
|
my $port_obj = new Device::SerialPort ($port) || die "Can't open $port: $^E\n"; |
49
|
|
|
|
|
|
|
|
50
|
0
|
|
0
|
|
|
|
my $baudrate = $arg_hsh{baudrate} || 19200; |
51
|
0
|
|
0
|
|
|
|
my $parity = $arg_hsh{parity} || "none"; |
52
|
0
|
|
0
|
|
|
|
my $databits = $arg_hsh{databits} || 8; |
53
|
0
|
|
0
|
|
|
|
my $stopbits = $arg_hsh{stopbits} || 1; |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# After new, must check for failure |
56
|
0
|
|
|
|
|
|
$port_obj->baudrate($baudrate); |
57
|
0
|
|
|
|
|
|
$port_obj->parity($parity); |
58
|
0
|
|
|
|
|
|
$port_obj->databits($databits); |
59
|
0
|
|
|
|
|
|
$port_obj->stopbits($stopbits); |
60
|
|
|
|
|
|
|
#-# $port_obj->read_interval(1); # max time between read char (milliseconds) Not in Device::SerialPort |
61
|
|
|
|
|
|
|
|
62
|
0
|
|
|
|
|
|
$port_obj->read_const_time(10000); # total = (avg * bytes) + const |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
#$port_obj->handshake("rts"); |
65
|
|
|
|
|
|
|
#$port_obj->buffers(4096, 4096); |
66
|
|
|
|
|
|
|
|
67
|
0
|
0
|
|
|
|
|
$port_obj->write_settings || warn 'Write Settings Failed'; |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
#$port_obj->save($conf); |
70
|
|
|
|
|
|
|
|
71
|
0
|
0
|
|
|
|
|
unless ($port_obj) { die "Can't change Device_Control_Block: $^E\n"; } |
|
0
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
|
73
|
0
|
|
0
|
|
|
|
my ($BlockingFlags, $InBytes, $OutBytes, $LatchErrorFlags) = $port_obj->status |
74
|
|
|
|
|
|
|
|| warn "could not get port status\n"; |
75
|
|
|
|
|
|
|
|
76
|
0
|
0
|
|
|
|
|
if ($BlockingFlags) |
77
|
|
|
|
|
|
|
{ |
78
|
|
|
|
|
|
|
#warn "Port is blocked $BlockingFlags, $InBytes, $OutBytes, $LatchErrorFlags\n"; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
0
|
|
|
|
|
|
$port_obj->purge_all(); # these don't seem to work but try anyway. |
82
|
0
|
|
|
|
|
|
$port_obj->purge_rx(); |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# The object data structure |
85
|
0
|
|
|
|
|
|
my $self = bless { |
86
|
|
|
|
|
|
|
'arg_hsh' => { %arg_hsh }, |
87
|
|
|
|
|
|
|
'port_obj' => $port_obj, |
88
|
|
|
|
|
|
|
'loop_cnt' => 0, |
89
|
|
|
|
|
|
|
}, $class; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# if ( $self->wake_up() ) { print "Station found ready for communications\n" } |
92
|
|
|
|
|
|
|
|
93
|
0
|
|
|
|
|
|
return $self; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
97
|
|
|
|
|
|
|
sub wake_up |
98
|
|
|
|
|
|
|
{ |
99
|
0
|
|
|
0
|
1
|
|
my $self = shift @_; |
100
|
|
|
|
|
|
|
|
101
|
0
|
|
|
|
|
|
foreach (1..3) |
102
|
|
|
|
|
|
|
{ |
103
|
0
|
|
|
|
|
|
my $cnt_out = $self->{'port_obj'}->write("\n"); |
104
|
0
|
0
|
|
|
|
|
unless ($cnt_out) { warn "write failed\n" }; |
|
0
|
|
|
|
|
|
|
105
|
0
|
|
|
|
|
|
my ($cnt_in, $str) = $self->read(2); |
106
|
|
|
|
|
|
|
|
107
|
0
|
0
|
|
|
|
|
if ($str eq "\n\r" ) |
108
|
|
|
|
|
|
|
{ |
109
|
0
|
0
|
|
|
|
|
print "Success on Wakeup $_\n" if $Verbose; |
110
|
0
|
|
|
|
|
|
return 1; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
|
warn "Not responding to Wakeup\n"; |
114
|
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
|
usleep 1200000; # As per page 5 of VantagePro Doc |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
0
|
|
|
|
|
|
warn("Could not unit wake up"); |
119
|
0
|
|
|
|
|
|
return -1; # fail |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - |
123
|
|
|
|
|
|
|
sub plug_test |
124
|
|
|
|
|
|
|
{ |
125
|
0
|
|
|
0
|
0
|
|
my $self = shift @_; |
126
|
|
|
|
|
|
|
|
127
|
0
|
|
|
|
|
|
my $port_obj = $self->{'port_obj'}; |
128
|
|
|
|
|
|
|
|
129
|
0
|
|
|
|
|
|
my $str = "TEST\n"; |
130
|
|
|
|
|
|
|
|
131
|
0
|
|
|
|
|
|
print "Sending $str"; |
132
|
0
|
|
|
|
|
|
my $cnt_out = $port_obj->write($str); |
133
|
0
|
0
|
|
|
|
|
unless ($cnt_out) { warn "write failed\n" }; |
|
0
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
my ($cnt_in, $str_in) = $port_obj->read(8); |
136
|
|
|
|
|
|
|
|
137
|
0
|
|
|
|
|
|
print "returned: $cnt_in, $str_in"; |
138
|
|
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
return $str; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - |
143
|
|
|
|
|
|
|
sub do_dmpaft |
144
|
|
|
|
|
|
|
{ |
145
|
0
|
|
|
0
|
1
|
|
my $self = shift @_; |
146
|
|
|
|
|
|
|
|
147
|
0
|
|
|
|
|
|
my $vDateStamp = shift @_; |
148
|
0
|
|
|
|
|
|
my $vTimeStamp = shift @_; |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# If not date/time stamp then assume 0 which will down load the entire archive |
151
|
0
|
0
|
|
|
|
|
unless ( $vDateStamp ) { $vDateStamp = 0 } |
|
0
|
|
|
|
|
|
|
152
|
0
|
0
|
|
|
|
|
unless ( $vTimeStamp ) { $vTimeStamp = 0 } |
|
0
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
|
154
|
0
|
|
|
|
|
|
my $port_obj = $self->{'port_obj'}; |
155
|
|
|
|
|
|
|
|
156
|
0
|
|
|
|
|
|
my $datetime = pack("ss",$vDateStamp, $vTimeStamp); |
157
|
|
|
|
|
|
|
|
158
|
0
|
|
|
|
|
|
my $crc = CRC_CCITT($datetime); |
159
|
0
|
|
|
|
|
|
my $cmd = pack("ssn",$vDateStamp,$vTimeStamp,$crc); |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
#----------------------- |
162
|
|
|
|
|
|
|
#my $str = unpack("H*", $cmd); |
163
|
|
|
|
|
|
|
#$str =~ s/(\w{2})/$1 /g; |
164
|
|
|
|
|
|
|
# Documentation is wrong! The example should be <0xC6><0x06><0xA2><0x03> in section X |
165
|
|
|
|
|
|
|
#print "cmd : $str \n";exit; |
166
|
|
|
|
|
|
|
#----------------------- |
167
|
|
|
|
|
|
|
|
168
|
0
|
|
|
|
|
|
sleep 2; # Needed after loop |
169
|
0
|
|
|
|
|
|
$self->wake_up(); |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# Ok let's start the communication sequence.... |
172
|
0
|
|
|
|
|
|
my $cnt_out = $port_obj->write("DMPAFT\n"); |
173
|
0
|
0
|
|
|
|
|
unless ($cnt_out) { warn "write failed\n" }; |
|
0
|
|
|
|
|
|
|
174
|
0
|
|
|
|
|
|
my ($cnt_in, $str) = $self->read(1); |
175
|
|
|
|
|
|
|
|
176
|
0
|
|
|
|
|
|
my $ack = ord $str; |
177
|
0
|
0
|
|
|
|
|
unless ($ack == 6) { warn "Ack not received on DMPAFT command: $ack"; exit -1; } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
|
179
|
0
|
|
|
|
|
|
$cnt_out = $port_obj->write($cmd); |
180
|
0
|
0
|
|
|
|
|
unless ($cnt_out) { warn "write failed\n" }; |
|
0
|
|
|
|
|
|
|
181
|
0
|
|
|
|
|
|
($cnt_in, $str) = $self->read(7); |
182
|
|
|
|
|
|
|
|
183
|
0
|
|
|
|
|
|
$ack = ord substr($str,0,1); |
184
|
|
|
|
|
|
|
|
185
|
0
|
|
|
|
|
|
my $ls = unpack("H20",substr($str,1,4) ); |
186
|
0
|
|
|
|
|
|
$ls =~ s/(\w{2})/$1 /g; |
187
|
|
|
|
|
|
|
|
188
|
0
|
|
|
|
|
|
my $pages = unpack("s",substr($str,1,2) ); |
189
|
0
|
|
|
|
|
|
my $rec_start = unpack("s",substr($str,3,2) ); |
190
|
|
|
|
|
|
|
|
191
|
0
|
|
|
|
|
|
$crc = CRC_CCITT(substr($str,1,6) ); |
192
|
|
|
|
|
|
|
|
193
|
0
|
|
|
|
|
|
print "Pages = $pages : rec = $rec_start Datestamp $vDateStamp $crc\n"; |
194
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
|
$cnt_out = $port_obj->write( pack("h", 0x06) ); |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
#if ($pages == 513 ) { return -1 } |
198
|
|
|
|
|
|
|
|
199
|
0
|
|
|
|
|
|
my @arc_rec_lst; |
200
|
0
|
|
|
|
|
|
foreach my $page (1..$pages) |
201
|
|
|
|
|
|
|
{ |
202
|
0
|
|
|
|
|
|
my $page_sz = 267; |
203
|
0
|
|
|
|
|
|
my ($cnt_in, $str) = $self->read($page_sz,3); |
204
|
0
|
0
|
|
|
|
|
print "Page $page\n" if ( $Verbose ); |
205
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
|
my $rec_sz = 52; |
207
|
0
|
|
|
|
|
|
my $date_prev = 0; |
208
|
0
|
|
|
|
|
|
my %hsh; |
209
|
|
|
|
|
|
|
|
210
|
0
|
|
|
|
|
|
foreach my $rec ( 0..4 ) |
211
|
|
|
|
|
|
|
{ |
212
|
0
|
0
|
0
|
|
|
|
if ( ($page == 1) && ($rec < $rec_start ) ) { next } # Find the right starting point... |
|
0
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
|
214
|
0
|
|
|
|
|
|
my $start_ptr = 1 + ($rec * $rec_sz ); |
215
|
0
|
|
|
|
|
|
my $rec_str = substr($str, $start_ptr ,52); |
216
|
|
|
|
|
|
|
#print "$start_ptr \t > " . unpack( "h*", $rec_str) . "\n"; |
217
|
|
|
|
|
|
|
|
218
|
0
|
|
|
|
|
|
my $date = substr($rec_str,0,2); |
219
|
0
|
|
|
|
|
|
my $date_curr = unpack "s", $date; |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
# Check if we have wrapped... |
222
|
0
|
0
|
|
|
|
|
if ( $date_curr < $date_prev ) { last; } |
|
0
|
|
|
|
|
|
|
223
|
0
|
|
|
|
|
|
$date_prev = $date_curr; |
224
|
|
|
|
|
|
|
|
225
|
0
|
|
|
|
|
|
$hsh{'date_stamp'} = $date_curr; |
226
|
0
|
|
|
|
|
|
$hsh{'time_stamp'} = unpack "s", substr($rec_str,2,2); |
227
|
|
|
|
|
|
|
|
228
|
0
|
|
|
|
|
|
$hsh{'day'} = unpack( "c", $date & pack("c",0x1F) ); |
229
|
0
|
|
|
|
|
|
$hsh{'month'} = ( $hsh{'date_stamp'} >> 5) & 0xF; |
230
|
0
|
|
|
|
|
|
$hsh{'year'} = ( $hsh{'date_stamp'} >> 9) + 2000; |
231
|
|
|
|
|
|
|
|
232
|
0
|
|
|
|
|
|
$hsh{'hour'} = sprintf("%02d", int ( $hsh{'time_stamp'} / 100 )); |
233
|
|
|
|
|
|
|
|
234
|
0
|
|
|
|
|
|
$hsh{'min'} = $hsh{'time_stamp'} - ($hsh{'hour'} * 100); |
235
|
0
|
|
|
|
|
|
$hsh{'min'} = sprintf("%02d", $hsh{'min'}); |
236
|
|
|
|
|
|
|
|
237
|
0
|
|
|
|
|
|
$hsh{'time_stamp_fmt'} = "$hsh{'hour'}:$hsh{'min'}:00"; |
238
|
0
|
|
|
|
|
|
$hsh{'date_stamp_fmt'} = "$hsh{'year'}_$hsh{'month'}_$hsh{'day'}"; |
239
|
|
|
|
|
|
|
|
240
|
0
|
|
|
|
|
|
$hsh{'unixtime'} = timelocal(0,$hsh{min}, $hsh{hour}, |
241
|
|
|
|
|
|
|
$hsh{day}, $hsh{month}-1, $hsh{year}-1900); |
242
|
|
|
|
|
|
|
|
243
|
0
|
|
|
|
|
|
$hsh{'Air_Temp'} = unpack("s", substr($rec_str,4,2)) / 10; |
244
|
0
|
|
|
|
|
|
$hsh{'Air_Temp_Hi'} = unpack("s", substr($rec_str,6,2)) / 10; |
245
|
0
|
|
|
|
|
|
$hsh{'Air_Temp_Lo'} = unpack("s", substr($rec_str,8,2)) / 10; |
246
|
0
|
|
|
|
|
|
$hsh{'Rain_Clicks'} = unpack("s", substr($rec_str,10,2)); |
247
|
0
|
|
|
|
|
|
$hsh{'Rain_Rate_Clicks'} = unpack("s", substr($rec_str,12,2)); |
248
|
0
|
|
|
|
|
|
$hsh{'Rain_Rate'} = $hsh{'Rain_Rate_Clicks'} / 100; # Inches per hour |
249
|
0
|
|
|
|
|
|
$hsh{'Barometric_Press'} = unpack("s", substr $rec_str,14,2) / 1000; |
250
|
0
|
|
|
|
|
|
$hsh{'Solar'} = unpack("s", substr $rec_str,16,2); # watt/m**2 |
251
|
0
|
|
|
|
|
|
$hsh{'Wind_Samples'} = unpack("s", substr $rec_str,18,2); |
252
|
0
|
|
|
|
|
|
$hsh{'Air_Temp_Inside'} = unpack("s", substr $rec_str,20,2) / 10; |
253
|
|
|
|
|
|
|
|
254
|
0
|
|
|
|
|
|
$hsh{'Relative_Humidity_Inside'} = unpack("C", substr $rec_str,22,1); |
255
|
0
|
|
|
|
|
|
$hsh{'Relative_Humidity'} = unpack("C", substr $rec_str,23,1); |
256
|
|
|
|
|
|
|
|
257
|
0
|
|
|
|
|
|
$hsh{'Wind_Speed'} = unpack("C", substr($rec_str,24,1)); |
258
|
0
|
|
|
|
|
|
$hsh{'Wind_Gust_Max'} = unpack("C", substr($rec_str,25,1)); |
259
|
0
|
|
|
|
|
|
$hsh{'Wind_Dir_Max'} = unpack("C", substr($rec_str,26,1)); |
260
|
0
|
|
|
|
|
|
$hsh{'Wind_Dir'} = unpack("C", substr($rec_str,27,1)); |
261
|
|
|
|
|
|
|
|
262
|
0
|
|
|
|
|
|
$hsh{'UV'} = unpack("C", substr($rec_str,28,1)) / 10; |
263
|
0
|
|
|
|
|
|
$hsh{'ET'} = unpack("C", substr($rec_str,29,1)) / 1000; |
264
|
|
|
|
|
|
|
|
265
|
0
|
|
|
|
|
|
$hsh{'Solar_Max'} = unpack("s", substr($rec_str,30,2)); |
266
|
0
|
|
|
|
|
|
$hsh{'UV_Max'} = unpack("C", substr($rec_str,32,1)); |
267
|
|
|
|
|
|
|
|
268
|
0
|
|
|
|
|
|
$hsh{'Forecast_Rule'} = unpack("C", substr($rec_str,33,1)); |
269
|
|
|
|
|
|
|
|
270
|
0
|
|
|
|
|
|
$hsh{'Dew_Point'} = _dew_point($hsh{'Air_Temp'},$hsh{'Relative_Humidity'}); |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
# Miscellaneous others omitted for now |
273
|
|
|
|
|
|
|
|
274
|
0
|
0
|
|
|
|
|
print "date> $hsh{'time_stamp'} $hsh{'time_stamp_fmt'} $hsh{'date_stamp'} $hsh{'date_stamp_fmt'}\n" if ( $Verbose ); |
275
|
|
|
|
|
|
|
#print Dumper \%hsh; |
276
|
|
|
|
|
|
|
|
277
|
0
|
|
|
|
|
|
push @arc_rec_lst, {%hsh}; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
#$in = ; # Testing step through facility |
281
|
|
|
|
|
|
|
#if ($in =~ /q/i ) { $port_obj->write( pack("h", 0x1B) ); last; } |
282
|
|
|
|
|
|
|
#else { $port_obj->write( pack("h", 0x06) ); } |
283
|
0
|
|
|
|
|
|
$port_obj->write( pack("h", 0x06) ); |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
|
287
|
0
|
|
|
|
|
|
return \@arc_rec_lst; |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - |
291
|
|
|
|
|
|
|
sub get_one_loop |
292
|
|
|
|
|
|
|
{ |
293
|
0
|
|
|
0
|
1
|
|
my $self = shift @_; |
294
|
|
|
|
|
|
|
|
295
|
0
|
0
|
|
|
|
|
unless ( $self->start_loop(1) ) { return 0; } |
|
0
|
|
|
|
|
|
|
296
|
0
|
|
|
|
|
|
my $hsh_ref = $self->read_loop(); |
297
|
|
|
|
|
|
|
|
298
|
0
|
|
|
|
|
|
return $hsh_ref; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - |
302
|
|
|
|
|
|
|
sub start_loop |
303
|
|
|
|
|
|
|
{ |
304
|
0
|
|
|
0
|
1
|
|
my $self = shift @_; |
305
|
0
|
|
0
|
|
|
|
my $lp_cnt = shift @_ || 1; |
306
|
|
|
|
|
|
|
|
307
|
0
|
|
|
|
|
|
$self->wake_up(); |
308
|
|
|
|
|
|
|
|
309
|
0
|
|
|
|
|
|
my $cnt_out = $self->{'port_obj'}->write("LOOP $lp_cnt\n"); |
310
|
|
|
|
|
|
|
|
311
|
0
|
|
|
|
|
|
my ($cnt_in, $str) = $self->read(1); |
312
|
|
|
|
|
|
|
|
313
|
0
|
0
|
|
|
|
|
if ( ord($str) != 6 ) { warn("Ack not returned for Loop"); return 0; } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
|
315
|
0
|
|
|
|
|
|
return 1; |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - |
319
|
|
|
|
|
|
|
sub read_loop |
320
|
|
|
|
|
|
|
{ |
321
|
0
|
|
|
0
|
1
|
|
my $self = shift @_; |
322
|
|
|
|
|
|
|
|
323
|
0
|
|
|
|
|
|
my ($cnt_in, $str) = $self->read(99, 4); # extend timeout to 3 seconds |
324
|
0
|
0
|
|
|
|
|
if ( $cnt_in != 99 ) { return 0 } |
|
0
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
|
326
|
0
|
|
|
|
|
|
my $hsh_ref = parse_loop_blck($str); |
327
|
|
|
|
|
|
|
|
328
|
0
|
|
|
|
|
|
return $hsh_ref; |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
332
|
|
|
|
|
|
|
sub parse_loop_blck |
333
|
|
|
|
|
|
|
{ |
334
|
0
|
|
|
0
|
0
|
|
my $blk = shift @_; |
335
|
0
|
|
|
|
|
|
my $loo = substr $blk,0,3; |
336
|
|
|
|
|
|
|
|
337
|
0
|
|
|
|
|
|
my $ack = ord substr($blk,0,1); |
338
|
|
|
|
|
|
|
|
339
|
0
|
0
|
|
|
|
|
unless ( $loo eq 'LOO') { warn("Block invalid loo -> $loo\n"); return ""; } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
|
341
|
0
|
|
|
|
|
|
my %hsh; |
342
|
|
|
|
|
|
|
|
343
|
0
|
|
|
|
|
|
$hsh{'Barometric_Trend'} = unpack("C", substr $blk,3,1); |
344
|
0
|
|
|
|
|
|
$hsh{'next_rec'} = unpack("s", substr $blk,5,2); |
345
|
0
|
|
|
|
|
|
$hsh{'Barometric_Press'} = unpack("s", substr $blk,7,2) / 1000; |
346
|
0
|
|
|
|
|
|
$hsh{'Air_Temp_Inside'} = unpack("s", substr $blk,9,2) / 10; |
347
|
0
|
|
|
|
|
|
$hsh{'Humidity_Inside'} = unpack("C", substr $blk,11,1); |
348
|
0
|
|
|
|
|
|
$hsh{'Air_Temp'} = unpack("s", substr $blk,12,2) / 10; |
349
|
0
|
|
|
|
|
|
$hsh{'Wind_Speed'} = unpack("C", substr $blk,14,1); |
350
|
0
|
|
|
|
|
|
$hsh{'Wind_Speed_10min_Ave'} = unpack("C", substr $blk,15,1); |
351
|
0
|
|
|
|
|
|
$hsh{'Wind_Dir'} = unpack("s", substr $blk,16,2); |
352
|
|
|
|
|
|
|
# Skip other temps for now... |
353
|
|
|
|
|
|
|
|
354
|
0
|
|
|
|
|
|
$hsh{'Relative_Humidity'} = unpack("C", substr $blk,33,1); |
355
|
|
|
|
|
|
|
# Skip other humidities for now... |
356
|
|
|
|
|
|
|
|
357
|
0
|
|
|
|
|
|
$hsh{'Rain_Rate_Clicks'} = unpack("s", substr $blk,41,2); |
358
|
0
|
|
|
|
|
|
$hsh{'Rain_Rate'} = $hsh{'Rain_Rate_Clicks'} / 100; # Inches per hr |
359
|
0
|
|
|
|
|
|
$hsh{'UV'} = unpack("C", substr $blk,43,1); |
360
|
0
|
|
|
|
|
|
$hsh{'Solar'} = unpack("s", substr $blk,44,2); # watt/m**2 |
361
|
0
|
|
|
|
|
|
$hsh{'Rain_Storm'} = unpack("s", substr $blk,46,2) / 100; # Inches per storm |
362
|
|
|
|
|
|
|
|
363
|
0
|
|
|
|
|
|
$hsh{'Storm_Date'} = unpack("s", substr $blk,48,2); # Need to parse data (not sure what this is) |
364
|
0
|
|
|
|
|
|
$hsh{'Rain_Day'} = unpack("s", substr $blk,50,2)/100; |
365
|
0
|
|
|
|
|
|
$hsh{'Rain_Month'} = unpack("s", substr $blk,52,2)/100; |
366
|
0
|
|
|
|
|
|
$hsh{'Rain_Year'} = unpack("s", substr $blk,54,2)/100; |
367
|
|
|
|
|
|
|
|
368
|
0
|
|
|
|
|
|
$hsh{'Day_ET'} = unpack("s", substr $blk,56,2)/1000; |
369
|
0
|
|
|
|
|
|
$hsh{'Month_ET'} = unpack("s", substr $blk,58,2)/100; |
370
|
0
|
|
|
|
|
|
$hsh{'Year_ET'} = unpack("s", substr $blk,60,2)/100; |
371
|
|
|
|
|
|
|
# Skip Soil/Leaf Wetness |
372
|
|
|
|
|
|
|
|
373
|
0
|
|
|
|
|
|
$hsh{'Alarms_Inside'} = unpack("b8", substr $blk,70,1); |
374
|
0
|
|
|
|
|
|
$hsh{'Alarms_Rain'} = unpack("b8", substr $blk,70,1); |
375
|
0
|
|
|
|
|
|
$hsh{'Alarms_Outside'} = unpack("b8", substr $blk,70,1); |
376
|
|
|
|
|
|
|
# Skip extra alarms |
377
|
|
|
|
|
|
|
|
378
|
0
|
|
|
|
|
|
$hsh{'Batt_Xmit'} = unpack("C", substr $blk,86,1) * 0.005859375; |
379
|
0
|
|
|
|
|
|
$hsh{'Batt_Cons'} = unpack("s", substr $blk,87,2) * 0.005859375; |
380
|
|
|
|
|
|
|
|
381
|
0
|
|
|
|
|
|
$hsh{'Forecast_Icon'} = unpack("C", substr $blk,89,1); |
382
|
0
|
|
|
|
|
|
$hsh{'Forecast_Rule'} = unpack("C", substr $blk,90,1); |
383
|
|
|
|
|
|
|
|
384
|
0
|
|
|
|
|
|
$hsh{'Sunrise'} = sprintf( "%04d", unpack("S", substr $blk,91,2) ); |
385
|
0
|
|
|
|
|
|
$hsh{'Sunrise'} =~ s/(\d{2})(\d{2})/$1:$2/; |
386
|
|
|
|
|
|
|
|
387
|
0
|
|
|
|
|
|
$hsh{'Sunset'} = sprintf( "%04d", unpack("S", substr $blk,93,2) ); |
388
|
0
|
|
|
|
|
|
$hsh{'Sunset'} =~ s/(\d{2})(\d{2})/$1:$2/; |
389
|
|
|
|
|
|
|
|
390
|
0
|
|
|
|
|
|
$hsh{'Dew_Point'} = _dew_point($hsh{'Air_Temp'},$hsh{'Relative_Humidity'}); |
391
|
|
|
|
|
|
|
|
392
|
0
|
|
|
|
|
|
my $nl = ord substr $blk,95,1; |
393
|
0
|
|
|
|
|
|
my $cr = ord substr $blk,96,1; |
394
|
|
|
|
|
|
|
|
395
|
0
|
|
|
|
|
|
$hsh{crc} = unpack "%n", substr($blk,97,2); |
396
|
0
|
|
|
|
|
|
$hsh{'crc_calc'} = CRC_CCITT($blk); |
397
|
|
|
|
|
|
|
|
398
|
0
|
|
|
|
|
|
return \%hsh; |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - |
402
|
|
|
|
|
|
|
sub get_eeprom |
403
|
|
|
|
|
|
|
{ |
404
|
0
|
|
|
0
|
1
|
|
my $self = shift @_; |
405
|
0
|
|
|
|
|
|
my $item = shift @_; |
406
|
|
|
|
|
|
|
|
407
|
0
|
|
|
|
|
|
my ($loc, $size); |
408
|
|
|
|
|
|
|
# Not all supported.... More to follow |
409
|
0
|
0
|
|
|
|
|
if ( uc($item) eq 'ARCHIVE_PERIOD' ){ $loc = '2D'; $size = '01' } |
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
410
|
0
|
|
|
|
|
|
elsif ( uc($item) eq 'TIME_ZONE' ){ $loc = '11'; $size = '01' } |
|
0
|
|
|
|
|
|
|
411
|
0
|
|
|
|
|
|
elsif ( uc($item) eq 'MANUAL_OR_AUTO' ){ $loc = '12'; $size = '01' } |
|
0
|
|
|
|
|
|
|
412
|
0
|
|
|
|
|
|
elsif ( uc($item) eq 'DAYLIGHT_SAVINGS' ){ $loc = '13'; $size = '01' } |
|
0
|
|
|
|
|
|
|
413
|
0
|
|
|
|
|
|
elsif ( uc($item) eq 'GMT_OFFSET' ){ $loc = '14'; $size = '02' } |
|
0
|
|
|
|
|
|
|
414
|
0
|
|
|
|
|
|
elsif ( uc($item) eq 'GMT_OR_ZONE' ){ $loc = '16'; $size = '01' } |
|
0
|
|
|
|
|
|
|
415
|
0
|
|
|
|
|
|
elsif ( uc($item) eq 'SETUP_BITS' ){ $loc = '2B'; $size = '01' } |
|
0
|
|
|
|
|
|
|
416
|
0
|
|
|
|
|
|
else { warn "$item not found"; return -1; } |
|
0
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
|
418
|
0
|
|
|
|
|
|
my $port_obj = $self->{port_obj}; |
419
|
|
|
|
|
|
|
|
420
|
0
|
|
|
|
|
|
my $cnt_out = $port_obj->write("EERD $loc $size\n"); |
421
|
0
|
0
|
|
|
|
|
unless ($cnt_out) { warn "write failed\n" }; |
|
0
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
# A \n\r is prefixed not as in the documentation... |
424
|
0
|
|
|
|
|
|
my $read_size = (hex($size) * 4) + 6; |
425
|
|
|
|
|
|
|
|
426
|
0
|
|
|
|
|
|
my ($cnt_in, $str) = $self->read($read_size); |
427
|
|
|
|
|
|
|
|
428
|
0
|
|
|
|
|
|
my @rsp_lst = split /\n\r/, $str; |
429
|
0
|
|
|
|
|
|
shift(@rsp_lst); |
430
|
|
|
|
|
|
|
|
431
|
0
|
0
|
|
|
|
|
if ( $rsp_lst[0] ne 'OK' ) { _dump($str); warn "OK Not returned"; } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
432
|
0
|
|
|
|
|
|
shift(@rsp_lst); |
433
|
|
|
|
|
|
|
|
434
|
0
|
|
|
|
|
|
return \@rsp_lst; |
435
|
|
|
|
|
|
|
} |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - |
438
|
|
|
|
|
|
|
sub gettime |
439
|
|
|
|
|
|
|
{ |
440
|
0
|
|
|
0
|
1
|
|
my $self = shift @_; |
441
|
|
|
|
|
|
|
|
442
|
0
|
|
|
|
|
|
my $port_obj = $self->{port_obj}; |
443
|
|
|
|
|
|
|
|
444
|
0
|
|
|
|
|
|
my $cnt_out = $port_obj->write("GETTIME\n"); |
445
|
0
|
0
|
|
|
|
|
unless ($cnt_out) { warn "write failed\n" }; |
|
0
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
|
447
|
0
|
|
|
|
|
|
my ($cnt_in, $str) = $port_obj->read(9); |
448
|
|
|
|
|
|
|
|
449
|
0
|
|
|
|
|
|
my $ck = CRC_CCITT(substr($str,1,9)); |
450
|
0
|
0
|
|
|
|
|
if ( $ck ) { warn "checksum error"; return 0; } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
|
452
|
0
|
|
|
|
|
|
my @rsp_lst = split //, $str; |
453
|
0
|
|
|
|
|
|
shift @rsp_lst; |
454
|
|
|
|
|
|
|
|
455
|
0
|
|
|
|
|
|
@rsp_lst = map ord, @rsp_lst; |
456
|
|
|
|
|
|
|
|
457
|
0
|
|
|
|
|
|
return \@rsp_lst; |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - |
461
|
|
|
|
|
|
|
sub settime |
462
|
|
|
|
|
|
|
{ |
463
|
0
|
|
|
0
|
1
|
|
my $self = shift @_; |
464
|
0
|
|
|
|
|
|
my $t_ref = shift @_; |
465
|
|
|
|
|
|
|
|
466
|
0
|
|
|
|
|
|
my $port_obj = $self->{port_obj}; |
467
|
|
|
|
|
|
|
|
468
|
0
|
|
|
|
|
|
my $cnt_out = $port_obj->write("SETTIME\n"); |
469
|
0
|
0
|
|
|
|
|
unless ($cnt_out) { warn "write failed\n" }; |
|
0
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
|
471
|
0
|
|
|
|
|
|
my ($cnt_in, $str) = $port_obj->read(1); |
472
|
0
|
|
|
|
|
|
my $ack = ord $str; |
473
|
0
|
0
|
|
|
|
|
if ( $ack != 6 ) { warn "SETTIME not set ack $ack !"; return 0; } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
|
475
|
0
|
|
|
|
|
|
my ($sec, $min, $hour, $day, $mon, $yr) = @{$t_ref}; |
|
0
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
|
477
|
0
|
|
|
|
|
|
$str = join "", map chr, ($sec, $min, $hour, $day, $mon, $yr); |
478
|
|
|
|
|
|
|
|
479
|
0
|
|
|
|
|
|
my $ck = CRC_CCITT($str); |
480
|
0
|
|
|
|
|
|
$str = $str . pack("n",$ck); |
481
|
|
|
|
|
|
|
|
482
|
0
|
|
|
|
|
|
$cnt_out = $port_obj->write($str); |
483
|
0
|
0
|
|
|
|
|
unless ($cnt_out) { warn "write failed\n" }; |
|
0
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
|
485
|
0
|
|
|
|
|
|
($cnt_in, $str) = $port_obj->read(1); |
486
|
0
|
0
|
|
|
|
|
if ( ord($str) != 6 ) { warn "SETTIME not set!"; return 0; } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
|
488
|
0
|
|
|
|
|
|
sleep 3; # The console seems to need to some time here... |
489
|
|
|
|
|
|
|
|
490
|
0
|
|
|
|
|
|
return 1; |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - |
494
|
|
|
|
|
|
|
sub set_archive_period |
495
|
|
|
|
|
|
|
{ |
496
|
0
|
|
|
0
|
1
|
|
my $self = shift @_; |
497
|
0
|
|
|
|
|
|
my $period = shift @_; |
498
|
|
|
|
|
|
|
|
499
|
0
|
0
|
|
|
|
|
unless ( grep { $_ == $period } (1, 5, 10, 15, 30, 60, 120) ) |
|
0
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
{ |
501
|
0
|
|
|
|
|
|
warn "Not valid archive period"; # Limits in document |
502
|
0
|
|
|
|
|
|
return 0; |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
|
505
|
0
|
|
|
|
|
|
my $port_obj = $self->{port_obj}; |
506
|
|
|
|
|
|
|
|
507
|
0
|
|
|
|
|
|
my $cnt_out = $port_obj->write("SETPER $period\n"); |
508
|
0
|
0
|
|
|
|
|
unless ($cnt_out) { warn "write failed\n" }; |
|
0
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
|
510
|
0
|
|
|
|
|
|
my ($cnt_in, $str) = $port_obj->read(1); |
511
|
|
|
|
|
|
|
|
512
|
0
|
|
|
|
|
|
my $ack = ord $str; |
513
|
|
|
|
|
|
|
|
514
|
0
|
0
|
|
|
|
|
unless ( $ack != 6 ) { warn "Archive not set!"; return 0; } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
|
516
|
0
|
|
|
|
|
|
return 1; |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
my $t_prv = time; |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
523
|
|
|
|
|
|
|
sub get_archive_period |
524
|
|
|
|
|
|
|
{ |
525
|
0
|
|
|
0
|
1
|
|
my $self = shift @_; |
526
|
|
|
|
|
|
|
|
527
|
0
|
|
|
|
|
|
my $rst = $self->get_eeprom('archive_period'); |
528
|
0
|
|
|
|
|
|
my $archive_period = hex($rst->[0]); |
529
|
|
|
|
|
|
|
|
530
|
0
|
|
|
|
|
|
return $archive_period; |
531
|
|
|
|
|
|
|
} |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
534
|
|
|
|
|
|
|
sub get_timezone |
535
|
|
|
|
|
|
|
{ |
536
|
0
|
|
|
0
|
1
|
|
my $self = shift @_; |
537
|
|
|
|
|
|
|
|
538
|
1
|
|
|
1
|
|
1123
|
use DateTime::TimeZone; |
|
1
|
|
|
|
|
92357
|
|
|
1
|
|
|
|
|
1761
|
|
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
# Calculate the time zone used by the VP and return as a TimeZone object |
541
|
|
|
|
|
|
|
|
542
|
0
|
|
|
|
|
|
my $timezone; |
543
|
0
|
0
|
|
|
|
|
if (hex $self->get_eeprom('gmt_or_zone')->[0]) |
544
|
|
|
|
|
|
|
{ |
545
|
|
|
|
|
|
|
# Unit is configured for GMT offset value |
546
|
|
|
|
|
|
|
# Wow, this is messy! |
547
|
0
|
|
|
|
|
|
my $dst = 0; # Manual daylight saving adjustment to make |
548
|
0
|
0
|
|
|
|
|
if (hex $self->get_eeprom('manual_or_auto')->[0]) |
549
|
|
|
|
|
|
|
{ |
550
|
|
|
|
|
|
|
# Unit has daylight saving in manual |
551
|
0
|
|
|
|
|
|
$dst = hex $self->get_eeprom('daylight_savings')->[0]; |
552
|
|
|
|
|
|
|
} |
553
|
0
|
|
|
|
|
|
my $val = $self->get_eeprom('gmt_offset'); # Get offset in hours |
554
|
0
|
|
|
|
|
|
my $offset = hex ($val->[1].$val->[0]); # Combine the 2 bytes together |
555
|
0
|
0
|
|
|
|
|
$offset -= 65536 if $offset > 32767; # 2's complement if -ve |
556
|
0
|
|
|
|
|
|
$offset /= 100; # Convert to hours |
557
|
0
|
|
|
|
|
|
$offset += $dst; # Adjust for daylight saving if required |
558
|
0
|
|
|
|
|
|
my $hours = int $offset; # The whole number of hours |
559
|
0
|
|
|
|
|
|
my $minutes = abs ($offset - $hours) * 60; # The number of minutes |
560
|
0
|
|
|
|
|
|
$minutes = sprintf("%02d", $minutes); # Prefix with 0 if required |
561
|
0
|
|
|
|
|
|
my $tzstr = $hours.$minutes; # The 2 together to create tz string |
562
|
0
|
0
|
0
|
|
|
|
$tzstr *= -1 if $offset < 0 && $hours == 0; # Fix negative for 0 hours |
563
|
0
|
|
|
|
|
|
$tzstr = sprintf("%+05d", $tzstr); # The final formatted string |
564
|
0
|
|
|
|
|
|
$timezone = DateTime::TimeZone->new( name => $tzstr ); |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
else { |
567
|
|
|
|
|
|
|
# Unit configured for specific timezone |
568
|
0
|
|
|
|
|
|
my $tz = hex $self->get_eeprom('time_zone')->[0]; |
569
|
0
|
|
|
|
|
|
my @timezones = qw( Pacific/Kwajalein |
570
|
|
|
|
|
|
|
Pacific/Midway |
571
|
|
|
|
|
|
|
Pacific/Honolulu |
572
|
|
|
|
|
|
|
America/Anchorage |
573
|
|
|
|
|
|
|
America/Tijuana |
574
|
|
|
|
|
|
|
America/Denver |
575
|
|
|
|
|
|
|
America/Chicago |
576
|
|
|
|
|
|
|
America/Mexico_City |
577
|
|
|
|
|
|
|
America/Monterrey |
578
|
|
|
|
|
|
|
America/Bogota |
579
|
|
|
|
|
|
|
America/New_York |
580
|
|
|
|
|
|
|
America/Halifax |
581
|
|
|
|
|
|
|
America/Santiago |
582
|
|
|
|
|
|
|
America/St_Johns |
583
|
|
|
|
|
|
|
America/Sao_Paulo |
584
|
|
|
|
|
|
|
America/Argentina/Buenos_Aires |
585
|
|
|
|
|
|
|
Atlantic/South_Georgia |
586
|
|
|
|
|
|
|
Atlantic/Azores |
587
|
|
|
|
|
|
|
Europe/London |
588
|
|
|
|
|
|
|
Africa/Casablanca |
589
|
|
|
|
|
|
|
Europe/Berlin |
590
|
|
|
|
|
|
|
Europe/Paris |
591
|
|
|
|
|
|
|
Europe/Prague |
592
|
|
|
|
|
|
|
Europe/Athens |
593
|
|
|
|
|
|
|
Africa/Cairo |
594
|
|
|
|
|
|
|
Europe/Bucharest |
595
|
|
|
|
|
|
|
Africa/Harare |
596
|
|
|
|
|
|
|
Asia/Jerusalem |
597
|
|
|
|
|
|
|
Asia/Baghdad |
598
|
|
|
|
|
|
|
Europe/Moscow |
599
|
|
|
|
|
|
|
Asia/Tehran |
600
|
|
|
|
|
|
|
Asia/Muscat |
601
|
|
|
|
|
|
|
Asia/Kabul |
602
|
|
|
|
|
|
|
Asia/Karachi |
603
|
|
|
|
|
|
|
Asia/Kolkata |
604
|
|
|
|
|
|
|
Asia/Almaty |
605
|
|
|
|
|
|
|
Asia/Bangkok |
606
|
|
|
|
|
|
|
Asia/Shanghai |
607
|
|
|
|
|
|
|
Asia/Hong_Kong |
608
|
|
|
|
|
|
|
Asia/Tokyo |
609
|
|
|
|
|
|
|
Australia/Adelaide |
610
|
|
|
|
|
|
|
Australia/Darwin |
611
|
|
|
|
|
|
|
Australia/Brisbane |
612
|
|
|
|
|
|
|
Australia/Hobart |
613
|
|
|
|
|
|
|
Asia/Magadan |
614
|
|
|
|
|
|
|
Pacific/Fiji |
615
|
|
|
|
|
|
|
Pacific/Auckland |
616
|
|
|
|
|
|
|
); |
617
|
0
|
|
|
|
|
|
$timezone = DateTime::TimeZone->new( name => $timezones[$tz] ); |
618
|
|
|
|
|
|
|
} |
619
|
|
|
|
|
|
|
|
620
|
0
|
|
|
|
|
|
return $timezone; |
621
|
|
|
|
|
|
|
} |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
624
|
|
|
|
|
|
|
sub make_date_time_stamp |
625
|
|
|
|
|
|
|
{ |
626
|
0
|
|
|
0
|
1
|
|
my $self = shift @_; |
627
|
|
|
|
|
|
|
|
628
|
0
|
|
|
|
|
|
my ($year, $mon, $mday, $hour, $min) = @_; |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
# Test Example as per Page 31 in Document |
632
|
|
|
|
|
|
|
#$mon = 6;$mday = 6;$year = 2003;$hour = 9;$min = 30; |
633
|
|
|
|
|
|
|
# See print time stamps below after CRC and formatting |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
#print "Looking for record $year, $mon $mday $hour:$min\n"; |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
# The friggen Vantage pro requires time stamps that _exactly_ match |
638
|
|
|
|
|
|
|
# the record in memory or it sends the whole archive. |
639
|
|
|
|
|
|
|
#my $rmn = $self->get_archive_period(); |
640
|
|
|
|
|
|
|
#$min = $min - $rmn; # Note this does not work for any archive_period > 60 |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
#if ( $min > 0 ) |
643
|
|
|
|
|
|
|
#{ $min = 60 + $min; |
644
|
|
|
|
|
|
|
# $hour -= 1; |
645
|
|
|
|
|
|
|
# if ($hour < 0 ) { $hour = 23; } |
646
|
|
|
|
|
|
|
#} |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
#my $gap = $min % $rmn; |
649
|
|
|
|
|
|
|
#$min = $min - $gap; |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
#print "Looking for record $year, $mon $mday $hour:$min\n"; |
652
|
|
|
|
|
|
|
|
653
|
0
|
|
|
|
|
|
my $vDateStamp = $mday + ($mon)*32 + ($year-2000)*512; |
654
|
0
|
|
|
|
|
|
my $vTimeStamp = (100 * $hour) + $min; |
655
|
|
|
|
|
|
|
|
656
|
0
|
|
|
|
|
|
return ($vDateStamp, $vTimeStamp); |
657
|
|
|
|
|
|
|
} |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
660
|
|
|
|
|
|
|
sub get_setup_bits |
661
|
|
|
|
|
|
|
{ |
662
|
0
|
|
|
0
|
1
|
|
my $self = shift @_; |
663
|
|
|
|
|
|
|
|
664
|
0
|
|
|
|
|
|
my $rst = $self->get_eeprom('setup_bits'); |
665
|
0
|
|
|
|
|
|
my $enc = hex($rst->[0]); |
666
|
0
|
|
|
|
|
|
my %setup_bits; |
667
|
0
|
|
|
|
|
|
$setup_bits{TimeMode} = $enc & 0x01; |
668
|
0
|
|
|
|
|
|
$setup_bits{IsAM} = $enc >> 1 & 0x01; |
669
|
0
|
|
|
|
|
|
$setup_bits{MonthDayFormat} = $enc >> 2 & 0x01; |
670
|
0
|
|
|
|
|
|
$setup_bits{WindCupSize} = $enc >> 3 & 0x01; |
671
|
0
|
|
|
|
|
|
$setup_bits{RainCollectorSize} = $enc >> 4 & 0x03; |
672
|
0
|
|
|
|
|
|
$setup_bits{Latitude} = $enc >> 6 & 0x01; |
673
|
0
|
|
|
|
|
|
$setup_bits{Longitude} = $enc >> 7 & 0x01; |
674
|
|
|
|
|
|
|
|
675
|
0
|
|
|
|
|
|
return \%setup_bits; |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
679
|
|
|
|
|
|
|
sub get_ymdhm |
680
|
|
|
|
|
|
|
{ |
681
|
0
|
|
|
0
|
0
|
|
my $self = shift @_; |
682
|
0
|
|
|
|
|
|
my $utime = shift @_; |
683
|
|
|
|
|
|
|
|
684
|
0
|
|
|
|
|
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($utime); |
685
|
0
|
|
|
|
|
|
$mon = $mon + 1; |
686
|
0
|
|
|
|
|
|
$year = $year + 1900; |
687
|
|
|
|
|
|
|
|
688
|
0
|
|
|
|
|
|
return ($year, $mon, $mday, $hour, $min); |
689
|
|
|
|
|
|
|
} |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
692
|
|
|
|
|
|
|
sub read |
693
|
|
|
|
|
|
|
{ |
694
|
0
|
|
|
0
|
0
|
|
my $self = shift @_; |
695
|
0
|
|
0
|
|
|
|
my $bytes = shift @_ || 255; |
696
|
0
|
|
0
|
|
|
|
my $timeout = shift @_ || 2; |
697
|
|
|
|
|
|
|
|
698
|
0
|
|
|
|
|
|
my $port_obj = $self->{port_obj}; |
699
|
|
|
|
|
|
|
|
700
|
0
|
|
|
|
|
|
my ($cnt_in, $str); |
701
|
|
|
|
|
|
|
|
702
|
0
|
|
|
|
|
|
eval { |
703
|
0
|
|
|
0
|
|
|
local $SIG{ALRM} = sub { die "alarm $timeout expired\n" }; # NB: \n required |
|
0
|
|
|
|
|
|
|
704
|
0
|
|
|
|
|
|
alarm $timeout; |
705
|
|
|
|
|
|
|
|
706
|
0
|
|
|
|
|
|
($cnt_in, $str) = $self->{'port_obj'}->read($bytes); |
707
|
|
|
|
|
|
|
|
708
|
0
|
|
|
|
|
|
alarm 0; |
709
|
|
|
|
|
|
|
}; |
710
|
|
|
|
|
|
|
|
711
|
0
|
0
|
|
|
|
|
if ($@) |
712
|
|
|
|
|
|
|
{ |
713
|
0
|
|
|
|
|
|
warn "Read Timeout $timeout\n"; |
714
|
0
|
|
|
|
|
|
return 0; |
715
|
|
|
|
|
|
|
} |
716
|
|
|
|
|
|
|
|
717
|
0
|
|
|
|
|
|
return ($cnt_in, $str); |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
} |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
sub _dew_point |
722
|
|
|
|
|
|
|
{ |
723
|
0
|
|
|
0
|
|
|
my $temp = shift @_; |
724
|
0
|
|
|
|
|
|
my $rh = shift @_; |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
# Using the simplified approximation for dew point |
727
|
|
|
|
|
|
|
# Accurate to 1 degree C for humidities > 50 % |
728
|
|
|
|
|
|
|
# http://en.wikipedia.org/wiki/Dew_point |
729
|
|
|
|
|
|
|
|
730
|
0
|
|
|
|
|
|
my $dew_point = $temp - ( (100 - $rh)/5 ); |
731
|
|
|
|
|
|
|
|
732
|
0
|
|
|
|
|
|
return $dew_point; |
733
|
|
|
|
|
|
|
} |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
sub _dump |
737
|
|
|
|
|
|
|
{ |
738
|
0
|
|
|
0
|
|
|
my @lst = split //, $_[0]; |
739
|
0
|
|
|
|
|
|
print "Bytes " . scalar(@lst) . "\n"; |
740
|
0
|
|
|
|
|
|
foreach my $i ( @lst ) { |
741
|
0
|
|
|
|
|
|
print "> " . ord($i) . "\n"; |
742
|
|
|
|
|
|
|
} |
743
|
|
|
|
|
|
|
} |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - |
746
|
|
|
|
|
|
|
sub CRC_CCITT |
747
|
|
|
|
|
|
|
{ |
748
|
|
|
|
|
|
|
# Expects packed data... |
749
|
0
|
|
|
0
|
0
|
|
my $data_str = shift @_; |
750
|
|
|
|
|
|
|
|
751
|
0
|
|
|
|
|
|
my @crc_table = crc_table(); |
752
|
|
|
|
|
|
|
|
753
|
0
|
|
|
|
|
|
my $crc = 0; |
754
|
0
|
|
|
|
|
|
my @lst = split //, $data_str; |
755
|
0
|
|
|
|
|
|
foreach my $data (@lst) |
756
|
|
|
|
|
|
|
{ |
757
|
0
|
|
|
|
|
|
my $data = unpack("c",$data); |
758
|
|
|
|
|
|
|
|
759
|
0
|
|
|
|
|
|
my $crc_prev = $crc; |
760
|
0
|
|
|
|
|
|
my $index = $crc >> 8 ^ $data; |
761
|
0
|
|
|
|
|
|
my $lhs = $crc_table[$index]; |
762
|
0
|
|
|
|
|
|
my $rhs = ($crc << 8) & 0xFFFF; |
763
|
0
|
|
|
|
|
|
$crc = $lhs ^ $rhs; |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
#$data = unpack("H*",$data); |
766
|
|
|
|
|
|
|
#printf("%X\t %s\t %X\t %X\t %X\t : %x \n", $crc_prev, $data, $index, $lhs, $rhs, $crc); |
767
|
|
|
|
|
|
|
} |
768
|
|
|
|
|
|
|
|
769
|
0
|
|
|
|
|
|
return $crc; |
770
|
|
|
|
|
|
|
} |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - |
773
|
|
|
|
|
|
|
sub crc_table |
774
|
|
|
|
|
|
|
{ |
775
|
|
|
|
|
|
|
|
776
|
0
|
|
|
0
|
0
|
|
my @crc_table = ( |
777
|
|
|
|
|
|
|
0x0, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, |
778
|
|
|
|
|
|
|
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, |
779
|
|
|
|
|
|
|
0x1231, 0x210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, |
780
|
|
|
|
|
|
|
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, |
781
|
|
|
|
|
|
|
0x2462, 0x3443, 0x420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, |
782
|
|
|
|
|
|
|
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, |
783
|
|
|
|
|
|
|
0x3653, 0x2672, 0x1611, 0x630, 0x76d7, 0x66f6, 0x5695, 0x46b4, |
784
|
|
|
|
|
|
|
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, |
785
|
|
|
|
|
|
|
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x840, 0x1861, 0x2802, 0x3823, |
786
|
|
|
|
|
|
|
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, |
787
|
|
|
|
|
|
|
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0xa50, 0x3a33, 0x2a12, |
788
|
|
|
|
|
|
|
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, |
789
|
|
|
|
|
|
|
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0xc60, 0x1c41, |
790
|
|
|
|
|
|
|
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, |
791
|
|
|
|
|
|
|
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0xe70, |
792
|
|
|
|
|
|
|
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, |
793
|
|
|
|
|
|
|
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, |
794
|
|
|
|
|
|
|
0x1080, 0xa1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, |
795
|
|
|
|
|
|
|
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, |
796
|
|
|
|
|
|
|
0x2b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, |
797
|
|
|
|
|
|
|
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, |
798
|
|
|
|
|
|
|
0x34e2, 0x24c3, 0x14a0, 0x481, 0x7466, 0x6447, 0x5424, 0x4405, |
799
|
|
|
|
|
|
|
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, |
800
|
|
|
|
|
|
|
0x26d3, 0x36f2, 0x691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, |
801
|
|
|
|
|
|
|
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, |
802
|
|
|
|
|
|
|
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x8e1, 0x3882, 0x28a3, |
803
|
|
|
|
|
|
|
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, |
804
|
|
|
|
|
|
|
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0xaf1, 0x1ad0, 0x2ab3, 0x3a92, |
805
|
|
|
|
|
|
|
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, |
806
|
|
|
|
|
|
|
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0xcc1, |
807
|
|
|
|
|
|
|
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, |
808
|
|
|
|
|
|
|
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0xed1, 0x1ef0); |
809
|
|
|
|
|
|
|
} |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
1; |
813
|
|
|
|
|
|
|
__END__ |