mirror of https://github.com/arendst/Tasmota.git
201 lines
5.4 KiB
C++
201 lines
5.4 KiB
C++
/**
|
|
* @file HPMA115S0.cpp
|
|
* @author Felix Galindo
|
|
* @date June 2017
|
|
* @brief Arduino Library for Honeywell's Particle Sensor (HPMA115S0-XXX)
|
|
* @license MIT
|
|
*/
|
|
|
|
#include "Arduino.h"
|
|
#include "hpma115S0.h"
|
|
|
|
extern "C" {
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
}
|
|
|
|
/**
|
|
* @brief Constructor for HPMA115S0 class
|
|
* @param a Stream ({Software/Hardware}Serial) object.
|
|
* @note The serial stream should be already initialized
|
|
* @return void
|
|
*/
|
|
HPMA115S0::HPMA115S0(Stream& serial):
|
|
_serial(serial)
|
|
{
|
|
_serial.setTimeout(100);
|
|
}
|
|
|
|
/**
|
|
* @brief Function that initializes sensor
|
|
* @return a String containing sensor response
|
|
*/
|
|
void HPMA115S0::Init() {
|
|
//Serial.println("PS- Initializing...");
|
|
delay(100);
|
|
StartParticleMeasurement();
|
|
delay(100);
|
|
DisableAutoSend();
|
|
}
|
|
|
|
/**
|
|
* @brief Function that sends serial command to sensor
|
|
* @param a unsigned char * containing the command
|
|
* @param size of buffer
|
|
* @return void
|
|
*/
|
|
void HPMA115S0::SendCmd(const char * cmdBuf, unsigned int cmdSize) {
|
|
//Clear RX
|
|
while (_serial.available())
|
|
_serial.read();
|
|
|
|
//Send command
|
|
//Serial.print("PS- Sending cmd: ");
|
|
unsigned int index = 0;
|
|
for (index = 0; index < cmdSize; index++) {
|
|
//Serial.print(cmdBuf[index], HEX);
|
|
//Serial.print(" ");
|
|
_serial.write(cmdBuf[index]);
|
|
}
|
|
//Serial.println("");
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief Function that reads command response from sensor
|
|
* @param Buffer to store data in
|
|
* @param Buffer size
|
|
* @param Expected command type
|
|
* @return returns number of bytes read from sensor
|
|
*/
|
|
int HPMA115S0::ReadCmdResp(unsigned char * dataBuf, unsigned int dataBufSize, unsigned int cmdType) {
|
|
static unsigned char respBuf[HPM_MAX_RESP_SIZE];
|
|
static unsigned int respIdx = 0;
|
|
static unsigned int calChecksum = 0;
|
|
|
|
//Read response
|
|
respIdx = 0;
|
|
calChecksum = 0;
|
|
memset(respBuf, 0, sizeof(respBuf));
|
|
_serial.setTimeout(100);
|
|
//Serial.println("PS- Waiting for cmd resp...");
|
|
if (_serial.readStringUntil(HPM_CMD_RESP_HEAD)) {
|
|
delay(1); //wait for the rest of the bytes to arrive
|
|
respBuf[HPM_HEAD_IDX] = HPM_CMD_RESP_HEAD;
|
|
respBuf[HPM_LEN_IDX] = _serial.read(); //Read the command length
|
|
|
|
//Ensure buffers are big enough
|
|
if (respBuf[HPM_LEN_IDX] && ((respBuf[HPM_LEN_IDX] + 1) <= sizeof(respBuf) - 2) && (respBuf[HPM_LEN_IDX] - 1) <= dataBufSize ) {
|
|
if (_serial.readBytes(&respBuf[HPM_CMD_IDX], respBuf[HPM_LEN_IDX] + 1) == (respBuf[HPM_LEN_IDX] + 1)) { //read respBuf[HPM_LEN_IDX] num of bytes + calChecksum byte
|
|
if (respBuf[HPM_CMD_IDX] == cmdType) { //check if CMD type matches
|
|
|
|
//Calculate and validate checksum
|
|
for (respIdx = 0; respIdx < (2 + respBuf[HPM_LEN_IDX]); respIdx++) {
|
|
calChecksum += respBuf[respIdx];
|
|
}
|
|
calChecksum = (65536 - calChecksum) % 256;
|
|
if (calChecksum == respBuf[2 + respBuf[HPM_LEN_IDX]]) {
|
|
//Serial.println("PS- Received valid data!!!");
|
|
memset(dataBuf, 0, dataBufSize);
|
|
memcpy(dataBuf, &respBuf[HPM_DATA_START_IDX], respBuf[HPM_LEN_IDX] - 1);
|
|
return (respBuf[HPM_LEN_IDX] - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Function that sends a read command to sensor
|
|
* @return returns true if valid measurements were read from sensor
|
|
*/
|
|
boolean HPMA115S0::ReadParticleMeasurement(unsigned int * pm2_5, unsigned int * pm10) {
|
|
const char cmdBuf[] = {0x68, 0x01, 0x04, 0x93};
|
|
static unsigned char dataBuf[HPM_READ_PARTICLE_MEASURMENT_LEN_C - 1];
|
|
int len;
|
|
|
|
// Serial.println("PS- Reading Particle Measurements..." );
|
|
|
|
//Send command
|
|
SendCmd(cmdBuf, 4);
|
|
|
|
//Read response
|
|
len = ReadCmdResp(dataBuf, sizeof(dataBuf), READ_PARTICLE_MEASURMENT);
|
|
if ((len == (HPM_READ_PARTICLE_MEASURMENT_LEN - 1)) || (len == (HPM_READ_PARTICLE_MEASURMENT_LEN_C - 1))) {
|
|
|
|
if (len == (HPM_READ_PARTICLE_MEASURMENT_LEN - 1)) {
|
|
// HPMA115S0 Standard devices
|
|
_pm2_5 = dataBuf[0] * 256 + dataBuf[1];
|
|
_pm10 = dataBuf[2] * 256 + dataBuf[3];
|
|
} else {
|
|
// HPMA115C0 Compact devices
|
|
_pm2_5 = dataBuf[2] * 256 + dataBuf[3];
|
|
_pm10 = dataBuf[6] * 256 + dataBuf[7];
|
|
}
|
|
*pm2_5 = _pm2_5;
|
|
*pm10 = _pm10;
|
|
// Serial.println("PS- PM 2.5: " + String(_pm2_5) + " ug/m3" );
|
|
// Serial.println("PS- PM 10: " + String(_pm10) + " ug/m3" );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief Function that starts sensor measurement
|
|
* @return void
|
|
*/
|
|
void HPMA115S0::StartParticleMeasurement() {
|
|
const char cmd[] = {0x68, 0x01, 0x01, 0x96};
|
|
SendCmd(cmd, 4);
|
|
}
|
|
|
|
/**
|
|
* @brief Function that stops sensor measurement
|
|
* @return void
|
|
*/
|
|
void HPMA115S0::StopParticleMeasurement() {
|
|
const char cmd[] = {0x68, 0x01, 0x02, 0x95};
|
|
SendCmd(cmd, 4);
|
|
}
|
|
|
|
/**
|
|
* @brief Function that enables auto send
|
|
* @return void
|
|
*/
|
|
void HPMA115S0::EnableAutoSend() {
|
|
const char cmd[] = {0x68, 0x01, 0x40, 0x57};
|
|
SendCmd(cmd, 4);
|
|
}
|
|
|
|
/**
|
|
* @brief Function that stops auto send
|
|
* @return void
|
|
*/
|
|
void HPMA115S0::DisableAutoSend() {
|
|
const char cmd[] = {0x68, 0x01, 0x20, 0x77};
|
|
SendCmd(cmd, 4);
|
|
}
|
|
|
|
/**
|
|
* @brief Function that returns the latest PM 2.5 reading
|
|
* @note Sensor reports new reading ~ every 1 sec.
|
|
* @return PM 2.5 reading (unsigned int)
|
|
*/
|
|
unsigned int HPMA115S0::GetPM2_5() {
|
|
return _pm2_5;
|
|
}
|
|
|
|
/**
|
|
* @brief Function that returns the latest PM 10 reading
|
|
* @note Sensor reports new reading ~ every 1 sec.
|
|
* @return PM 10 reading (unsigned int)
|
|
*/
|
|
unsigned int HPMA115S0::GetPM10() {
|
|
return _pm10;
|
|
}
|