esphome / feature-requests

ESPHome Feature Request Tracker
https://esphome.io/
404 stars 26 forks source link

Request: MQ135 Air Quality Sensor (PPM) support #757

Open micfogas opened 4 years ago

micfogas commented 4 years ago

Describe the problem you have/What new integration you would like

I would like to request sensor integration for the MQ135 air quality gas sensor. This sensor provides 4 pins: 3.3v, GND, DOUT, AOUT.

Please describe your use case for this integration and alternatives you've tried:

I have tried using custom sensor integrations, however I am still learning C++ and Arduino coding. I have found multiple libraries online (in .ino form and .h/.cpp form), and have tried multiple ways to impliment it into ESPHome, but I have been unsuccessful. Each library appears to use its own formula for calibration. The most accurate, from what I have heard, exists here: https://github.com/GeorgK/MQ135 however, additional libraries are: https://platformio.org/lib/show/2537/TroykaMQ (comments in russian) and https://os.mbed.com/users/ngomez/code/MQ135/

Additional context

This is a gas/VOC sensor and should provide a reading output in PPM (particles per million). It appears the AOUT is used to provide the data to the NodeMCU/ESP8266.

AlexBelfegor commented 3 years ago

Here I changed the library for yaml format. Outdoor calibration is required for adequate performance. https://github.com/AlexBelfegor/esphome-mq135

micfogas commented 3 years ago

thank you @AlexBelfegor !!

hco commented 3 years ago

@AlexBelfegor could you explain the calibration a little bit? If I put it on the street, which numbers do I need to read and where do I need to put them?

AlexBelfegor commented 3 years ago

@AlexBelfegor could you explain the calibration a little bit? If I put it on the street, which numbers do I need to read and where do I need to put them?

You need to get CorrectedRZero on the street and enter this value into RZERO.

dragonerix commented 3 years ago

Hi @AlexBelfegor , can you help me with calibration... i must rewrite 2 index:

Calibration resistance at atmospheric CO2 level. Outdoor calibration data

Atmospheric CO2 level for calibration purposes. Outdoor CO2 level during calibration. Usually 450, but it's better to clarify.

True? Ok, i put sensro out door and get some data from (Corrected PPM CO2, PPM CO2, CorrectedRZero, RZero) Which i need use to write... Correcter or clasic? Thank you so much and sorry for my english.

PS? C.RZero > RZero and C.CO2 > CO2?

AlexBelfegor commented 3 years ago

Hi @AlexBelfegor , can you help me with calibration... i must rewrite 2 index:

Calibration resistance at atmospheric CO2 level. Outdoor calibration data

Atmospheric CO2 level for calibration purposes. Outdoor CO2 level during calibration. Usually 450, but it's better to clarify.

True? Ok, i put sensro out door and get some data from (Corrected PPM CO2, PPM CO2, CorrectedRZero, RZero) Which i need use to write... Correcter or clasic? Thank you so much and sorry for my english. PS? C.RZero > RZero and C.CO2 > CO2?

I already answered earlier. You need to get the CorrectedRZero readings on the street and write their globals RZERO (line 60 "initial_value: '35 .429 '").

"CorrectedRZero" and "RZERO" and "Corrected PPM CO2" and "PPM CO2" differ in that Corrected also takes into account temperature and humidity.

Bojkas1985 commented 3 years ago

Hi, @AlexBelfegor , is it possible to use the DHT11 / 22 sensor instead of htu21d, or not use any? I changed all htu21d to dht

sensor:
  - platform: dht
    pin: D2
    temperature:
      name: "Temperature dht"
      id: dht_temperature
    humidity:
      name: "Humidity"
      id: dht_humidity
      filters:
      - lambda: if ((id(dht_temperature).state)>=0) {return (id(dht_humidity).raw_state + (25.0 - id(dht_temperature).state) * (-0.15));} else {return id(dht_humidity).raw_state;}
    update_interval: 30s

and

lambda: |-
      if (id(dht_temperature).state<20) {
        return (id(CORA) * id(dht_temperature).state * id(dht_temperature).state - id(CORB) *
          id(dht_temperature).state + id(CORC) - (id(dht_humidity).state - 33.) * id(CORD));
      } else {
        return (id(CORE) * id(dht_temperature).state + id(CORF) * id(dht_humidity).state + id(CORG));
      }

But dht22 shows wrong temperature, at home 3,5°C and humidity 16%. I have 25°C and 55%. Any sugestion?

Thank you

AlexBelfegor commented 3 years ago

Hi, @AlexBelfegor , is it possible to use the DHT11 / 22 sensor instead of htu21d, or not use any? I changed all htu21d to dht But dht22 shows wrong temperature, at home 3,5°C and humidity 16%. I have 25°C and 55%. Any sugestion?

You can use any humidity and temperature sensor of your choice. But its resurrection is mandatory, because the formulas provide for the adjustment of temperature and humidity. You may have a faulty sensor. The code has an adjustment for humidity, but the temperature is taken as is.

Bojkas1985 commented 3 years ago

You can use any humidity and temperature sensor of your choice. But its resurrection is mandatory, because the formulas provide for the adjustment of temperature and humidity. You may have a faulty sensor. The code has an adjustment for humidity, but the temperature is taken as is.

