Measuring CO2/Temp/RH/Pressure with ESP8266 version 2

By Atomstar on Sunday 3 January 2021 12:21 - Comments (8)
Categories: ESP8266, Smarthome, Views: 6.007

After experimenting a bit, I've made a new iteration of my ESP8266 sensor board, which now sports a PCB design (thanks all fellow Tweakers on GoT!). Some improvements:
  • More compact & uncluttered thanks to PCB
  • Added one (optionally more distant) temperature sensor to prevent self-heating
  • Added deep-sleep cycle to alternatively mitigate self-heating


Update 20210207: made voltage regulator for BME280 requirement more explicit (thanks @ManS-H!)

Introduction

For this project, I had the same goals as before, and wanted to optimise the design.

This guide assumes you've read the previous guide, so this article skips the basics such as installing esphome etc.

Bill of materials

  1. Special-built SensorThing mk2 PCB -- 5 euros with same-day shipping!
  2. ESP8266 WeMos D1 mini (optionally pro)
  3. Winsen MH-Z19B CO2 sensor
  4. Optional: 1.3" I2C OLED screen (for displaying values live)
  5. BME280 module with level converter - N.B. ensure you have a BME280 module that accepts 5V to use my print!
  6. DS18B20 temperature sensor
  7. Male pin headers straight (for modules)
  8. Optional: Micro usb dip adapter/module (for bottom-side power supply, else use Wemos USB port directly)
  9. Optional: Male pin headers 90 degrees (for USB micro module)
  10. Optional: Dupont female-female jumper wires (to increase distance of DS18B20)
Since I power everything on 5V and the BME280 only accepts 1.7-3.6V as input voltage, ensure you get a BME280 module with voltage regulator, e.g. the one linked above. It should explicitly note that input voltage can be either 3.3V or 5V.

Bill of process

Software integration
Install esphome as documented here.
Hardware integration
Collect all parts
https://tweakers.net/i/vb09Pe3ivqPGbeV4UWGXkMip4R8=/100x75/filters:strip_icc():strip_exif()/f/image/6EbIUxzIpFDSnMxpbPG2RnAO.jpg?f=fotoalbum_smallhttps://tweakers.net/i/tKXH_2BMRha47IAewf3r-H15i1I=/100x75/filters:strip_icc():strip_exif()/f/image/SBn8Q97YTtpNqnLHWch5kHPT.jpg?f=fotoalbum_smallhttps://tweakers.net/i/IduZxlI30dSOG5DJHnGsjRu6Tn4=/100x75/filters:strip_icc():strip_exif()/f/image/dTeTShK0Q9QZ2amG8oPoN99d.jpg?f=fotoalbum_small

Solder male header pins onto PCB (1) for D1 mini (2), MH-Z19B (3), and OLED (4). For the MH-Z19B you can save a few headers by only connecting the necessary VCC, GND, RX and TX pins. (You could also only solder used pins for the D1 mini but I chose to connect all so I can optionally connect additional stuff via jumper wires).
https://tweakers.net/i/dONvdSgevjDnKaeWv50yhrtMMSc=/100x75/filters:strip_icc():strip_exif()/f/image/nBQ8FlRnukqhyNfyy7ZGS8Er.jpg?f=fotoalbum_smallhttps://tweakers.net/i/X_cKMswA1LpEeiaE7pXeNRSD9iI=/100x75/filters:strip_icc():strip_exif()/f/image/W82sLxGdXuIBYtHJs9Pnlwe0.jpg?f=fotoalbum_small

For the temperature sensors BME280 (5) and DS18B20 (6), decide what mounting option you want (see above), and either connect male header pins or female header pins to the PCB. In this example I connected BME280 using male pin headers, and the DS18B20 using female pin headers.
https://tweakers.net/i/NludVtFgCSpMhUHslo-R9zwj1Wg=/100x75/filters:strip_icc():strip_exif()/f/image/Luj4EsyCm4mOG0m6bVosDAEn.jpg?f=fotoalbum_smallhttps://tweakers.net/i/ujZmb5kXXNYE_z7yrnZu1ieCEKs=/100x75/filters:strip_icc():strip_exif()/f/image/8kWNi1IicxSmGfpKLsmg5xVY.jpg?f=fotoalbum_small

