1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
// Copyright 2020 Brian J. Tarricone <brian@tarricone.org>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)]
/// Sensors connected to the I2C bus
pub mod i2c;
pub(crate) mod read;
/// Sensors connected to a serial UART
pub mod serial;
use core::fmt;
/// Trait representing a bus-agnostic air quality sensor
pub trait AirQualitySensor<E: fmt::Debug> {
/// Reads a single sensor measurement
///
/// This function will block until sufficient data is available.
fn read(&mut self) -> Result<Reading, SensorError<E>>;
}
/// A single air quality sensor reading
#[derive(Debug, Clone, Copy)]
pub struct Reading {
pm1: u16,
pm2_5: u16,
pm10: u16,
env_pm1: u16,
env_pm2_5: u16,
env_pm10: u16,
particles_0_3: u16,
particles_0_5: u16,
particles_1: u16,
particles_2_5: u16,
particles_5: u16,
particles_10: u16,
}
impl Reading {
/// Returns the standard PM1 concentration in µg/m³
pub fn pm1(&self) -> u16 {
self.pm1
}
/// Returns the standard PM2.5 concentration in µg/m³
pub fn pm2_5(&self) -> u16 {
self.pm2_5
}
/// Returns the standard PM10 concentration in µg/m³
pub fn pm10(&self) -> u16 {
self.pm10
}
/// Returns the environmental PM1 concentration in µg/m³
///
/// Note that some devices do not support this reading and will
/// return garbage data for this value.
pub fn env_pm1(&self) -> u16 {
self.env_pm1
}
/// Returns the environmental PM2.5 concentration in µg/m³
///
/// Note that some devices do not support this reading and will
/// return garbage data for this value.
pub fn env_pm2_5(&self) -> u16 {
self.env_pm2_5
}
/// Returns the environmental PM10 concentration in µg/m³
///
/// Note that some devices do not support this reading and will
/// return garbage data for this value.
pub fn env_pm10(&self) -> u16 {
self.env_pm10
}
/// Returns count of particles smaller than 0.3µm
pub fn particles_0_3(&self) -> u16 {
self.particles_0_3
}
/// Returns count of particles smaller than 0.5µm
pub fn particles_0_5(&self) -> u16 {
self.particles_0_5
}
/// Returns count of particles smaller than 1µm
pub fn particles_1(&self) -> u16 {
self.particles_1
}
/// Returns count of particles smaller than 2.5µm
pub fn particles_2_5(&self) -> u16 {
self.particles_2_5
}
/// Returns count of particles smaller than 5µm
pub fn particles_5(&self) -> u16 {
self.particles_5
}
/// Returns count of particles smaller than 10µm
pub fn particles_10(&self) -> u16 {
self.particles_10
}
}
/// Describes errors returned by the air quality sensor
#[derive(Debug)]
pub enum SensorError<E: fmt::Debug> {
/// Couldn't find the "magic" bytes that indicate the start of a data frame
///
/// This likely means that you've set an incorrect baud rate, or there is something
/// noisy about your connection to the device.
BadMagic,
/// The checksum provided in the sensor data did not match the checksum of the data itself
///
/// Retrying the read will usually clear up the problem.
ChecksumMismatch,
/// Read error from the serial device or I2C bus
ReadError(E),
}
impl<E: fmt::Debug> fmt::Display for SensorError<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use SensorError::*;
match self {
BadMagic => f.write_str("Unable to find magic bytes at start of payload"),
ChecksumMismatch => f.write_str("Data read was corrupt"),
ReadError(error) => write!(f, "Read error: {:?}", error),
}
}
}
#[cfg(feature = "std")]
impl<E: fmt::Debug> std::error::Error for SensorError<E> {}
impl<E: fmt::Debug> From<E> for SensorError<E> {
fn from(error: E) -> Self {
SensorError::ReadError(error)
}
}