Can you please see if I'm all right? I only changed the temperature sensor to DHT.

esphome:
  name: co2_navstevnicky_pokoj
  platform: ESP8266
  board: nodemcuv2

wifi:
  ssid: Internet home
  password: ""

  # Optional manual IP

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "co2_navstevnicky_pokoj"
    password: ""

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:
  password: ""

ota:
   password: ""
   safe_mode: True

web_server:
  port: 80
  auth:
    username: admin
    password: ""

i2c:
  sda: 5
  scl: 4
  scan: False
  id: bus_a

globals:

#The load resistance on the board. Value in KiloOhms
  - id: RLOAD
    type: float
    restore_value: no
    initial_value: '1.025'

#Calibration resistance at atmospheric CO2 level. Outdoor calibration data
  - id: RZERO
    type: float
    restore_value: no
    initial_value: '5.175'

#Atmospheric CO2 level for calibration purposes. Outdoor CO2 level during calibration. Usually 450, but it's better to clarify.
  - id: ATMOCO2
    type: float
    restore_value: no
    initial_value: '450'

#Parameters for calculating ppm of CO2 from sensor resistance
#  Exponential regression:
#  GAS      | a      | b
#  CO       | 605.18 | -3.937  
#  Alcohol  | 77.255 | -3.18 
#  CO2      | 110.47 | -2.862
#  Tolueno  | 44.947 | -3.445
#  NH4      | 102.2  | -2.473
#  Acetona  | 34.668 | -3.369
  - id: PARA
    type: float
    restore_value: no
    initial_value: '110.47'
  - id: PARB
    type: float
    restore_value: no
    initial_value: '-2.862'

#Parameters to model temperature and humidity dependence
  - id: CORA
    type: float
    restore_value: no
    initial_value: '0.00035'
  - id: CORB
    type: float
    restore_value: no
    initial_value: '0.02718'
  - id: CORC
    type: float
    restore_value: no
    initial_value: '1.39538'
  - id: CORD
    type: float
    restore_value: no
    initial_value: '0.0018'
  - id: CORE
    type: float
    restore_value: no
    initial_value: '-0.003333333'
  - id: CORF
    type: float
    restore_value: no
    initial_value: '-0.001923077'
  - id: CORG
    type: float
    restore_value: no
    initial_value: '1.130128205'

# Here you need to indicate the supply voltage of the MQ135 sensor. It can be measured with a voltmeter. Please note that the rated power will not always be accurate.
  - id: volt_resolution
    type: float
    restore_value: no
    initial_value: '5.14'

# 1 for Exponential, 2 for Linear
  - id: regression_method
    type: int
    restore_value: no
    initial_value: '1'

sensor:
  - platform: dht
    pin: D2
    temperature:
      name: "Temperature dht"
      id: dht_temperature
    humidity:
      name: "Humidity"
      id: dht_humidity
      filters:
      - lambda: if ((id(dht_temperature).state)>=0) {return (id(dht_humidity).raw_state + (25.0 - id(dht_temperature).state) * (-0.15));} else {return id(dht_humidity).raw_state;}
    update_interval: 30s

  - platform: adc
    pin: A0
    name: "Gas ADC"
    update_interval: 1s
    filters:
      - multiply: 3.3 # for NodeMcu ESP8266 v3 Lua
    accuracy_decimals: 0
    unit_of_measurement: V
    id: sensor_volt

  - platform: template
    #Linearization of the temperature dependency curve under and above 20 degree C
    #below 20degC: fact = a * t * t - b * t - (h - 33) * d
    #above 20degC: fact = a * t + b * h + c
    #this assumes a linear dependency on humidity
    #getCorrectionFactor
    name: "Correction Factor"
    lambda: |-
      if (id(dht_temperature).state<20) {
        return (id(CORA) * id(dht_temperature).state * id(dht_temperature).state - id(CORB) *
          id(dht_temperature).state + id(CORC) - (id(dht_humidity).state - 33.) * id(CORD));
      } else {
        return (id(CORE) * id(dht_temperature).state + id(CORF) * id(dht_humidity).state + id(CORG));
      }
    update_interval: 10s
    accuracy_decimals: 6
    id: correction_factor

  - platform: template
    #Get the resistance of the sensor, ie. the measurement value @return The sensor resistance in kOhm
    # RS = [(VC x RL) / VRL] - RL
    # RS_air = ((5.14*1.0)/sensor_volt)-1.0 Calculate RS in fresh air 
    #getResistance
    name: "Resistance"
    lambda: |-
      return ((id(volt_resolution)*id(RLOAD)/id(sensor_volt).state) - id(RLOAD));
    update_interval: 5s
    accuracy_decimals: 3
    unit_of_measurement: kOm
    id: resistance

  - platform: template
    # Get the resistance of the sensor, ie. the measurement value correctedfor temp/hum @return The corrected sensor resistance kOhm
    #getCorrectedResistance
    name: "Corrected Resistance"
    lambda: |-
      return (id(resistance).state / id(correction_factor).state);
    update_interval: 5s
    accuracy_decimals: 3
    unit_of_measurement: kOm
    id: corrected_resistance

  - platform: template
    # Get the ppm of CO2 sensed (assuming only CO2 in the air). The ppm of CO2 in the air
    #getPPM
    name: "PPM CO2"
    lambda: |-
      if (id(regression_method)==1) {
        return (id(PARA) * pow((id(resistance).state / id(RZERO)), id(PARB)));
      } else {
        return (pow(10, (log10(id(resistance).state / id(RZERO)) - id(PARB)) / id(PARA)));
      }
    update_interval: 5s
    unit_of_measurement: ppm
    id: ppm_co2

  - platform: template
    # Get the ppm of CO2 sensed (assuming only CO2 in the air), corrected  for temp. The ppm of CO2 in the air
    #getCorrectedPPM
    name: "Corrected PPM CO2"
    lambda: |-
      if (id(regression_method)==1) {
        return (id(PARA) * pow((id(corrected_resistance).state / id(RZERO)), id(PARB)));
      } else {
        return (pow(10, (log10(id(corrected_resistance).state / id(RZERO)) - id(PARB)) / id(PARA)));
      }
    update_interval: 5s
    unit_of_measurement: ppm
    id: corrected_ppm_co2

  - platform: template
    # Get the resistance RZero of the sensor for calibration purposes. The sensor resistance RZero in kOhm
    #getRZero
    name: "RZero"
    lambda: |-
      return (id(resistance).state / pow((id(ATMOCO2) / id(PARA)), (1./id(PARB))));
    filters:
      - sliding_window_moving_average:
          window_size: 15
          send_every: 1
    update_interval: 5s
    accuracy_decimals: 3
    unit_of_measurement: kOm
    id: r_zero

  - platform: template
    # Get the corrected resistance RZero of the sensor for calibration purposes. The corrected sensor resistance RZERO in kOhm for ATMOCO2 level
    #getCorrectedRZero
    name: "CorrectedRZero"
    lambda: |-
      return (id(corrected_resistance).state / pow((id(ATMOCO2) / id(PARA)), (1./id(PARB))));
    filters:
      - sliding_window_moving_average:
          window_size: 15
          send_every: 1
    update_interval: 5s
    accuracy_decimals: 3
    unit_of_measurement: kOm
    id: corrected_r_zero