To power the board, you can either A] solder male headers in the USB pins, and connect them with jumper wires directly, or B] solder the micro-USB dip connector to the PCB.

For A], simply solder extra male header pins which you can connect jumper wires to later. N.B. GND is left and VCC is the right pin. (B] continues below):
https://tweakers.net/i/zyYCHYP-lAkqTiakU_cLGExvkc4=/100x75/filters:strip_icc():strip_exif()/f/image/hwfXRifCNviVhqOiARY4pRz4.jpg?f=fotoalbum_smallhttps://tweakers.net/i/_DMRgmbYArmZbd5JxJfkZkyJWB8=/100x75/filters:strip_icc():strip_exif()/f/image/6kacpfUd8QiutwKtZPr7KazL.jpg?f=fotoalbum_small

Next, connect the modules (note in these pictures I chose for powering via male header pins, i.e. A])
https://tweakers.net/i/ylqdNKd0cwO5AlMFdyAeiALSI3I=/100x75/filters:strip_icc():strip_exif()/f/image/4jvnrZW6V9nidqGwc3xkGCax.jpg?f=fotoalbum_smallhttps://tweakers.net/i/bLPNxln6UYoTIlwHP84avvcRNa8=/100x75/filters:strip_icc():strip_exif()/f/image/YIiKzBu9QZOuQIzeXLkojKg1.jpg?f=fotoalbum_smallhttps://tweakers.net/i/bHljnXd1EF-yIlOHhRPyAFL7lUI=/100x75/filters:strip_icc():strip_exif()/f/image/tYlXqVB3xPPsLfFQEcHRS61U.jpg?f=fotoalbum_smallhttps://tweakers.net/i/GSJNCZ7f6POs7gamWrNS5LPtF7I=/100x75/filters:strip_icc():strip_exif()/f/image/A1SJaiPwoY1YpcHkaiDqHVc6.jpg?f=fotoalbum_smallhttps://tweakers.net/i/hoqRmyC4Hg8u1he1lZ-ln4fVRVo=/100x75/filters:strip_icc():strip_exif()/f/image/4U1GY5eJieLAjEH0qpfvwanC.jpg?f=fotoalbum_small

For B], solder 90 degree headers onto USB micro dip. Ensure that the pins do not protrude through the module pcb, else they might touch the MH-Z19B module. Only the outer pins (VCC and GND) matter.
https://tweakers.net/i/QfI5dwdYVu8r8SXJxhqay9pVURg=/100x75/filters:strip_icc():strip_exif()/f/image/8z4HHiMdm5N2zC1daTepDcid.jpg?f=fotoalbum_smallhttps://tweakers.net/i/0Pg6sALFWn1l03w4z5Iqe4UIAio=/100x75/filters:strip_icc():strip_exif()/f/image/9ledHfV1sQetgfigkOiCjSwG.jpg?f=fotoalbum_smallhttps://tweakers.net/i/b9uApATGa9t7_NFlEzQrGQAdy1Y=/100x75/filters:strip_icc():strip_exif()/f/image/jpMEcpVLvo5lhd4x0sdBEbpP.jpg?f=fotoalbum_smallhttps://tweakers.net/i/VhG401rbFDrh7qzxfAaJhO509gY=/100x75/filters:strip_icc():strip_exif()/f/image/N2wmNjofwKpnJIZU9rhO97SG.jpg?f=fotoalbum_small

Then solder the Micro USB dip module onto PCB, which doubles as a stand.
https://tweakers.net/i/RXPFIJKji54WjpLxHbTg_BTn2cs=/100x75/filters:strip_icc():strip_exif()/f/image/1jrTe9pWmn1mF4KMFv8VNw0o.jpg?f=fotoalbum_smallhttps://tweakers.net/i/gb79XzKBGq_62shhBeDFGgln39g=/100x75/filters:strip_icc():strip_exif()/f/image/JZA8zzEyr1UCdRjndCPJIvn8.jpg?f=fotoalbum_small
Software configuration
This esphome configuration is very similar to my previous project, with some tweaks:
  • Added Dallas DS18B20 sensor code
  • Re-enable home assistant api for logging over wifi
  • Disable web server to reduce resource usage and since it's not necessary
  • Optionally use deep sleep loop
