Browse Source

Added support for MHZ19 CO2 sensor

fastled
Xose Pérez 6 years ago
parent
commit
77b05086d9
9 changed files with 2078 additions and 1900 deletions
  1. +0
    -45
      code/espurna/config/general.h
  2. +3
    -0
      code/espurna/config/prototypes.h
  3. +60
    -13
      code/espurna/config/sensors.h
  4. BIN
      code/espurna/data/index.html.gz
  5. +8
    -0
      code/espurna/sensor.ino
  6. +6
    -3
      code/espurna/sensors/BaseSensor.h
  7. +162
    -0
      code/espurna/sensors/MHZ19Sensor.h
  8. +1838
    -1838
      code/espurna/static/index.html.gz.h
  9. +1
    -1
      code/html/custom.js

+ 0
- 45
code/espurna/config/general.h View File

@ -755,51 +755,6 @@ PROGMEM const char* const custom_reset_string[] = {
#define RF_SEND_DELAY 250 // Interval between sendings in ms
#define RF_RECEIVE_DELAY 500 // Interval between recieving in ms (avoid debouncing)
// -----------------------------------------------------------------------------
// SENSORS
// -----------------------------------------------------------------------------
#define SENSOR_READ_INTERVAL 6000 // Read data from sensors every 6 seconds
#define SENSOR_REPORT_EVERY 10 // Report every this many readings
#define SENSOR_USE_INDEX 0 // Use the index in topic (i.e. temperature/0)
// even if just one sensor (0 for backwards compatibility)
#define SENSOR_TEMPERATURE_DECIMALS 1
#define SENSOR_HUMIDITY_DECIMALS 0
#define SENSOR_PRESSURE_DECIMALS 2
#define SENSOR_ANALOG_DECIMALS 0
#define SENSOR_EVENTS_DECIMALS 0
#define SENSOR_CURRENT_DECIMALS 3
#define SENSOR_VOLTAGE_DECIMALS 0
#define SENSOR_POWER_DECIMALS 0
#define SENSOR_POWER_FACTOR_DECIMALS 0
#define SENSOR_ENERGY_DECIMALS 0
#define SENSOR_PM1dot0_DECIMALS 0
#define SENSOR_PM2dot5_DECIMALS 0
#define SENSOR_PM10_DECIMALS 0
#define SENSOR_UNKNOWN_TOPIC "unknown"
#define SENSOR_TEMPERATURE_TOPIC "temperature"
#define SENSOR_HUMIDITY_TOPIC "humidity"
#define SENSOR_PRESSURE_TOPIC "pressure"
#define SENSOR_CURRENT_TOPIC "current"
#define SENSOR_VOLTAGE_TOPIC "voltage"
#define SENSOR_ACTIVE_POWER_TOPIC "power"
#define SENSOR_APPARENT_POWER_TOPIC "apparent"
#define SENSOR_REACTIVE_POWER_TOPIC "reactive"
#define SENSOR_POWER_FACTOR_TOPIC "factor"
#define SENSOR_ENERGY_TOPIC "energy"
#define SENSOR_ENERGY_DELTA_TOPIC "energy_delta"
#define SENSOR_PM1dot0_TOPIC "pm1dot0"
#define SENSOR_PM2dot5_TOPIC "pm2dot5"
#define SENSOR_PM10_TOPIC "pm10"
#define SENSOR_ANALOG_TOPIC "analog"
#define SENSOR_DIGITAL_TOPIC "digital"
#define SENSOR_EVENTS_TOPIC "events"
#define SENSOR_TEMPERATURE_UNITS TMP_CELSIUS // Temperature units (TMP_CELSIUS | TMP_FAHRENHEIT)
#define SENSOR_TEMPERATURE_CORRECTION 0.0 // Offset correction
// -----------------------------------------------------------------------------
// IR
// -----------------------------------------------------------------------------


+ 3
- 0
code/espurna/config/prototypes.h View File

@ -82,6 +82,9 @@ template<typename T> bool idbSend(const char * topic, unsigned char id, T payloa
#include <SoftwareSerial.h>
#include <PMS.h>
#endif
#if MHZ19_SUPPORT
#include <SoftwareSerial.h>
#endif
#if BME280_SUPPORT
#include <SparkFunBME280.h>
#endif


+ 60
- 13
code/espurna/config/sensors.h View File

@ -1,16 +1,51 @@
//--------------------------------------------------------------------------------
// General
//--------------------------------------------------------------------------------
#ifndef TEMPERATURE_MIN_CHANGE
#define TEMPERATURE_MIN_CHANGE 0.0 // Minimum temperature change to report
#endif
#ifndef HUMIDITY_MIN_CHANGE
#define HUMIDITY_MIN_CHANGE 0 // Minimum humidity change to report
#endif
#define TEMPERATURE_DECIMALS 1 // Decimals for temperature values
// -----------------------------------------------------------------------------
// SENSORS
// -----------------------------------------------------------------------------
#define SENSOR_READ_INTERVAL 6000 // Read data from sensors every 6 seconds
#define SENSOR_REPORT_EVERY 10 // Report every this many readings
#define SENSOR_USE_INDEX 0 // Use the index in topic (i.e. temperature/0)
// even if just one sensor (0 for backwards compatibility)
#define SENSOR_TEMPERATURE_UNITS TMP_CELSIUS // Temperature units (TMP_CELSIUS | TMP_FAHRENHEIT)
#define SENSOR_TEMPERATURE_CORRECTION 0.0 // Offset correction
#define TEMPERATURE_MIN_CHANGE 0.0 // Minimum temperature change to report
#define HUMIDITY_MIN_CHANGE 0 // Minimum humidity change to report
#define SENSOR_TEMPERATURE_DECIMALS 1
#define SENSOR_HUMIDITY_DECIMALS 0
#define SENSOR_PRESSURE_DECIMALS 2
#define SENSOR_ANALOG_DECIMALS 0
#define SENSOR_EVENTS_DECIMALS 0
#define SENSOR_CURRENT_DECIMALS 3
#define SENSOR_VOLTAGE_DECIMALS 0
#define SENSOR_POWER_DECIMALS 0
#define SENSOR_POWER_FACTOR_DECIMALS 0
#define SENSOR_ENERGY_DECIMALS 0
#define SENSOR_PM1dot0_DECIMALS 0
#define SENSOR_PM2dot5_DECIMALS 0
#define SENSOR_PM10_DECIMALS 0
#define SENSOR_CO2_DECIMALS 0
#define SENSOR_UNKNOWN_TOPIC "unknown"
#define SENSOR_TEMPERATURE_TOPIC "temperature"
#define SENSOR_HUMIDITY_TOPIC "humidity"
#define SENSOR_PRESSURE_TOPIC "pressure"
#define SENSOR_CURRENT_TOPIC "current"
#define SENSOR_VOLTAGE_TOPIC "voltage"
#define SENSOR_ACTIVE_POWER_TOPIC "power"
#define SENSOR_APPARENT_POWER_TOPIC "apparent"
#define SENSOR_REACTIVE_POWER_TOPIC "reactive"
#define SENSOR_POWER_FACTOR_TOPIC "factor"
#define SENSOR_ENERGY_TOPIC "energy"
#define SENSOR_ENERGY_DELTA_TOPIC "energy_delta"
#define SENSOR_PM1dot0_TOPIC "pm1dot0"
#define SENSOR_PM2dot5_TOPIC "pm2dot5"
#define SENSOR_PM10_TOPIC "pm10"
#define SENSOR_ANALOG_TOPIC "analog"
#define SENSOR_DIGITAL_TOPIC "digital"
#define SENSOR_EVENTS_TOPIC "events"
#define SENSOR_CO2_TOPIC "co2"
//--------------------------------------------------------------------------------
// DHTXX temperature/humidity sensor
@ -244,6 +279,18 @@
#define PMS_RX_PIN 13
#define PMS_TX_PIN 15
//--------------------------------------------------------------------------------
// MHZ19 CO2 sensor
// Enable support by passing MHZ19_SUPPORT=1 build flag
//--------------------------------------------------------------------------------
#ifndef MHZ19_SUPPORT
#define MHZ19_SUPPORT 1
#endif
#define MHZ19_RX_PIN 13
#define MHZ19_TX_PIN 15
//--------------------------------------------------------------------------------
// Internal power montior
// Enable support by passing ADC_VCC_ENABLED=1 build flag


BIN
code/espurna/data/index.html.gz View File


+ 8
- 0
code/espurna/sensor.ino View File

@ -55,6 +55,7 @@ String _sensorTopic(magnitude_t type) {
if (type == MAGNITUDE_PM1dot0) return String(SENSOR_PM1dot0_TOPIC);
if (type == MAGNITUDE_PM2dot5) return String(SENSOR_PM2dot5_TOPIC);
if (type == MAGNITUDE_PM10) return String(SENSOR_PM10_TOPIC);
if (type == MAGNITUDE_CO2) return String(SENSOR_CO2_TOPIC);
return String(SENSOR_UNKNOWN_TOPIC);
}
@ -75,6 +76,7 @@ unsigned char _sensorDecimals(magnitude_t type) {
if (type == MAGNITUDE_PM1dot0) return SENSOR_PM1dot0_DECIMALS;
if (type == MAGNITUDE_PM2dot5) return SENSOR_PM2dot5_DECIMALS;
if (type == MAGNITUDE_PM10) return SENSOR_PM10_DECIMALS;
if (type == MAGNITUDE_CO2) return SENSOR_CO2_DECIMALS;
return 0;
}
@ -94,6 +96,7 @@ String _sensorUnits(magnitude_t type) {
if (type == MAGNITUDE_PM1dot0) return String("µg/m3");
if (type == MAGNITUDE_PM2dot5) return String("µg/m3");
if (type == MAGNITUDE_PM10) return String("µg/m3");
if (type == MAGNITUDE_CO2) return String("ppm");
return String();
}
@ -282,6 +285,11 @@ void sensorInit() {
sensorRegister(new PMSX003Sensor(PMS_RX_PIN, PMS_TX_PIN));
#endif
#if MHZ19_SUPPORT
#include "sensors/MHZ19Sensor.h"
sensorRegister(new MHZ19Sensor(MHZ19_RX_PIN, MHZ19_TX_PIN));
#endif
#if COUNTER_SUPPORT
#include "sensors/EventSensor.h"
sensorRegister(new EventSensor(COUNTER_PIN, COUNTER_PIN_MODE, COUNTER_DEBOUNCE));


+ 6
- 3
code/espurna/sensors/BaseSensor.h View File

@ -31,13 +31,16 @@ typedef enum magnitude_t {
MAGNITUDE_PM2dot5,
MAGNITUDE_PM10,
MAGNITUDE_CO2,
MAGNITUDE_MAX,
} magnitude_t;
#define SENSOR_ERROR_OK 0
#define SENSOR_ERROR_OUT_OF_RANGE 1
#define SENSOR_ERROR_WARM_UP 2
#define SENSOR_ERROR_OK 0 // No error
#define SENSOR_ERROR_OUT_OF_RANGE 1 // Result out of sensor range
#define SENSOR_ERROR_WARM_UP 2 // Sensor is warming-up
#define SENSOR_ERROR_TIMEOUT 3 // Response from sensor timed out
class BaseSensor {


+ 162
- 0
code/espurna/sensors/MHZ19Sensor.h View File

@ -0,0 +1,162 @@
// -----------------------------------------------------------------------------
// MHZ19 CO2 sensor
// Based on: https://github.com/nara256/mhz19_uart
// http://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf
// -----------------------------------------------------------------------------
#pragma once
#include "Arduino.h"
#include "BaseSensor.h"
#include <SoftwareSerial.h>
#define MHZ19_REQUEST_LEN 8
#define MHZ19_RESPONSE_LEN 9
#define MHZ19_TIMEOUT 1000
#define MHZ19_GETPPM 0x8600
#define MHZ19_ZEROCALIB 0x8700
#define MHZ19_SPANCALIB 0x8800
#define MHZ19_AUTOCALIB_ON 0x79A0
#define MHZ19_AUTOCALIB_OFF 0x7900
class MHZ19Sensor : public BaseSensor {
public:
MHZ19Sensor(int pin_rx = MHZ19_RX_PIN, int pin_tx = MHZ19_TX_PIN): BaseSensor() {
// Cache
_pin_rx = pin_rx;
_pin_tx = pin_tx;
_count = 1;
// Init
_serial = new SoftwareSerial(pin_rx, pin_tx, false, 256);
_serial->begin(9600);
calibrateAuto(false);
}
// Descriptive name of the sensor
String name() {
char buffer[28];
snprintf(buffer, sizeof(buffer), "MHZ19 @ SwSerial(%i,%i)", _pin_rx, _pin_tx);
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return name();
}
// Type for slot # index
magnitude_t type(unsigned char index) {
_error = SENSOR_ERROR_OK;
if (index == 0) return MAGNITUDE_CO2;
_error = SENSOR_ERROR_OUT_OF_RANGE;
return MAGNITUDE_NONE;
}
void pre() {
_read();
}
// Current value for slot # index
double value(unsigned char index) {
_error = SENSOR_ERROR_OK;
if (index == 0) return _co2;
_error = SENSOR_ERROR_OUT_OF_RANGE;
return 0;
}
void calibrateAuto(boolean state){
_write(state ? MHZ19_AUTOCALIB_ON : MHZ19_AUTOCALIB_OFF);
}
void calibrateZero() {
_write(MHZ19_ZEROCALIB);
}
void calibrateSpan(unsigned int ppm) {
if( ppm < 1000 ) return;
unsigned char buffer[MHZ19_REQUEST_LEN] = {0};
buffer[0] = 0xFF;
buffer[1] = 0x01;
buffer[2] = MHZ19_SPANCALIB >> 8;
buffer[3] = ppm >> 8;
buffer[4] = ppm & 0xFF;
_write(buffer);
}
protected:
void _write(unsigned char * command) {
_serial->write(command, MHZ19_REQUEST_LEN);
_serial->write(_checksum(command));
_serial->flush();
}
void _write(unsigned int command, unsigned char * response) {
unsigned char buffer[MHZ19_REQUEST_LEN] = {0};
buffer[0] = 0xFF;
buffer[1] = 0x01;
buffer[2] = command >> 8;
buffer[3] = command & 0xFF;
_write(buffer);
if (response != NULL) {
unsigned long start = millis();
while (_serial->available() == 0) {
if (millis() - start > MHZ19_TIMEOUT) {
_error = SENSOR_ERROR_TIMEOUT;
return;
}
yield();
}
_serial->readBytes(response, MHZ19_RESPONSE_LEN);
}
}
void _write(unsigned int command) {
_write(command, NULL);
}
void _read() {
unsigned char buffer[MHZ19_RESPONSE_LEN] = {0};
_write(MHZ19_GETPPM, buffer);
// Check response
if ((buffer[0] == 0xFF)
&& (buffer[1] == 0x86)
&& (_checksum(buffer) == buffer[MHZ19_RESPONSE_LEN-1])) {
unsigned int value = buffer[2] * 256 + buffer[3];
if (0 <= value && value <= 5000) {
_co2 = value;
_error = SENSOR_ERROR_OK;
} else {
_error = SENSOR_ERROR_OUT_OF_RANGE;
}
}
}
uint8_t _checksum(uint8_t * command) {
uint8_t sum = 0x00;
for (unsigned char i = 1; i < MHZ19_REQUEST_LEN-1; i++) {
sum += command[i];
}
sum = 0xFF - sum + 0x01;
return sum;
}
double _co2 = 0;
unsigned int _pin_rx;
unsigned int _pin_tx;
SoftwareSerial * _serial;
};

+ 1838
- 1838
code/espurna/static/index.html.gz.h
File diff suppressed because it is too large
View File


+ 1
- 1
code/html/custom.js View File

@ -33,7 +33,7 @@ function sensorType(type) {
"Current", "Voltage", "Active Power", "Apparent Power",
"Reactive Power", "Energy", "Energy (delta)", "Power Factor",
"Analog", "Digital", "Events",
"PM1.0", "PM2.5", "PM10"
"PM1.0", "PM2.5", "PM10", "CO2"
];
if (1 <= type && type <= types.length) return types[type-1];
return null;


Loading…
Cancel
Save