I tried another sensor and the result is the same. :-/ Another problem I have is that I pulled the device out, left it there for about half an hour, pulled it out from Hassio CorrectedRZero, wrote to RZero in code, and reloaded into the device. For a while I had a value around 430, but now at home after about 4 hours there I have correcterd CO 60ppm.

AlexBelfegor commented 3 years ago

Unfortunately, I cannot tell what problem you have with the temperature sensor. If it shows data that is different from the real one, then the problem is in the sensor. First, get the humidity and temperature sensor normal. You can find out more about their configuration here https://esphome.io/components/sensor/dht.html?highlight=dht. After that, you can already calibrate the device. There is no point in calibrating without a working temperature sensor.

З повагою та побажанням успіхів,

Олександр Петрович Портянко


Україна, Київ, вул. Руденко, 6а, оф.630

+38 067 2-316-316

+38 044 536-4-666

E-mail: alexportyanko@gmail.com

www.inconsulting.com.ua

www.wookko.com.ua

www.el-studio.in.ua

www.isdiplom.com

вт, 26 янв. 2021 г. в 17:47, Bojkas1985 notifications@github.com:

You can use any humidity and temperature sensor of your choice. But its resurrection is mandatory, because the formulas provide for the adjustment of temperature and humidity. You may have a faulty sensor. The code has an adjustment for humidity, but the temperature is taken as is.

Can you please see if I'm all right? I only changed the temperature sensor to DHT.

esphome: name: co2_navstevnicky_pokoj platform: ESP8266 board: nodemcuv2

wifi: ssid: Internet home password: ""

Optional manual IP

Enable fallback hotspot (captive portal) in case wifi connection fails

ap: ssid: "co2_navstevnicky_pokoj" password: ""

captive_portal:

Enable logging

logger:

Enable Home Assistant API

api: password: ""

ota: password: "" safe_mode: True

web_server: port: 80 auth: username: admin password: ""

i2c: sda: 5 scl: 4 scan: False id: bus_a

globals:

The load resistance on the board. Value in KiloOhms

  • id: RLOAD type: float restore_value: no initial_value: '1.025'

Calibration resistance at atmospheric CO2 level. Outdoor calibration data

  • id: RZERO type: float restore_value: no initial_value: '5.175'

Atmospheric CO2 level for calibration purposes. Outdoor CO2 level during calibration. Usually 450, but it's better to clarify.

  • id: ATMOCO2 type: float restore_value: no initial_value: '450'

Parameters for calculating ppm of CO2 from sensor resistance

Exponential regression:

GAS | a | b

CO | 605.18 | -3.937

Alcohol | 77.255 | -3.18

CO2 | 110.47 | -2.862

Tolueno | 44.947 | -3.445

NH4 | 102.2 | -2.473

Acetona | 34.668 | -3.369

  • id: PARA type: float restore_value: no initial_value: '110.47'
  • id: PARB type: float restore_value: no initial_value: '-2.862'

Parameters to model temperature and humidity dependence

  • id: CORA type: float restore_value: no initial_value: '0.00035'
  • id: CORB type: float restore_value: no initial_value: '0.02718'
  • id: CORC type: float restore_value: no initial_value: '1.39538'
  • id: CORD type: float restore_value: no initial_value: '0.0018'
  • id: CORE type: float restore_value: no initial_value: '-0.003333333'
  • id: CORF type: float restore_value: no initial_value: '-0.001923077'
  • id: CORG type: float restore_value: no initial_value: '1.130128205'

