Device-Chip-PMS5003
view release on metacpan or search on metacpan
lib/Device/Chip/PMS5003.pm view on Meta::CPAN
use Device::Chip::PMS5003;
use Future::AsyncAwait;
my $chip = Device::Chip::PMS5003->new;
await $chip->mount( Device::Chip::Adapter::...->new );
$chip->start;
my $readings = await $chip->read_all;
printf "Particulate matter readings are %d / %d / %d\n",
@{$readings->{concentration}}{qw( pm1 pm2_5 pm10 )};
=head1 DESCRIPTION
This L<Device::Chip> subclass provides specific communication to a
F<PLANTOWER> F<PMS5003> particle concentration sensor attached to a computer
via a UART adapter. (Though if the communication protocol is the same, it is
likely also useful for a variety of other related sensors too).
The reader is presumed to be familiar with the general operation of this chip;
the documentation here will not attempt to explain or define chip-specific
concepts or features, only the use of this module to access them.
=cut
=head1 METHODS
The following methods documented in an C<await> expression return L<Future>
instances.
=cut
method UART_options
{
return
baudrate => 9600;
}
async method _loop
{
my $buf = "";
while(1) {
# A complete notification is 32bytes long
$buf .= await $self->protocol->read( 32 - length $buf );
# A notification begins "\x42\x4D"
$buf =~ s{.*(?=\x42\x4D)}{}s or next;
# A notification should be header, length, data
my ( $sof, $len ) = unpack( "a2 s>", $buf );
# Buffer length should be 28
$len == 28 or goto next_packet;
4 + length $buf >= $len or next;
my @data = unpack( "s>*", substr $buf, 4, 28 );
my $got_checksum = pop @data;
my $want_checksum = 0;
$want_checksum += ord for split m//, substr $buf, 0, 30;
if( $got_checksum != $want_checksum ) {
# Checksum failed
goto next_packet;
}
substr( $buf, 0, 32 ) = "";
$self->on_data( @data );
next;
next_packet:
# It's possible the header we found was not a real header but in fact
# spurious data in the middle of packet.
substr( $buf, 0, 2 ) = "";
# Trim down to the next plausible start
$buf =~ s{^.*\x42\x4D}{}s or $buf = "";
next;
}
}
field $_reading_count = 0;
field $_latest_reading;
field $_next_reading_f;
method on_data ( @data )
{
# From observation, the chip outputs a reading every second but only
# updates its values every 3. We'll therefore ignore the next two
if( !$_reading_count ) {
$_latest_reading = {
concentration => {
pm1 => $data[0],
pm2_5 => $data[1],
pm10 => $data[2],
},
atmos => {
pm1 => $data[3],
pm2_5 => $data[4],
pm10 => $data[5],
},
particles => {
pm0_3 => $data[6],
pm0_5 => $data[7],
pm1 => $data[8],
pm2_5 => $data[9],
pm5 => $data[10],
pm10 => $data[11],
}
};
my $f = $_next_reading_f; undef $_next_reading_f;
$f->done if $f;
}
$_reading_count++;
$_reading_count = 0 if $_reading_count > 2;
}
( run in 0.507 second using v1.01-cache-2.11-cpan-71847e10f99 )