mirror of https://github.com/arendst/Tasmota.git
134 lines
3.1 KiB
C++
134 lines
3.1 KiB
C++
|
/*!
|
||
|
* @file Adafruit_PM25AQI.cpp
|
||
|
*
|
||
|
* @mainpage Adafruit PM2.5 air quality sensor driver
|
||
|
*
|
||
|
* @section intro_sec Introduction
|
||
|
*
|
||
|
* This is the documentation for Adafruit's PM2.5 AQI driver for the
|
||
|
* Arduino platform. It is designed specifically to work with the
|
||
|
* Adafruit PM2.5 Air quality sensors: http://www.adafruit.com/products/4632
|
||
|
*
|
||
|
* These sensors use I2C or UART to communicate.
|
||
|
*
|
||
|
* Adafruit invests time and resources providing this open source code,
|
||
|
* please support Adafruit and open-source hardware by purchasing
|
||
|
* products from Adafruit!
|
||
|
*
|
||
|
*
|
||
|
* @section author Author
|
||
|
* Written by Ladyada for Adafruit Industries.
|
||
|
*
|
||
|
* @section license License
|
||
|
* BSD license, all text here must be included in any redistribution.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "Adafruit_PM25AQI.h"
|
||
|
|
||
|
/*!
|
||
|
* @brief Instantiates a new PM25AQI class
|
||
|
*/
|
||
|
Adafruit_PM25AQI::Adafruit_PM25AQI() {}
|
||
|
|
||
|
/*!
|
||
|
* @brief Setups the hardware and detects a valid PMSA003I. Initializes I2C.
|
||
|
* @param theWire
|
||
|
* Optional pointer to I2C interface, otherwise use Wire
|
||
|
* @return True if PMSA003I found on I2C, False if something went wrong!
|
||
|
*/
|
||
|
bool Adafruit_PM25AQI::begin_I2C(TwoWire *theWire) {
|
||
|
if (!i2c_dev) {
|
||
|
i2c_dev = new Adafruit_I2CDevice(PMSA003I_I2CADDR_DEFAULT, theWire);
|
||
|
}
|
||
|
|
||
|
if (!i2c_dev->begin()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* @brief Setups the hardware and detects a valid UART PM2.5
|
||
|
* @param theSerial
|
||
|
* Pointer to Stream (HardwareSerial/SoftwareSerial) interface
|
||
|
* @return True
|
||
|
*/
|
||
|
bool Adafruit_PM25AQI::begin_UART(Stream *theSerial) {
|
||
|
serial_dev = theSerial;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* @brief Setups the hardware and detects a valid UART PM2.5
|
||
|
* @param data
|
||
|
* Pointer to PM25_AQI_Data that will be filled by read()ing
|
||
|
* @return True on successful read, false if timed out or bad data
|
||
|
*/
|
||
|
bool Adafruit_PM25AQI::read(PM25_AQI_Data *data) {
|
||
|
uint8_t buffer[32];
|
||
|
uint16_t sum = 0;
|
||
|
|
||
|
if (!data) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (i2c_dev) { // ok using i2c?
|
||
|
if (!i2c_dev->read(buffer, 32)) {
|
||
|
return false;
|
||
|
}
|
||
|
} else if (serial_dev) { // ok using uart
|
||
|
if (!serial_dev->available()) {
|
||
|
return false;
|
||
|
}
|
||
|
int skipped = 0;
|
||
|
while ((skipped < 32) && (serial_dev->peek() != 0x42)) {
|
||
|
serial_dev->read();
|
||
|
skipped++;
|
||
|
if (!serial_dev->available()) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
if (serial_dev->peek() != 0x42) {
|
||
|
serial_dev->read();
|
||
|
return false;
|
||
|
}
|
||
|
// Now read all 32 bytes
|
||
|
if (serial_dev->available() < 32) {
|
||
|
return false;
|
||
|
}
|
||
|
serial_dev->readBytes(buffer, 32);
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Check that start byte is correct!
|
||
|
if (buffer[0] != 0x42) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// get checksum ready
|
||
|
for (uint8_t i = 0; i < 30; i++) {
|
||
|
sum += buffer[i];
|
||
|
}
|
||
|
|
||
|
// The data comes in endian'd, this solves it so it works on all platforms
|
||
|
uint16_t buffer_u16[15];
|
||
|
for (uint8_t i = 0; i < 15; i++) {
|
||
|
buffer_u16[i] = buffer[2 + i * 2 + 1];
|
||
|
buffer_u16[i] += (buffer[2 + i * 2] << 8);
|
||
|
}
|
||
|
|
||
|
// put it into a nice struct :)
|
||
|
memcpy((void *)data, (void *)buffer_u16, 30);
|
||
|
|
||
|
if (sum != data->checksum) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// success!
|
||
|
return true;
|
||
|
}
|