Here you need to indicate the supply voltage of the MQ135 sensor. It can be measured with a voltmeter. Please note that the rated power will not always be accurate.

  • id: volt_resolution type: float restore_value: no initial_value: '5.14'

1 for Exponential, 2 for Linear

  • id: regression_method type: int restore_value: no initial_value: '1'

sensor:

  • platform: dht pin: D2 temperature: name: "Temperature dht" id: dht_temperature humidity: name: "Humidity" id: dht_humidity filters:

    • lambda: if ((id(dht_temperature).state)>=0) {return (id(dht_humidity).raw_state + (25.0 - id(dht_temperature).state) * (-0.15));} else {return id(dht_humidity).raw_state;} update_interval: 30s
  • platform: adc pin: A0 name: "Gas ADC" update_interval: 1s filters:

    • multiply: 3.3 # for NodeMcu ESP8266 v3 Lua accuracy_decimals: 0 unit_of_measurement: V id: sensor_volt
  • platform: template

    Linearization of the temperature dependency curve under and above 20 degree C

    below 20degC: fact = a t t - b t - (h - 33) d

    above 20degC: fact = a t + b h + c

    this assumes a linear dependency on humidity

    getCorrectionFactor

    name: "Correction Factor" lambda: |- if (id(dht_temperature).state<20) { return (id(CORA) id(dht_temperature).state id(dht_temperature).state - id(CORB) id(dht_temperature).state + id(CORC) - (id(dht_humidity).state - 33.) id(CORD)); } else { return (id(CORE) id(dht_temperature).state + id(CORF) id(dht_humidity).state + id(CORG)); } update_interval: 10s accuracy_decimals: 6 id: correction_factor

  • platform: template

    Get the resistance of the sensor, ie. the measurement value @return The sensor resistance in kOhm

    RS = [(VC x RL) / VRL] - RL

    RS_air = ((5.14*1.0)/sensor_volt)-1.0 Calculate RS in fresh air

    getResistance

    name: "Resistance" lambda: |- return ((id(volt_resolution)*id(RLOAD)/id(sensor_volt).state) - id(RLOAD)); update_interval: 5s accuracy_decimals: 3 unit_of_measurement: kOm id: resistance

  • platform: template

    Get the resistance of the sensor, ie. the measurement value correctedfor temp/hum @return The corrected sensor resistance kOhm

    getCorrectedResistance

    name: "Corrected Resistance" lambda: |- return (id(resistance).state / id(correction_factor).state); update_interval: 5s accuracy_decimals: 3 unit_of_measurement: kOm id: corrected_resistance

  • platform: template

    Get the ppm of CO2 sensed (assuming only CO2 in the air). The ppm of CO2 in the air

    getPPM

    name: "PPM CO2" lambda: |- if (id(regression_method)==1) { return (id(PARA) * pow((id(resistance).state / id(RZERO)), id(PARB))); } else { return (pow(10, (log10(id(resistance).state / id(RZERO)) - id(PARB)) / id(PARA))); } update_interval: 5s unit_of_measurement: ppm id: ppm_co2

  • platform: template

    Get the ppm of CO2 sensed (assuming only CO2 in the air), corrected for temp. The ppm of CO2 in the air

    getCorrectedPPM

    name: "Corrected PPM CO2" lambda: |- if (id(regression_method)==1) { return (id(PARA) * pow((id(corrected_resistance).state / id(RZERO)), id(PARB))); } else { return (pow(10, (log10(id(corrected_resistance).state / id(RZERO)) - id(PARB)) / id(PARA))); } update_interval: 5s unit_of_measurement: ppm id: corrected_ppm_co2

  • platform: template

    Get the resistance RZero of the sensor for calibration purposes. The sensor resistance RZero in kOhm

    getRZero

    name: "RZero" lambda: |- return (id(resistance).state / pow((id(ATMOCO2) / id(PARA)), (1./id(PARB)))); filters:

    • sliding_window_moving_average: window_size: 15 send_every: 1 update_interval: 5s accuracy_decimals: 3 unit_of_measurement: kOm id: r_zero
  • platform: template

    Get the corrected resistance RZero of the sensor for calibration purposes. The corrected sensor resistance RZERO in kOhm for ATMOCO2 level

    getCorrectedRZero

    name: "CorrectedRZero" lambda: |- return (id(corrected_resistance).state / pow((id(ATMOCO2) / id(PARA)), (1./id(PARB)))); filters:

    • sliding_window_moving_average: window_size: 15 send_every: 1 update_interval: 5s accuracy_decimals: 3 unit_of_measurement: kOm id: corrected_r_zero

I tried another sensor and the result is the same. :-/ Another problem I have is that I pulled the device out, left it there for about half an hour, pulled it out from Hassio CorrectedRZero, wrote to RZero in code, and reloaded into the device. For a while I had a value around 430, but now at home after about 4 hours there I have correcterd CO 60ppm.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/esphome/feature-requests/issues/757#issuecomment-767633684, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACEISZA4JXH6K4QNIIP4FXTS33PZPANCNFSM4NS65E5A .