YAML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
esphome:
  name: esp_test_board
  platform: ESP8266
  board: d1_mini_pro

wifi:
  ssid: "your wifi SSID"
  password: "your wifi password"
  #fast_connect: True # Required to connect to hidden SSIDs and only with one network
  domain: ".lan"

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esp Living Fallback Hotspot"
    password: "your fallback password"

captive_portal:

# Enable logging
logger:
  # Disable UART Logging to fix MHZ-19B preamble issue when using hardware UART, see https://github.com/esphome/issues/issues/488
  # Not strictly necessary anymore with 1.14.0 https://github.com/esphome/esphome/releases/tag/v1.14.0
  # baud_rate: 0

# Enable Home Assistant API for logging over wifi.
# Disable reboot loop by setting reboot_timeout to 0s!
# See warning on https://esphome.io/components/mqtt.html
api:
  reboot_timeout: 0s

# Disable webserver, since we push data over mqtt. Can be useful for 
# diagnostics, but takes up quite some memory
# web_server:
#   port: 80

# Optionally use deep sleep loop to reduce power consumption/self-heating.
# deep_sleep:
#   run_duration: 30s
#   sleep_duration: 150s

# Allow OTA updates
ota:

# For MH-Z19B CO2 via software serial
uart:
  - id: myuart1 
    rx_pin: GPIO12
    tx_pin: GPIO13
    baud_rate: 9600

# For BME280
i2c:
  sda: GPIO4
  scl: GPIO5
  scan: True

# For Dallas temp sensors connected to pin GPIO0 = D3, enable internal pull-up
# resistor
dallas:
  id: ds18b20_temp_sensor
  pin:
    number: GPIO0
    # inverted: True
    mode: INPUT_PULLUP
  update_interval: 30s


# Ensure you get *ttf files from somewhere
font:
  - file: "slkscr.ttf"
    id: my_font1
    size: 8
  - file: "slkscr.ttf"
    id: my_font2
    size: 16
  - file: "Arial.ttf"
    id: my_font3
    size: 16

mqtt:
  # For mobile = WAN : use FQDN, for local (IoT network - no WAN), use home IP.
  broker: "192.168.0.1"
  #broker: home.yourhostname.org
  port: 1883
  username: "esp_board_client"
  password: "AQFCg72z5MqFihspHGbkqOj9"

sensor:
  - platform: wifi_signal
    name: "WiFi Signal"
    update_interval: 10s
    id: mywifi1
  - platform: wifi_signal
    name: "WiFi Signal2"
    update_interval: 10s
    filters:
    - exponential_moving_average:
        alpha: 0.001 # We want ~6 hour averaging, at 10s update, that's 6*3600/10 = 2160 points, thus alpha should be 2/2160 ~ 0.001 
        send_every: 1
    id: mywifi2    
  - platform: dallas
    index: 0
    name: "DS18B20 Temperature"
    state_topic: influx/environv3/quantity/T/source/dallas1/board/esp_test_board/location/home/room/living/value/state
    id: ds18b20_temp
  - platform: mhz19
    co2:
      name: "MH-Z19 CO2"
      state_topic: influx/environv3/quantity/CO2/source/mhz19b/board/esp_test_board/location/home/room/living/value/state
      id: mhz_19_co2
    temperature:
      name: "MH-Z19 Temperature"
      state_topic: influx/environv3/quantity/T/source/mhz19b/board/esp_test_board/location/home/room/living/value/state
      id: mhz_19_T
    update_interval: 20s
    uart_id: myuart1
  - platform: mhz19
    co2:
      name: "MH-Z19 CO2"
      id: mhz_19_co2_ema
      filters:
      - exponential_moving_average:
          alpha: 0.001 # We want ~12 hour averaging, at 20s update, that's 12*3600/20 = 2160 points, thus alpha should be 2/2160 ~ 0.001 
          send_every: 1
    temperature:
      name: "MH-Z19 Temperature"
      id: mhz_19_T_ema
      filters:
      - exponential_moving_average:
          alpha: 0.001 # We want ~12 hour averaging, at 20s update, that's 12*3600/20 = 2160 points, thus alpha should be 2/2160 ~ 0.001 
          send_every: 1
    update_interval: 20s # if changed also update alpha
    uart_id: myuart1
  - platform: bme280
    temperature:
      name: "BME280 Temperature"
      oversampling: 16x
      id: bme_280_temp
      state_topic: influx/environv3/quantity/T/source/bme280/board/esp_test_board/location/home/room/living/value/state
    pressure:
      name: "BME280 Pressure"
      id: bme_280_press
      state_topic: influx/environv3/quantity/P/source/bme280/board/esp_test_board/location/home/room/living/value/state
    humidity:
      name: "BME280 Humidity"
      id: bme_280_rh
      state_topic: influx/environv3/quantity/RH/source/bme280/board/esp_test_board/location/home/room/living/value/state
    address: 0x76
    update_interval: 30s
  - platform: bme280
    temperature:
      name: "BME280 Temperature"
      oversampling: 16x
      id: bme_280_temp_ema
      filters:
      - exponential_moving_average:
          alpha: 0.001 # We want ~12 hour averaging, at 20s update, that's 12*3600/20 = 2160 points, thus alpha should be 2/2160 ~ 0.001 
          send_every: 1
    pressure:
      name: "BME280 Pressure"
      id: bme_280_press_ema
      filters:
      - exponential_moving_average:
          alpha: 0.0002 # We want ~48 hour averaging, at 20s update, that's 48*3600/20 = 8640 points, thus alpha should be 2/8640 ~ 0.0002 
          send_every: 1
    humidity:
      name: "BME280 Humidity"
      id: bme_280_rh_ema
      filters:
      - exponential_moving_average:
          alpha: 0.001 # We want ~12 hour averaging, at 20s update, that's 12*3600/20 = 2160 points, thus alpha should be 2/2160 ~ 0.001 
          send_every: 1
    address: 0x76
    update_interval: 20s # if you change this don't forget to update alpha

