diff --git a/lib/HPMA115S0/LICENSE.md b/lib/HPMA115S0/LICENSE.md new file mode 100644 index 000000000..9866a1dcc --- /dev/null +++ b/lib/HPMA115S0/LICENSE.md @@ -0,0 +1,7 @@ +Copyright 2017 Felix Galindo + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/HPMA115S0/README.md b/lib/HPMA115S0/README.md new file mode 100644 index 000000000..6b6388658 --- /dev/null +++ b/lib/HPMA115S0/README.md @@ -0,0 +1,2 @@ +# HPMA115S0 +Library for Honeywell's Particle Sensor (HPMA115S0-XXX) diff --git a/lib/HPMA115S0/example/example.ino b/lib/HPMA115S0/example/example.ino new file mode 100644 index 000000000..165055d00 --- /dev/null +++ b/lib/HPMA115S0/example/example.ino @@ -0,0 +1,34 @@ +/** + * @file example.ino + * @author Felix Galindo + * @date June 2017 + * @brief Example using HPMA115S0 sensor library on a Feather 32u4 + * @license MIT + */ + +#include +#include + +//Create an instance of software serial +SoftwareSerial hpmaSerial(10, 11); // Feather TX, Feather RX + +//Create an instance of the hpma115S0 library +HPMA115S0 hpma115S0(hpmaSerial); + +void setup() { + Serial.begin(57600); + hpmaSerial.begin(9600); + delay(5000); + Serial.println("Starting..."); + hpma115S0.Init(); + hpma115S0.StartParticleMeasurement(); +} + +void loop() { + unsigned int pm2_5, pm10; + if (hpma115S0.ReadParticleMeasurement(&pm2_5, &pm10)) { + Serial.println("PM 2.5: " + String(pm2_5) + " ug/m3" ); + Serial.println("PM 10: " + String(pm10) + " ug/m3" ); + } + delay(1000); +} \ No newline at end of file diff --git a/lib/HPMA115S0/library.properties b/lib/HPMA115S0/library.properties new file mode 100644 index 000000000..eff2a7564 --- /dev/null +++ b/lib/HPMA115S0/library.properties @@ -0,0 +1,9 @@ +name=HPMA115S0 Arduino Library +version=1.0.0 +author=Felix Galindo +maintainer=Felix Galindo +sentence=A library for Honeywell HPMA115S0 Particle Sensor +paragraph=Supports the HPMA115S0 +category=Sensors +url=https://github.com/felixgalindo/HPMA115S0.git +architectures=* diff --git a/lib/HPMA115S0/src/hpma115S0.cpp b/lib/HPMA115S0/src/hpma115S0.cpp new file mode 100644 index 000000000..7e5cfc67b --- /dev/null +++ b/lib/HPMA115S0/src/hpma115S0.cpp @@ -0,0 +1,190 @@ +/** + * @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 +#include +#include +} + +/** + * @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(unsigned 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) { + unsigned char cmdBuf[] = {0x68, 0x01, 0x04, 0x93}; + static unsigned char dataBuf[HPM_READ_PARTICLE_MEASURMENT_LEN - 1]; + + //Serial.println("PS- Reading Particle Measurements..." ); + + //Send command + SendCmd(cmdBuf, 4); + + //Read response + if (ReadCmdResp(dataBuf, sizeof(dataBuf), READ_PARTICLE_MEASURMENT) == (HPM_READ_PARTICLE_MEASURMENT_LEN - 1)) { + _pm2_5 = dataBuf[0] * 256 + dataBuf[1]; + _pm10 = dataBuf[2] * 256 + dataBuf[3]; + *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() { + unsigned char cmd[] = {0x68, 0x01, 0x01, 0x96}; + SendCmd(cmd, 4); +} + +/** + * @brief Function that stops sensor measurement + * @return void + */ +void HPMA115S0::StopParticleMeasurement() { + unsigned char cmd[] = {0x68, 0x01, 0x02, 0x95}; + SendCmd(cmd, 4); +} + +/** + * @brief Function that enables auto send + * @return void + */ +void HPMA115S0::EnableAutoSend() { + unsigned char cmd[] = {0x68, 0x01, 0x40, 0x57}; + SendCmd(cmd, 4); +} + +/** + * @brief Function that stops auto send + * @return void + */ +void HPMA115S0::DisableAutoSend() { + unsigned 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; +} diff --git a/lib/HPMA115S0/src/hpma115S0.h b/lib/HPMA115S0/src/hpma115S0.h new file mode 100644 index 000000000..995b86a73 --- /dev/null +++ b/lib/HPMA115S0/src/hpma115S0.h @@ -0,0 +1,123 @@ +/** + * + * @file HPMA115S0.h + * @author Felix A. Galindo + * @date June 2017 + * @brief Arduino Library for Honeywell's Particle Sensor (HPMA115S0-XXX) + * + */ + +#ifndef HPMA115S0_H +#define HPMA115S0_H + +#include "Arduino.h" + +#define HPM_CMD_RESP_HEAD 0x40 +#define HPM_MAX_RESP_SIZE 8 // max command response size is 8 bytes +#define HPM_READ_PARTICLE_MEASURMENT_LEN 5 + +enum CMD_TYPE_T { + READ_PARTICLE_MEASURMENT = 0x04, + START_PARTICLE_MEASURMENT = 0x01, + STOP_PARTICLE_MEASURMENT = 0x02, + SET_ADJUSTMENT_COEFFICIENT = 0x08, + READ_ADJUSTMENT_COEFFICIENT = 0x08, + STOP_AUTO_SEND = 0x20, + ENABLE_AUTO_SEND = 0x40, +}; + +enum HPM_PACKET_T { + HPM_HEAD_IDX, + HPM_LEN_IDX, + HPM_CMD_IDX, + HPM_DATA_START_IDX +}; + +class HPMA115S0 +{ +public: + /** + * @brief Constructor for HPMA115S0 class + * @param a Stream ({Software/Hardware}Serial) object. + * @note The serial stream should be already initialized + * @return void + */ + HPMA115S0(Stream& serial); + + /** + * @brief Function that initializes sensor + * @return a String containing sensor response + */ + void Init(); + + /** + * @brief Function that sends a read command to sensor + * @return returns true if valid measurements were read from sensor + */boolean ReadParticleMeasurement(unsigned int * pm2_5, unsigned int * pm10) + ; + + /** + * @brief Function that starts sensor measurement + * @return void + */ + void StartParticleMeasurement(); + /** + * @brief Function that stops sensor measurement + * @return void + */ + void StopParticleMeasurement(); + + /** + * @brief Function that enables auto send + * @return void + */ + void EnableAutoSend(); + + /** + * @brief Function that stops auto send + * @return void + */ + void DisableAutoSend(); + + /** + * @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 GetPM2_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 GetPM10(); + +private: + Stream& _serial; + + //Latest PM 2.5 reading + unsigned int _pm2_5 = 0; + + //Latest PM 10 reading + unsigned int _pm10 = 0; + + /** + * @brief Function that sends serial command to sensor + * @param a char * containing the command + * @param size of buffer + * @return void + */ + void SendCmd(unsigned char * command, unsigned int size); + + /** + * @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 ReadCmdResp(unsigned char * dataBuf, unsigned int dataBufSize, unsigned int cmdType); +}; + +#endif diff --git a/tasmota/language/bg-BG.h b/tasmota/language/bg-BG.h index ff28de65d..1ac26a0ea 100644 --- a/tasmota/language/bg-BG.h +++ b/tasmota/language/bg-BG.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/cs-CZ.h b/tasmota/language/cs-CZ.h index afe2f33f6..0417eb67b 100644 --- a/tasmota/language/cs-CZ.h +++ b/tasmota/language/cs-CZ.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/de-DE.h b/tasmota/language/de-DE.h index 9916bd923..e5900b056 100644 --- a/tasmota/language/de-DE.h +++ b/tasmota/language/de-DE.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/el-GR.h b/tasmota/language/el-GR.h index 78546d1d5..785d4d486 100644 --- a/tasmota/language/el-GR.h +++ b/tasmota/language/el-GR.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/en-GB.h b/tasmota/language/en-GB.h index 4f8b8d728..5e1ff19c1 100644 --- a/tasmota/language/en-GB.h +++ b/tasmota/language/en-GB.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/es-ES.h b/tasmota/language/es-ES.h index 21636c80b..af9c8039f 100644 --- a/tasmota/language/es-ES.h +++ b/tasmota/language/es-ES.h @@ -1,6 +1,8 @@ /* es-ES.h - localization for Spanish - Spain for Tasmota +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_RX "HPMA Rx" Copyright (C) 2019 Adrian Scillato This program is free software: you can redistribute it and/or modify @@ -548,6 +550,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/fr-FR.h b/tasmota/language/fr-FR.h index 83d8f2ce8..2a8835159 100644 --- a/tasmota/language/fr-FR.h +++ b/tasmota/language/fr-FR.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/he-HE.h b/tasmota/language/he-HE.h index ca1cef4ac..ea8487d6d 100644 --- a/tasmota/language/he-HE.h +++ b/tasmota/language/he-HE.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/hu-HU.h b/tasmota/language/hu-HU.h index a6e22bd4a..6f978e7bb 100644 --- a/tasmota/language/hu-HU.h +++ b/tasmota/language/hu-HU.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/it-IT.h b/tasmota/language/it-IT.h index 16392f675..ad28b0d94 100644 --- a/tasmota/language/it-IT.h +++ b/tasmota/language/it-IT.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/ko-KO.h b/tasmota/language/ko-KO.h index bf8c8fe09..61a84270c 100644 --- a/tasmota/language/ko-KO.h +++ b/tasmota/language/ko-KO.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/nl-NL.h b/tasmota/language/nl-NL.h index baf5e933a..9a752a963 100644 --- a/tasmota/language/nl-NL.h +++ b/tasmota/language/nl-NL.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/pl-PL.h b/tasmota/language/pl-PL.h index 842646b3a..19e8552ca 100644 --- a/tasmota/language/pl-PL.h +++ b/tasmota/language/pl-PL.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/pt-BR.h b/tasmota/language/pt-BR.h index acb44af24..7e5b117a4 100644 --- a/tasmota/language/pt-BR.h +++ b/tasmota/language/pt-BR.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/pt-PT.h b/tasmota/language/pt-PT.h index ff5b3448d..2b36e9a09 100644 --- a/tasmota/language/pt-PT.h +++ b/tasmota/language/pt-PT.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/ru-RU.h b/tasmota/language/ru-RU.h index 8ccbc9df1..e287c3b89 100644 --- a/tasmota/language/ru-RU.h +++ b/tasmota/language/ru-RU.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/sk-SK.h b/tasmota/language/sk-SK.h index de4a72367..9eb0e33dc 100644 --- a/tasmota/language/sk-SK.h +++ b/tasmota/language/sk-SK.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/sv-SE.h b/tasmota/language/sv-SE.h index 466f2e396..87559bee6 100644 --- a/tasmota/language/sv-SE.h +++ b/tasmota/language/sv-SE.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/tr-TR.h b/tasmota/language/tr-TR.h index be515217c..c5f200c78 100644 --- a/tasmota/language/tr-TR.h +++ b/tasmota/language/tr-TR.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/uk-UK.h b/tasmota/language/uk-UK.h index 8d454447c..85483781d 100644 --- a/tasmota/language/uk-UK.h +++ b/tasmota/language/uk-UK.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/zh-CN.h b/tasmota/language/zh-CN.h index 14dd178c9..915c42fc2 100644 --- a/tasmota/language/zh-CN.h +++ b/tasmota/language/zh-CN.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/language/zh-TW.h b/tasmota/language/zh-TW.h index 96504e371..04fff0a37 100644 --- a/tasmota/language/zh-TW.h +++ b/tasmota/language/zh-TW.h @@ -548,6 +548,8 @@ #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" #define D_SENSOR_SBR_RX "SerBr Rx" #define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_SR04_TRIG "SR04 Tri" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 4f93355d6..574d59146 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -456,6 +456,7 @@ //#define PMS_MODEL_PMS3003 // Enable support of PMS3003 instead of PMS5003/PMS7003 (needs the USE_PMS5003 above) #define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+1k5 code) #define STARTING_OFFSET 30 // Turn on NovaSDS XX-seconds before tele_period is reached +#define USE_HPMA // Add support for Honeywell HPMA115S0 particle concentration sensor #define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+0k8 code) //#define USE_MP3_PLAYER // Use of the DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop #define MP3_VOLUME 10 // Set the startup volume on init, the range can be 0..30(max) diff --git a/tasmota/tasmota_post.h b/tasmota/tasmota_post.h index eca4fc85c..da3098418 100644 --- a/tasmota/tasmota_post.h +++ b/tasmota/tasmota_post.h @@ -170,6 +170,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c #define USE_PMS5003 // Add support for PMS5003 and PMS7003 particle concentration sensor (+1k3 code) //#define PMS_MODEL_PMS3003 // Enable support of PMS3003 instead of PMS5003/PMS7003 (needs the USE_PMS5003 above) #define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+0k7 code) +#define USE_HPMA // Add support for Honeywell HPMA115S0 particle concentration sensor #define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+0k8 code) #define USE_MP3_PLAYER // Use of the DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop #define MP3_VOLUME 10 // Set the startup volume on init, the range can be 0..30(max) @@ -365,6 +366,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c #undef USE_SENSEAIR // Disable support for SenseAir K30, K70 and S8 CO2 sensor #undef USE_PMS5003 // Disable support for PMS5003 and PMS7003 particle concentration sensor #undef USE_NOVA_SDS // Disable support for SDS011 and SDS021 particle concentration sensor +#undef USE_HPMA // Disable support for Honeywell HPMA115S0 particle concentration sensor #undef USE_SERIAL_BRIDGE // Disable support for software Serial Bridge #undef USE_MP3_PLAYER // Disable DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop #undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger @@ -452,6 +454,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c #undef USE_SENSEAIR // Disable support for SenseAir K30, K70 and S8 CO2 sensor #undef USE_PMS5003 // Disable support for PMS5003 and PMS7003 particle concentration sensor #undef USE_NOVA_SDS // Disable support for SDS011 and SDS021 particle concentration sensor +#undef USE_HPMA // Disable support for Honeywell HPMA115S0 particle concentration sensor #undef USE_SERIAL_BRIDGE // Disable support for software Serial Bridge #undef USE_MP3_PLAYER // Disable DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop #undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger @@ -553,6 +556,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c #undef USE_SENSEAIR // Disable support for SenseAir K30, K70 and S8 CO2 sensor #undef USE_PMS5003 // Disable support for PMS5003 and PMS7003 particle concentration sensor #undef USE_NOVA_SDS // Disable support for SDS011 and SDS021 particle concentration sensor +#undef USE_HPMA // Disable support for Honeywell HPMA115S0 particle concentration sensor #undef USE_SERIAL_BRIDGE // Disable support for software Serial Bridge #undef USE_MP3_PLAYER // Disable DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop #undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index bf361ca0f..e73e60aad 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -212,6 +212,8 @@ enum UserSelectablePins { GPIO_TASMOTASLAVE_RXD, // Slave RX GPIO_TASMOTASLAVE_RST, // Slave Reset Pin GPIO_TASMOTASLAVE_RST_INV, // Slave Reset Inverted + GPIO_HPMA_RX, // Honeywell HPMA115S0 Serial interface + GPIO_HPMA_TX, // Honeywell HPMA115S0 Serial interface GPIO_SENSOR_END }; // Programmer selectable GPIO functionality @@ -291,6 +293,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_SM2135_CLK "|" D_SENSOR_SM2135_DAT "|" D_SENSOR_DEEPSLEEP "|" D_SENSOR_EXS_ENABLE "|" D_SENSOR_SLAVE_TX "|" D_SENSOR_SLAVE_RX "|" D_SENSOR_SLAVE_RESET "|" D_SENSOR_SLAVE_RESET "i|" + D_SENSOR_HPMA_RX "|" D_SENSOR_HPMA_TX "|" ; const char kSensorNamesFixed[] PROGMEM = @@ -686,6 +689,10 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_SDS0X1_TX, // Nova Fitness SDS011 Serial interface GPIO_SDS0X1_RX, // Nova Fitness SDS011 Serial interface #endif +#ifdef USE_HPMA + GPIO_HPMA_TX, // Honeywell HPMA115S0 Serial interface + GPIO_HPMA_RX, // Honeywell HPMA115S0 Serial interface +#endif #ifdef USE_PMS5003 GPIO_PMS5003, // Plantower PMS5003 Serial interface #endif diff --git a/tasmota/xsns_56_hpma.ino b/tasmota/xsns_56_hpma.ino new file mode 100644 index 000000000..28b8f102d --- /dev/null +++ b/tasmota/xsns_56_hpma.ino @@ -0,0 +1,147 @@ +/* + xsns_56_hpma.ino - Honeywell HPMA115S0 particle concentration sensor support for Tasmota + + Copyright (C) 2019 Theo Arends + Copyright (C) 2019 David Hunt + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_HPMA +/*********************************************************************************************\ + * Honeywell HPMA115S0 particle concentration sensor + * For background information see + * https://sensing.honeywell.com/hpma115s0-xxx-particulate-matter-sensors + * For protocol specification see + * https://sensing.honeywell.com/honeywell-sensing-hpm-series-particle-sensors-datasheet-32322550-e-en.pdf + * +\*********************************************************************************************/ + +#define XSNS_56 56 + +#include +#include + +TasmotaSerial *HpmaSerial; +HPMA115S0 *hpma115S0; + +uint8_t hpma_type = 1; +uint8_t hpma_valid = 0; + +struct hpmadata { + unsigned int pm10; + unsigned int pm2_5; +} hpma_data; + +/*********************************************************************************************/ + +void HpmaSecond(void) // Every second +{ + unsigned int pm2_5, pm10; + + /* + * Sensor sends data every second, so we just read it and update the structure. + */ + if (hpma115S0->ReadParticleMeasurement(&pm2_5, &pm10)) { + hpma_data.pm2_5 = pm2_5; + hpma_data.pm10 = pm10; + hpma_valid = 1; + } + +} + +void HpmaInit(void) +{ + hpma_type = 0; + Serial.println("SDS init"); + if (pin[GPIO_HPMA_RX] < 99 && pin[GPIO_HPMA_TX] < 99) { + HpmaSerial = new TasmotaSerial(pin[GPIO_HPMA_RX], pin[GPIO_HPMA_TX], 1); + hpma115S0 = new HPMA115S0(*HpmaSerial); + + if (HpmaSerial->begin(9600)) { + if (HpmaSerial->hardwareSerial()) { + ClaimSerial(); + } + hpma_type = 1; + hpma115S0->Init(); + hpma115S0->StartParticleMeasurement(); + } + } +} + +#ifdef USE_WEBSERVER +const char HTTP_HPMA_SNS[] PROGMEM = + "{s}HPMA " D_ENVIRONMENTAL_CONCENTRATION "2.5 " D_UNIT_MICROMETER "{m}%s " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" + "{s}HPMA " D_ENVIRONMENTAL_CONCENTRATION "10 " D_UNIT_MICROMETER "{m}%s " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; // {s} = , {m} = , {e} = +#endif // USE_WEBSERVER + +void HpmaShow(bool json) +{ + if (hpma_valid) { + char pm10[33]; + snprintf_P(pm10, 33, PSTR("%d"), hpma_data.pm10); + char pm2_5[33]; + snprintf_P(pm2_5, 33, PSTR("%d"), hpma_data.pm2_5); + + if (json) { + ResponseAppend_P(PSTR(",\"HPMA\":{\"PM2.5\":%d,\"PM10\":%d}"), hpma_data.pm2_5, hpma_data.pm10); +#ifdef USE_DOMOTICZ + if (0 == tele_period) { + DomoticzSensor(DZ_VOLTAGE, pm2_5); // PM2.5 + DomoticzSensor(DZ_CURRENT, pm10); // PM10 + } +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_HPMA_SNS, pm2_5, pm10); +#endif // USE_WEBSERVER + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns56(uint8_t function) +{ + bool result = false; + + if (hpma_type) { + switch (function) { + case FUNC_INIT: + HpmaInit(); + break; + case FUNC_EVERY_SECOND: + HpmaSecond(); + break; + case FUNC_COMMAND_SENSOR: + if (XSNS_56 == XdrvMailbox.index) { + return true; + } + break; + case FUNC_JSON_APPEND: + HpmaShow(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + HpmaShow(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_HPMA