ohormazabal commented 3 years ago

You can use any humidity and temperature sensor of your choice. But its resurrection is mandatory, because the formulas provide for the adjustment of temperature and humidity. You may have a faulty sensor. The code has an adjustment for humidity, but the temperature is taken as is.

Can you please see if I'm all right? I only changed the temperature sensor to DHT.

esphome:
  name: co2_navstevnicky_pokoj
  platform: ESP8266
  board: nodemcuv2

wifi:
  ssid: Internet home
  password: ""

  # Optional manual IP

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "co2_navstevnicky_pokoj"
    password: ""

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:
  password: ""

ota:
   password: ""
   safe_mode: True

web_server:
  port: 80
  auth:
    username: admin
    password: ""

i2c:
  sda: 5
  scl: 4
  scan: False
  id: bus_a

globals:

#The load resistance on the board. Value in KiloOhms
  - id: RLOAD
    type: float
    restore_value: no
    initial_value: '1.025'

#Calibration resistance at atmospheric CO2 level. Outdoor calibration data
  - id: RZERO
    type: float
    restore_value: no
    initial_value: '5.175'

#Atmospheric CO2 level for calibration purposes. Outdoor CO2 level during calibration. Usually 450, but it's better to clarify.
  - id: ATMOCO2
    type: float
    restore_value: no
    initial_value: '450'

#Parameters for calculating ppm of CO2 from sensor resistance
#  Exponential regression:
#  GAS      | a      | b
#  CO       | 605.18 | -3.937  
#  Alcohol  | 77.255 | -3.18 
#  CO2      | 110.47 | -2.862
#  Tolueno  | 44.947 | -3.445
#  NH4      | 102.2  | -2.473
#  Acetona  | 34.668 | -3.369
  - id: PARA
    type: float
    restore_value: no
    initial_value: '110.47'
  - id: PARB
    type: float
    restore_value: no
    initial_value: '-2.862'

#Parameters to model temperature and humidity dependence
  - id: CORA
    type: float
    restore_value: no
    initial_value: '0.00035'
  - id: CORB
    type: float
    restore_value: no
    initial_value: '0.02718'
  - id: CORC
    type: float
    restore_value: no
    initial_value: '1.39538'
  - id: CORD
    type: float
    restore_value: no
    initial_value: '0.0018'
  - id: CORE
    type: float
    restore_value: no
    initial_value: '-0.003333333'
  - id: CORF
    type: float
    restore_value: no
    initial_value: '-0.001923077'
  - id: CORG
    type: float
    restore_value: no
    initial_value: '1.130128205'

# Here you need to indicate the supply voltage of the MQ135 sensor. It can be measured with a voltmeter. Please note that the rated power will not always be accurate.
  - id: volt_resolution
    type: float
    restore_value: no
    initial_value: '5.14'

# 1 for Exponential, 2 for Linear
  - id: regression_method
    type: int
    restore_value: no
    initial_value: '1'