display:
  - platform: ssd1306_i2c
    model: "SH1106 128x64"
    address: 0x3C
    lambda: |-
      it.printf(0,  2, id(my_font1), "CO2");
      it.printf(0,  10, id(my_font1), "PPM");
      it.printf(24, 6, id(my_font3), "%d (%d)", int(id(mhz_19_co2).state), int(id(mhz_19_co2_ema).state));
      
      it.printf(0, 18, id(my_font1), "T");
      it.printf(0,  26, id(my_font1), "C");
      it.printf(24, 22, id(my_font3), "%.1f (%.1f)", id(bme_280_temp).state, id(bme_280_temp_ema).state);
      
      it.printf(0, 34, id(my_font1), "RH");
      it.printf(0,  42, id(my_font1), "%%");
      it.printf(24, 38, id(my_font3), "%.1f (%.1f)", (id(bme_280_rh).state), (id(bme_280_rh_ema).state));
      
      it.printf(0, 50, id(my_font1), "P");
      it.printf(0, 58, id(my_font1), "HPa");
      it.printf(24, 54, id(my_font3), "%d (%d)", int(id(bme_280_press).state), int(id(bme_280_press_ema).state));

Temperature calibration

The 'closed' box of the previous design reported higher temperatures than the room really was, and it appeared I underestimated the heat generation of the ESP8266 SoC. To solve this, I compared self-heating in different design (variations).

Preliminary conclusions: The PCB design without OLED and the D1 mini (non-pro), (which I called 'esp_kidsroom') seems to give the best results. The 'closed' box ('esp_bathroom') gives the worst results. Adding (arguably) ugly wires to increase distance always helps. Deep sleep helps. Turning off the OLED helps a little bit. The Wemos D1 mini seems cooler than the D1 mini pro.



Looking at each design in detail:

esp_bathroom:


esp_bedroom:


esp_kidsroom:


esp_living:


I will expand this section once I have more time for analysis/digestion of results.

Future work

  • Try to measure, model, and calibrate self-heating
  • Use direct ESP8266 chips instead of modules for more compact design.
  • Perhaps just give up and buy 10 euro wireless temperature sensors 😬

Volgende: Particulates kill, build your sensor now! 28-04 Particulates kill, build your sensor now!
Volgende: Reading out Kamstrup Multical 402/403 with home-built optical head 11-'20 Reading out Kamstrup Multical 402/403 with home-built optical head

Comments


