├── README.md ├── LICENSE └── isl_climatestatio.yaml /README.md: -------------------------------------------------------------------------------- 1 | # esphome-mq135 2 | Yaml code for MQ135 sensor
3 | 1. Download the firmware with the file.
4 | 2. Obtain the CorrectedRZero values on the street.
5 | 3. Change the constants RZERO and ATMOCO2.
6 | 4. Download the firmware again.
7 | 8 | htu21d for Humidity
9 | Any other temperature and humidity sensors can be used. 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Alex 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /isl_climatestatio.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: isl_climatestatio 3 | platform: ESP8266 4 | board: nodemcuv2 5 | 6 | wifi: 7 | ssid: !secret ssid 8 | password: !secret wifi_password 9 | 10 | # Optional manual IP 11 | manual_ip: 12 | static_ip: 192.x.x.x 13 | gateway: 192.x.x.1 14 | dns1: 192.x.x.1 15 | dns2: 8.8.8.8 16 | subnet: 255.255.255.0 17 | 18 | # Enable fallback hotspot (captive portal) in case wifi connection fails 19 | ap: 20 | ssid: "Isl Climatestatio 10" 21 | password: "" 22 | 23 | captive_portal: 24 | 25 | # Enable logging 26 | logger: 27 | 28 | # Enable Home Assistant API 29 | api: 30 | password: !secret api_password 31 | 32 | ota: 33 | password: !secret ota_password 34 | safe_mode: True 35 | 36 | web_server: 37 | port: 80 38 | auth: 39 | username: admin 40 | password: !secret web_server_password 41 | 42 | i2c: 43 | sda: 5 44 | scl: 4 45 | scan: False 46 | id: bus_a 47 | 48 | globals: 49 | 50 | #The load resistance on the board. Value in KiloOhms 51 | - id: RLOAD 52 | type: float 53 | restore_value: no 54 | initial_value: '1.025' 55 | 56 | #Calibration resistance at atmospheric CO2 level. Outdoor calibration data 57 | - id: RZERO 58 | type: float 59 | restore_value: no 60 | initial_value: '35.429' 61 | 62 | #Atmospheric CO2 level for calibration purposes. Outdoor CO2 level during calibration. Usually 450, but it's better to clarify. 63 | - id: ATMOCO2 64 | type: float 65 | restore_value: no 66 | initial_value: '450' 67 | 68 | #Parameters for calculating ppm of CO2 from sensor resistance 69 | # Exponential regression: 70 | # GAS | a | b 71 | # CO | 605.18 | -3.937 72 | # Alcohol | 77.255 | -3.18 73 | # CO2 | 110.47 | -2.862 74 | # Tolueno | 44.947 | -3.445 75 | # NH4 | 102.2 | -2.473 76 | # Acetona | 34.668 | -3.369 77 | - id: PARA 78 | type: float 79 | restore_value: no 80 | initial_value: '110.47' 81 | - id: PARB 82 | type: float 83 | restore_value: no 84 | initial_value: '-2.862' 85 | 86 | #Parameters to model temperature and humidity dependence 87 | - id: CORA 88 | type: float 89 | restore_value: no 90 | initial_value: '0.00035' 91 | - id: CORB 92 | type: float 93 | restore_value: no 94 | initial_value: '0.02718' 95 | - id: CORC 96 | type: float 97 | restore_value: no 98 | initial_value: '1.39538' 99 | - id: CORD 100 | type: float 101 | restore_value: no 102 | initial_value: '0.0018' 103 | - id: CORE 104 | type: float 105 | restore_value: no 106 | initial_value: '-0.003333333' 107 | - id: CORF 108 | type: float 109 | restore_value: no 110 | initial_value: '-0.001923077' 111 | - id: CORG 112 | type: float 113 | restore_value: no 114 | initial_value: '1.130128205' 115 | 116 | # 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. 117 | - id: volt_resolution 118 | type: float 119 | restore_value: no 120 | initial_value: '5.14' 121 | 122 | # 1 for Exponential, 2 for Linear 123 | - id: regression_method 124 | type: int 125 | restore_value: no 126 | initial_value: '1' 127 | 128 | sensor: 129 | - platform: htu21d 130 | temperature: 131 | name: "Temperature htu21d" 132 | id: htu21d_temperature 133 | humidity: 134 | name: "Humidity" 135 | id: htu21d_humidity 136 | filters: 137 | - lambda: if ((id(htu21d_temperature).state)>=0) {return (id(htu21d_humidity).raw_state + (25.0 - id(htu21d_temperature).state) * (-0.15));} else {return id(htu21d_humidity).raw_state;} 138 | update_interval: 30s 139 | 140 | - platform: adc 141 | pin: A0 142 | name: "Gas ADC" 143 | update_interval: 1s 144 | filters: 145 | - multiply: 3.3 # for NodeMcu ESP8266 v3 Lua 146 | accuracy_decimals: 4 147 | unit_of_measurement: V 148 | id: sensor_volt 149 | 150 | - platform: template 151 | #Linearization of the temperature dependency curve under and above 20 degree C 152 | #below 20degC: fact = a * t * t - b * t - (h - 33) * d 153 | #above 20degC: fact = a * t + b * h + c 154 | #this assumes a linear dependency on humidity 155 | #getCorrectionFactor 156 | name: "Correction Factor" 157 | lambda: |- 158 | if (id(htu21d_temperature).state<20) { 159 | return (id(CORA) * id(htu21d_temperature).state * id(htu21d_temperature).state - id(CORB) * 160 | id(htu21d_temperature).state + id(CORC) - (id(htu21d_humidity).state - 33.) * id(CORD)); 161 | } else { 162 | return (id(CORE) * id(htu21d_temperature).state + id(CORF) * id(htu21d_humidity).state + id(CORG)); 163 | } 164 | update_interval: 10s 165 | accuracy_decimals: 6 166 | id: correction_factor 167 | 168 | - platform: template 169 | #Get the resistance of the sensor, ie. the measurement value @return The sensor resistance in kOhm 170 | # RS = [(VC x RL) / VRL] - RL 171 | # RS_air = ((5.14*1.0)/sensor_volt)-1.0 Calculate RS in fresh air 172 | #getResistance 173 | name: "Resistance" 174 | lambda: |- 175 | return ((id(volt_resolution)*id(RLOAD)/id(sensor_volt).state) - id(RLOAD)); 176 | update_interval: 5s 177 | accuracy_decimals: 3 178 | unit_of_measurement: kOm 179 | id: resistance 180 | 181 | - platform: template 182 | # Get the resistance of the sensor, ie. the measurement value correctedfor temp/hum @return The corrected sensor resistance kOhm 183 | #getCorrectedResistance 184 | name: "Corrected Resistance" 185 | lambda: |- 186 | return (id(resistance).state / id(correction_factor).state); 187 | update_interval: 5s 188 | accuracy_decimals: 3 189 | unit_of_measurement: kOm 190 | id: corrected_resistance 191 | 192 | - platform: template 193 | # Get the ppm of CO2 sensed (assuming only CO2 in the air). The ppm of CO2 in the air 194 | #getPPM 195 | name: "PPM CO2" 196 | lambda: |- 197 | if (id(regression_method)==1) { 198 | return (id(PARA) * pow((id(resistance).state / id(RZERO)), id(PARB))); 199 | } else { 200 | return (pow(10, (log10(id(resistance).state / id(RZERO)) - id(PARB)) / id(PARA))); 201 | } 202 | update_interval: 5s 203 | unit_of_measurement: ppm 204 | id: ppm_co2 205 | 206 | - platform: template 207 | # Get the ppm of CO2 sensed (assuming only CO2 in the air), corrected for temp. The ppm of CO2 in the air 208 | #getCorrectedPPM 209 | name: "Corrected PPM CO2" 210 | lambda: |- 211 | if (id(regression_method)==1) { 212 | return (id(PARA) * pow((id(corrected_resistance).state / id(RZERO)), id(PARB))); 213 | } else { 214 | return (pow(10, (log10(id(corrected_resistance).state / id(RZERO)) - id(PARB)) / id(PARA))); 215 | } 216 | update_interval: 5s 217 | unit_of_measurement: ppm 218 | id: corrected_ppm_co2 219 | 220 | - platform: template 221 | # Get the resistance RZero of the sensor for calibration purposes. The sensor resistance RZero in kOhm 222 | #getRZero 223 | name: "RZero" 224 | lambda: |- 225 | return (id(resistance).state / pow((id(ATMOCO2) / id(PARA)), (1./id(PARB)))); 226 | filters: 227 | - sliding_window_moving_average: 228 | window_size: 15 229 | send_every: 1 230 | update_interval: 5s 231 | accuracy_decimals: 3 232 | unit_of_measurement: kOm 233 | id: r_zero 234 | 235 | - platform: template 236 | # Get the corrected resistance RZero of the sensor for calibration purposes. The corrected sensor resistance RZERO in kOhm for ATMOCO2 level 237 | #getCorrectedRZero 238 | name: "CorrectedRZero" 239 | lambda: |- 240 | return (id(corrected_resistance).state / pow((id(ATMOCO2) / id(PARA)), (1./id(PARB)))); 241 | filters: 242 | - sliding_window_moving_average: 243 | window_size: 15 244 | send_every: 1 245 | update_interval: 5s 246 | accuracy_decimals: 3 247 | unit_of_measurement: kOm 248 | id: corrected_r_zero 249 | --------------------------------------------------------------------------------