sensor:
  - platform: dht
    pin: D2
    temperature:
      name: "Temperature dht"
      id: dht_temperature
    humidity:
      name: "Humidity"
      id: dht_humidity
      filters:
      - lambda: if ((id(dht_temperature).state)>=0) {return (id(dht_humidity).raw_state + (25.0 - id(dht_temperature).state) * (-0.15));} else {return id(dht_humidity).raw_state;}
    update_interval: 30s

  - platform: adc
    pin: A0
    name: "Gas ADC"
    update_interval: 1s
    filters:
      - multiply: 3.3 # for NodeMcu ESP8266 v3 Lua
    accuracy_decimals: 0
    unit_of_measurement: V
    id: sensor_volt

  - platform: template
    #Linearization of the temperature dependency curve under and above 20 degree C
    #below 20degC: fact = a * t * t - b * t - (h - 33) * d
    #above 20degC: fact = a * t + b * h + c
    #this assumes a linear dependency on humidity
    #getCorrectionFactor
    name: "Correction Factor"
    lambda: |-
      if (id(dht_temperature).state<20) {
        return (id(CORA) * id(dht_temperature).state * id(dht_temperature).state - id(CORB) *
          id(dht_temperature).state + id(CORC) - (id(dht_humidity).state - 33.) * id(CORD));
      } else {
        return (id(CORE) * id(dht_temperature).state + id(CORF) * id(dht_humidity).state + id(CORG));
      }
    update_interval: 10s
    accuracy_decimals: 6
    id: correction_factor

  - platform: template
    #Get the resistance of the sensor, ie. the measurement value @return The sensor resistance in kOhm
    # RS = [(VC x RL) / VRL] - RL
    # RS_air = ((5.14*1.0)/sensor_volt)-1.0 Calculate RS in fresh air 
    #getResistance
    name: "Resistance"
    lambda: |-
      return ((id(volt_resolution)*id(RLOAD)/id(sensor_volt).state) - id(RLOAD));
    update_interval: 5s
    accuracy_decimals: 3
    unit_of_measurement: kOm
    id: resistance

  - platform: template
    # Get the resistance of the sensor, ie. the measurement value correctedfor temp/hum @return The corrected sensor resistance kOhm
    #getCorrectedResistance
    name: "Corrected Resistance"
    lambda: |-
      return (id(resistance).state / id(correction_factor).state);
    update_interval: 5s
    accuracy_decimals: 3
    unit_of_measurement: kOm
    id: corrected_resistance

  - platform: template
    # Get the ppm of CO2 sensed (assuming only CO2 in the air). The ppm of CO2 in the air
    #getPPM
    name: "PPM CO2"
    lambda: |-
      if (id(regression_method)==1) {
        return (id(PARA) * pow((id(resistance).state / id(RZERO)), id(PARB)));
      } else {
        return (pow(10, (log10(id(resistance).state / id(RZERO)) - id(PARB)) / id(PARA)));
      }
    update_interval: 5s
    unit_of_measurement: ppm
    id: ppm_co2

  - platform: template
    # Get the ppm of CO2 sensed (assuming only CO2 in the air), corrected  for temp. The ppm of CO2 in the air
    #getCorrectedPPM
    name: "Corrected PPM CO2"
    lambda: |-
      if (id(regression_method)==1) {
        return (id(PARA) * pow((id(corrected_resistance).state / id(RZERO)), id(PARB)));
      } else {
        return (pow(10, (log10(id(corrected_resistance).state / id(RZERO)) - id(PARB)) / id(PARA)));
      }
    update_interval: 5s
    unit_of_measurement: ppm
    id: corrected_ppm_co2

  - platform: template
    # Get the resistance RZero of the sensor for calibration purposes. The sensor resistance RZero in kOhm
    #getRZero
    name: "RZero"
    lambda: |-
      return (id(resistance).state / pow((id(ATMOCO2) / id(PARA)), (1./id(PARB))));
    filters:
      - sliding_window_moving_average:
          window_size: 15
          send_every: 1
    update_interval: 5s
    accuracy_decimals: 3
    unit_of_measurement: kOm
    id: r_zero

  - platform: template
    # Get the corrected resistance RZero of the sensor for calibration purposes. The corrected sensor resistance RZERO in kOhm for ATMOCO2 level
    #getCorrectedRZero
    name: "CorrectedRZero"
    lambda: |-
      return (id(corrected_resistance).state / pow((id(ATMOCO2) / id(PARA)), (1./id(PARB))));
    filters:
      - sliding_window_moving_average:
          window_size: 15
          send_every: 1
    update_interval: 5s
    accuracy_decimals: 3
    unit_of_measurement: kOm
    id: corrected_r_zero

I tried another sensor and the result is the same. :-/ Another problem I have is that I pulled the device out, left it there for about half an hour, pulled it out from Hassio CorrectedRZero, wrote to RZero in code, and reloaded into the device. For a while I had a value around 430, but now at home after about 4 hours there I have correcterd CO 60ppm.

Did you put a R = 10kohm between the Data pin and VCC pin into the DHT22 ? when I did that the temperature were corrected.

AlexBelfegor commented 3 years ago

I do not use the DHT22 sensor because it has low accuracy compared to BME

З повагою та побажанням успіхів,

Олександр Петрович Портянко


Україна, Київ, вул. Руденко, 6а, оф.630

+38 067 2-316-316

+38 044 536-4-666

E-mail: alexportyanko@gmail.com

www.inconsulting.com.ua

www.wookko.com.ua

www.el-studio.in.ua

www.isdiplom.com

ср, 3 мар. 2021 г. в 03:23, ohormazabal notifications@github.com:

You can use any humidity and temperature sensor of your choice. But its resurrection is mandatory, because the formulas provide for the adjustment of temperature and humidity. You may have a faulty sensor. The code has an adjustment for humidity, but the temperature is taken as is.

Can you please see if I'm all right? I only changed the temperature sensor to DHT.

esphome: name: co2_navstevnicky_pokoj platform: ESP8266 board: nodemcuv2

wifi: ssid: Internet home password: ""

Optional manual IP

Enable fallback hotspot (captive portal) in case wifi connection fails

ap: ssid: "co2_navstevnicky_pokoj" password: ""

captive_portal:

Enable logging

logger:

Enable Home Assistant API

api: password: ""

ota: password: "" safe_mode: True

web_server: port: 80 auth: username: admin password: ""

i2c: sda: 5 scl: 4 scan: False id: bus_a

globals:

The load resistance on the board. Value in KiloOhms

  • id: RLOAD type: float restore_value: no initial_value: '1.025'

Calibration resistance at atmospheric CO2 level. Outdoor calibration data

  • id: RZERO type: float restore_value: no initial_value: '5.175'

Atmospheric CO2 level for calibration purposes. Outdoor CO2 level during calibration. Usually 450, but it's better to clarify.

  • id: ATMOCO2 type: float restore_value: no initial_value: '450'

Parameters for calculating ppm of CO2 from sensor resistance

Exponential regression:

GAS | a | b

CO | 605.18 | -3.937

Alcohol | 77.255 | -3.18

CO2 | 110.47 | -2.862

Tolueno | 44.947 | -3.445

NH4 | 102.2 | -2.473

Acetona | 34.668 | -3.369

  • id: PARA type: float restore_value: no initial_value: '110.47'
  • id: PARB type: float restore_value: no initial_value: '-2.862'