By Tweakers user DJ-Promo, Monday 4 January 2021 11:23

Mooie PCB! Ga even kijken welke onderdelen ik nog allemaal heb liggen hier.
Denk dat er een PCB deze kant op moet gaan komen :) .

By Tweakers user Rips10, Monday 4 January 2021 23:13

Leuk om te lezen, gaaf project!

By cavey, Wednesday 13 January 2021 12:03

Why would you use a BME280 in conjunction with a DS18B20? The DS18 seems superfluous to me, as the BME280 combines three-in-one, and has a slight edge over the DS18B20 in measurement precision/stability.

By Tweakers user Atomstar, Monday 18 January 2021 12:06

cavey wrote on Wednesday 13 January 2021 @ 12:03:
Why would you use a BME280 in conjunction with a DS18B20? The DS18 seems superfluous to me, as the BME280 combines three-in-one, and has a slight edge over the DS18B20 in measurement precision/stability.
I think the DS18B20 has slightly better temp sensitivity, and since I’m having some issues with self heating I was hoping one of the two would perform better. In an ideal world one is sufficient indeed ;)

By Tweakers user wibra, Sunday 31 January 2021 22:03

Once you're this far, why not also detect VOCs and particles?

By Simon, Monday 1 February 2021 08:08

Zeer cool! Thuis heb ik exact dezelfde sensoren alleen nog niet zo
Netjes bij elkaar gestopt. Ik heb ook een ESP8266 met de PMS5003 fijnstof sensor. Dat is ook een zeer nuttige meting voor de luchtkwaliteit. Vooral in de huiskamer na een kooksessie. Ik heb ook een BME680 hangen maar die VOC waarde is all over the place (zonder aantoonbare grote wijzigingen). Dus daar hecht ik niet veel waarde aan.

Binnenkort ga ik mijn eigen 3D doosjes pinten om het geheel netjes in weg te werken. Misschien gebruik ik wel zo’n printje van jou.
Maar heating is dus een probleem voor de temperatuur. Misschien met een doosjes er omheen waarbij de temperatuur sensor een stukje uitsteekt?

Trouwens, na een aantal jaar de OLED aan gehad hebbende, branden de lesjes wel in.
Ik heb dit opgelost door in ESPHome de positie van de letters na x seconde aan te passen zodat ze precies een regel pixels in x en y verschuiven.

Succes met het project!

By Kerel, Monday 1 February 2021 08:32

Interesting project! How do you plan on calibrating the MH-Z19?

By Tweakers user Atomstar, Monday 1 February 2021 09:45

wibra wrote on Sunday 31 January 2021 @ 22:03:
Once you're this far, why not also detect VOCs and particles?
Almost there, just not on a pcb or documented yet. Stay tuned :)
Simon wrote on Monday 1 February 2021 @ 08:08:

Binnenkort ga ik mijn eigen 3D doosjes pinten om het geheel netjes in weg te werken. Misschien gebruik ik wel zo’n printje van jou.
Maar heating is dus een probleem voor de temperatuur. Misschien met een doosjes er omheen waarbij de temperatuur sensor een stukje uitsteekt?

Trouwens, na een aantal jaar de OLED aan gehad hebbende, branden de lesjes wel in.
Ik heb dit opgelost door in ESPHome de positie van de letters na x seconde aan te passen zodat ze precies een regel pixels in x en y verschuiven.

Succes met het project!
VOC (met CCS811) werkte bij mij ook niet heel goed, dus daarom ook CO2 genomen. Fijnstof staat op de lijst. Als je een case print dan zeker je temperatuursensor uit laten steken, anders zit je zo 3-4 graden hoger. OLED burn-in is een goed punt, maar ik heb die van mij al 3x omgesoldeerd en daarbij de flatcable soms geraakt dus er zitten al strepen op :p
Kerel wrote on Monday 1 February 2021 @ 08:32:
Interesting project! How do you plan on calibrating the MH-Z19?
Thanks! The MH-Z19B is self-calibrating: it sets the zero-point (400 ppm) to the lowest value measured in the last 24h. So if you open your windows in the morning the calibration is solved :) Opening the windows is also good if you're not calibrating any CO2 sensors ;)

[Comment edited on Monday 1 February 2021 09:46]


Comments are closed