]> Git — Sourcephile - julm/air-duino.git/blob - collect.pl
init
[julm/air-duino.git] / collect.pl
1 #!/usr/bin/perl -w
2 # Licence: WTFPLv2 <http://www.wtfpl.net/txt/copying/>
3 # Copyright 2015: Julien Moutinho <julm+air@autogeree.net>
4
5 use strict;
6 use warnings;
7 use DateTime::Duration;
8 use DateTime;
9 use Device::SerialPort qw( 0.07 );
10 use File::Basename;
11 use File::Path;
12 use File::Spec;
13 use Log::Log4perl qw(:easy);
14 use RRDTool::OO;
15 #use Data::Dumper qw(Dumper);
16 #use IO::Handle;
17
18 sub rrd_init () {
19 Log::Log4perl->easy_init(
20 { level => $INFO
21 , category => 'rrdtool'
22 , layout => '%m%n'
23 });
24 my $now
25 = DateTime->now
26 ( time_zone => 'local'
27 #, locale => $config{locale}
28 ); # ->set_time_zone('floating');
29 my $dir = File::Spec->catdir(dirname($0), 'rrd', (sprintf '%0d', $now->year()));
30 my $file = File::Spec->catfile($dir, (sprintf '%02d.rrd', $now->month()));
31 File::Path::make_path($dir);
32 my $rrd = RRDTool::OO->new(file => $file);
33 if (not (-e $file)) {
34 my $one_month = DateTime::Duration->new(months => 1, end_of_month => 'limit');
35 my $month_begin = $now->clone->truncate(to => 'month');
36 my $month_end = $month_begin->clone->add_duration($one_month);
37 my $month_seconds = $month_end->epoch() - $month_begin->epoch();
38 my $step = 30; # NOTE: sampling interval in seconds
39 $rrd->create
40 ( step => $step
41 , data_source =>
42 { name => "humidity"
43 , type => "GAUGE"
44 , min => 0
45 , max => 100
46 , heartbeat => 2 * $step # seconds
47 }
48 , data_source =>
49 { name => "temperature"
50 , type => "GAUGE"
51 , min => -15
52 , max => 50
53 , heartbeat => 2 * $step # seconds
54 }
55 , data_source =>
56 { name => "quality"
57 , type => "GAUGE"
58 , min => 0
59 , max => 1000
60 , heartbeat => 2 * $step # seconds
61 }
62 , data_source =>
63 { name => "particles"
64 , type => "GAUGE"
65 , min => 0
66 , max => 10000
67 , heartbeat => 2 * $step # seconds
68 }
69 , archive =>
70 { cpoints => 1
71 , cfunc => 'AVERAGE'
72 , rows => $month_seconds / $step
73 }
74 );
75 }
76 return $rrd;
77 }
78 sub dev_init ($) {
79 my ($file) = @_;
80 my $dev = Device::SerialPort->new($file);
81 $dev->baudrate(9600); # MUST: match *uino Serial.begin()
82 #$dev->buffers(4096, 4096); # NOTE: no-op on POSIX
83 $dev->databits(8);
84 $dev->dtr_active(1); # NOTE: reset the *uino on serial connection
85 $dev->handshake('none');
86 $dev->parity("none");
87 $dev->read_char_time(0); # NOTE: don't wait for each character
88 $dev->read_const_time(1000); # NOTE: 1 second per unfulfilled "read" call
89 $dev->stopbits(1);
90 $dev->write_settings;
91 $dev->lookclear; # NOTE: discard buffered data within the TTY device
92 return $dev;
93 }
94
95 sub main () {
96 my $rrd = rrd_init();
97 my $dev = dev_init($ARGV[0]);
98
99 #autoflush STDOUT 1;
100 my $read_timeout = 60;
101 my $timeout = $read_timeout;
102 my $buffer = "";
103 my $last_time = 0;
104 my $last_day = (localtime)[3];
105 while ($timeout>0) {
106 my $curr_day = (localtime)[3];
107 if ($curr_day < $last_day) {
108 # NOTE: month changed, change RRD
109 $rrd = rrd_init();
110 $last_day = $curr_day;
111 }
112 my ($count, $saw) = $dev->read(1);
113 # NOTE: this could have read up to 255 chars (max for portability)
114 # but reading only 1 char at a time
115 # enables to add a more accurate timestamp.
116 if ($count > 0) {
117 $buffer .= $saw;
118 my @lines = split /\r\n/, $buffer;
119 if (@lines > 1) {
120 my $time = time;
121 # NOTE: process only ended lines
122 $buffer = pop @lines;
123 foreach (@lines) {
124 if ($_ =~ /^\d+;/) {
125 #print STDOUT ($time, ";", $_, "\n");
126 my ($counter, $uptime, $humidity, $temperature, $quality, $particules)
127 = split /;/, $_;
128 if ($time > $last_time) {
129 $rrd->update
130 ( time => $time
131 , values => [$humidity,$temperature,$quality,$particules]
132 );
133 $last_time = $time;
134 }
135 }
136 else {
137 print STDERR ($_, "\n");
138 }
139 }
140 }
141 $timeout = $read_timeout;
142 }
143 else {
144 $timeout--;
145 }
146 }
147 if ($timeout==0) {
148 die "Connection timeout (after ${read_timeout}s)\n";
149 }
150 undef $dev;
151 }
152 main;
153 1;