Parameters to model temperature and humidity dependence

  • id: CORA type: float restore_value: no initial_value: '0.00035'
  • id: CORB type: float restore_value: no initial_value: '0.02718'
  • id: CORC type: float restore_value: no initial_value: '1.39538'
  • id: CORD type: float restore_value: no initial_value: '0.0018'
  • id: CORE type: float restore_value: no initial_value: '-0.003333333'
  • id: CORF type: float restore_value: no initial_value: '-0.001923077'
  • id: CORG type: float restore_value: no initial_value: '1.130128205'

Here you need to indicate the supply voltage of the MQ135 sensor. It can be measured with a voltmeter. Please note that the rated power will not always be accurate.

  • id: volt_resolution type: float restore_value: no initial_value: '5.14'

1 for Exponential, 2 for Linear

  • id: regression_method type: int restore_value: no initial_value: '1'

sensor:

  • platform: dht pin: D2 temperature: name: "Temperature dht" id: dht_temperature humidity: name: "Humidity" id: dht_humidity filters:

    • lambda: if ((id(dht_temperature).state)>=0) {return (id(dht_humidity).raw_state + (25.0 - id(dht_temperature).state) * (-0.15));} else {return id(dht_humidity).raw_state;} update_interval: 30s
  • platform: adc pin: A0 name: "Gas ADC" update_interval: 1s filters:

    • multiply: 3.3 # for NodeMcu ESP8266 v3 Lua accuracy_decimals: 0 unit_of_measurement: V id: sensor_volt
  • platform: template

    Linearization of the temperature dependency curve under and above 20 degree C

    below 20degC: fact = a t t - b t - (h - 33) d

    above 20degC: fact = a t + b h + c

    this assumes a linear dependency on humidity

    getCorrectionFactor

    name: "Correction Factor" lambda: |- if (id(dht_temperature).state<20) { return (id(CORA) id(dht_temperature).state id(dht_temperature).state - id(CORB) id(dht_temperature).state + id(CORC) - (id(dht_humidity).state - 33.) id(CORD)); } else { return (id(CORE) id(dht_temperature).state + id(CORF) id(dht_humidity).state + id(CORG)); } update_interval: 10s accuracy_decimals: 6 id: correction_factor

  • platform: template

    Get the resistance of the sensor, ie. the measurement value @return The sensor resistance in kOhm

    RS = [(VC x RL) / VRL] - RL

    RS_air = ((5.14*1.0)/sensor_volt)-1.0 Calculate RS in fresh air

    getResistance

    name: "Resistance" lambda: |- return ((id(volt_resolution)*id(RLOAD)/id(sensor_volt).state) - id(RLOAD)); update_interval: 5s accuracy_decimals: 3 unit_of_measurement: kOm id: resistance

  • platform: template

    Get the resistance of the sensor, ie. the measurement value correctedfor temp/hum @return The corrected sensor resistance kOhm

    getCorrectedResistance

    name: "Corrected Resistance" lambda: |- return (id(resistance).state / id(correction_factor).state); update_interval: 5s accuracy_decimals: 3 unit_of_measurement: kOm id: corrected_resistance

  • platform: template

    Get the ppm of CO2 sensed (assuming only CO2 in the air). The ppm of CO2 in the air

    getPPM

    name: "PPM CO2" lambda: |- if (id(regression_method)==1) { return (id(PARA) * pow((id(resistance).state / id(RZERO)), id(PARB))); } else { return (pow(10, (log10(id(resistance).state / id(RZERO)) - id(PARB)) / id(PARA))); } update_interval: 5s unit_of_measurement: ppm id: ppm_co2

  • platform: template

    Get the ppm of CO2 sensed (assuming only CO2 in the air), corrected for temp. The ppm of CO2 in the air

    getCorrectedPPM

    name: "Corrected PPM CO2" lambda: |- if (id(regression_method)==1) { return (id(PARA) * pow((id(corrected_resistance).state / id(RZERO)), id(PARB))); } else { return (pow(10, (log10(id(corrected_resistance).state / id(RZERO)) - id(PARB)) / id(PARA))); } update_interval: 5s unit_of_measurement: ppm id: corrected_ppm_co2

  • platform: template

    Get the resistance RZero of the sensor for calibration purposes. The sensor resistance RZero in kOhm

    getRZero

    name: "RZero" lambda: |- return (id(resistance).state / pow((id(ATMOCO2) / id(PARA)), (1./id(PARB)))); filters:

    • sliding_window_moving_average: window_size: 15 send_every: 1 update_interval: 5s accuracy_decimals: 3 unit_of_measurement: kOm id: r_zero
  • platform: template

    Get the corrected resistance RZero of the sensor for calibration purposes. The corrected sensor resistance RZERO in kOhm for ATMOCO2 level

    getCorrectedRZero

    name: "CorrectedRZero" lambda: |- return (id(corrected_resistance).state / pow((id(ATMOCO2) / id(PARA)), (1./id(PARB)))); filters:

    • sliding_window_moving_average: window_size: 15 send_every: 1 update_interval: 5s accuracy_decimals: 3 unit_of_measurement: kOm id: corrected_r_zero

I tried another sensor and the result is the same. :-/ Another problem I have is that I pulled the device out, left it there for about half an hour, pulled it out from Hassio CorrectedRZero, wrote to RZero in code, and reloaded into the device. For a while I had a value around 430, but now at home after about 4 hours there I have correcterd CO 60ppm.

