├── 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 |
--------------------------------------------------------------------------------