Did you put a R = 10kohm between the Data pin and VCC pin into the DHT22 ? when I did that the temperature were corrected.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/esphome/feature-requests/issues/757#issuecomment-789352092, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACEISZDY7SRZY3HA4VSGQ53TBWFSJANCNFSM4NS65E5A .

cg089 commented 2 years ago

Hi, I'm using it on a ESP32 board with a DHT11 (which works fine), but the MQ135 values jump within seconds from factor 10: [D][sensor:113]: 'Gas ADC': Sending state 0.22250 V with 4 decimals of accuracy [D][sensor:113]: 'Corrected PPM CO2': Sending state 728.75134 ppm with 1 decimals of accuracy [D][sensor:113]: 'Corrected Resistance': Sending state 9.93926 kOm with 3 decimals of accuracy [D][sensor:113]: 'CorrectedRZero': Sending state nan kOm with 3 decimals of accuracy [D][sensor:113]: 'Resistance': Sending state 22.00890 kOm with 3 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.12V [D][sensor:113]: 'Gas ADC': Sending state 0.40865 V with 4 decimals of accuracy [D][sensor:113]: 'PPM CO2': Sending state 31313.85547 ppm with 1 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.02V [D][sensor:113]: 'Gas ADC': Sending state 0.05939 V with 4 decimals of accuracy [D][sensor:113]: 'RZero': Sending state nan kOm with 3 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.02V [D][sensor:113]: 'Gas ADC': Sending state 0.07092 V with 4 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.00V [D][sensor:113]: 'Gas ADC': Sending state 0.00000 V with 4 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.02V [D][sensor:113]: 'Gas ADC': Sending state 0.07978 V with 4 decimals of accuracy [D][sensor:113]: 'Corrected PPM CO2': Sending state 304666.81250 ppm with 1 decimals of accuracy [D][sensor:113]: 'Corrected Resistance': Sending state 18.90541 kOm with 3 decimals of accuracy [D][sensor:113]: 'CorrectedRZero': Sending state nan kOm with 3 decimals of accuracy [D][sensor:113]: 'Resistance': Sending state 63.21398 kOm with 3 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.00V [D][sensor:113]: 'Gas ADC': Sending state 0.00000 V with 4 decimals of accuracy [D][sensor:113]: 'PPM CO2': Sending state 1528.71204 ppm with 1 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.01V [D][sensor:113]: 'Gas ADC': Sending state 0.03989 V with 4 decimals of accuracy [D][sensor:113]: 'RZero': Sending state nan kOm with 3 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.00V [D][sensor:113]: 'Gas ADC': Sending state 0.00000 V with 4 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.01V [D][sensor:113]: 'Gas ADC': Sending state 0.01684 V with 4 decimals of accuracy [D][sensor:113]: 'Correction Factor': Sending state 1.16416 with 6 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.02V [D][sensor:113]: 'Gas ADC': Sending state 0.05053 V with 4 decimals of accuracy [D][sensor:113]: 'Corrected PPM CO2': Sending state 48379.72266 ppm with 1 decimals of accuracy [D][sensor:113]: 'Corrected Resistance': Sending state 54.30015 kOm with 3 decimals of accuracy [D][sensor:113]: 'CorrectedRZero': Sending state nan kOm with 3 decimals of accuracy [D][sensor:113]: 'Resistance': Sending state 100.40497 kOm with 3 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.00V [D][sensor:113]: 'Gas ADC': Sending state 0.00000 V with 4 decimals of accuracy [D][sensor:113]: 'PPM CO2': Sending state 406.65823 ppm with 1 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.00V [D][sensor:113]: 'Gas ADC': Sending state 0.01507 V with 4 decimals of accuracy [D][sensor:113]: 'RZero': Sending state nan kOm with 3 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.02V [D][sensor:113]: 'Gas ADC': Sending state 0.05673 V with 4 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.02V [D][sensor:113]: 'Gas ADC': Sending state 0.05939 V with 4 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.02V [D][sensor:113]: 'Gas ADC': Sending state 0.05141 V with 4 decimals of accuracy [D][sensor:113]: 'Corrected PPM CO2': Sending state 2361.85083 ppm with 1 decimals of accuracy [D][sensor:113]: 'Corrected Resistance': Sending state 86.24681 kOm with 3 decimals of accuracy [D][sensor:113]: 'CorrectedRZero': Sending state nan kOm with 3 decimals of accuracy [D][sensor:113]: 'Resistance': Sending state 98.65617 kOm with 3 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.00V [D][sensor:113]: 'Gas ADC': Sending state 0.00177 V with 4 decimals of accuracy [D][sensor:113]: 'PPM CO2': Sending state 427.63104 ppm with 1 decimals of accuracy [D][adc:109]: 'Gas ADC': Got voltage=0.08V [D][sensor:113]: 'Gas ADC': Sending state 0.26948 V with 4 decimals of accuracy [D][sensor:113]: 'RZero': Sending state nan kOm with 3 decimals of accuracy

Any ideas on that one?

viotemp1 commented 2 years ago

Here is a custom sensor using MQUnifiedsensor git-esphome-MQUnifiedsensor

Still more work to be done, but it's a start