Ad

Sunday, March 22, 2020

Tasmota-based multi-channel air quality sensor station


The sense of smell is an amazing function in vertebrate animals. Even the human nose, which is not particularly notable in comparison with other animals, is fascinating in its sensitivity to trace amounts of a large variety of substances. It has a level of selectivity and capability of distinguishing between different kinds of smells, which is very difficult to match by even the most sophisticated artificial sensors.

Having as the main motivation the enrichment of the IoT gadgetry sitting around in my house (and eventually fill up an entire 192.168.1.1/24 network address range), I found that (after the motion and entrance detection device), an interesting device to invest time on would be something capable of sensing multiple air quality parameters at the same time.


While not trying to challenge the biological supremacy of the nose in this respect, my idea was to pack a number of different state-of-the-art air analysis sensors into a relatively compact module that could be placed in a location where air quality related hazards would have more probability of occuring, and as such where monitoring would be of greater interest.

In a regular house as mine, the most obvious location is the kitchen, given the proximity to air quality impacting sources. Most notably, the natural gas (methane) used to power the stove and water heater is present in the respective piping. The burning of this fuel (by the stove and water heater) places the risk (if proper ventilation does not take place) of carbon monoxide (CO) build-up. As you may know, the later is produced during the combustion of hydrocarbons, and its proportion is greater when the combustion is richer and outside the stoichiometric sweet spot of a particular fuel.


The worst thing about this gas, is that in spite of its high toxicity, our fenomenal nose is totally unable to sense its presence. Also its effects are difficult to anticipate by the subject, as in a high concentration environment, one may lose consciousness before having time to react. Once absorbed by the organism, the CO gas restricts the blood's ability to carry oxygen, depriving the cells of the body from this fundamental substance to its functioning.

As such, one of my main priorities was to add the ability to detect this gas, as a undetected ventilation problem in the water heater exhaust could easily promote build-up in the kitchen, originating an invisible danger to its occupants.

Also, it doesn't take a very high concentration of CO gas, for it to be harmful or even life threatening to an individual. Theoretically the exposure to 400 ppm of this gas for at least 3 hours may prove fatal to an average human.

Another gas that can occur at home is methane, commonly referred to as natural gas (CH4).  Monitoring it could also be important to perform, not so much for its toxicity (compared to the 400 ppm of the CO gas, it takes about 500 000 ppm of CH4 concentration for it to actually be harmful to the human organism - this happens mostly due to the oxygen displacement that it causes, than because of direct impact with the metabolism). To put this into perspective, this concentration is so high (50%) that is well above its upper flammability limit (UFL), which is 15%. So, the bottom line is that asphyxiation is the least of the worries regarding this gas.

The main purpose of detecting methane is therefore because of its flammability. A lean concentration of about 8% methane could produce a violent explosion in the presence of a source of ignition.

As such I did a research on the different types of sensors available in the market, and analysed the more mainstream ones, for their capabilities.

One of the challenges of detecting these gases, is the selectivity of the sensor device. While the most common sensors may be sensitive at detecting small emissions of the gases of interest, they will also pickup different types of gases without being able to distinguish between these.

Detecting Carbon Monoxide

For detecting Carbon Monoxide, I have selected the very common MQ-7 sensor. Like other sensors in the MQ series, it is based on a tin dioxide semiconductor that once heated, becomes sensitive to the CO gas. According to the manufacturer datasheet these are the materials that compose the sensor:


This sensor is widely available and sells for a reasonably low price:




The sensor provides an analog output, and as with the other MQ-series sensors, it incorporates an LM393 comparator, outputting a digital signal when the detection is above a threshold adjusted by the on-board potentiometer. In words this seems simple, but the reality is that this particular sensor requires an operation cycle that is not possible to implement with the circuit it this PCB. So if one buys the sensor in the board like the one shown above, modifications to this board (or the removal of the bare sensor and placement in another circuit) are unavoidable for correct operation.

The board manufacturer have chosen to use the same PCB design on every MQ-series board, not accounting for the nuances of this particular sensor.

While the sensor is more sensitive to CO gas, in requires a specific thermal cycle, in order to clean itself up from the build up of VOCs that will interfere with the CO detection:


This cycle consists of running the heater in full blast (at 5 Volts) for 60 seconds. During this period, measurements cannot be taken from the sensor, since the signal does not reflect CO detection. Afterwards, the heater must be operated at 1.4 Volts for 90 seconds. During this period the measurements are considered valid.


As the PCB circuit has the heater element always connected to the 5 Volts, it is not possible to control the thermal cycle required for normal operation.

As such, for obtaining a usable sensor, one must either modify the PCB, or remove the bare sensor and put it on another PCB.

I went for the first approach, as desoldering the sensor could be a pain. In this photo, the modified sensor can be seen, side by side with the MQ-4 methane detection sensor:


The modification consists of: i) removing the permanent connection between the heater element and the positive rail; ii) control the sensor heater with a transistor (e.g. with the BC547B transistor), so that we can PWM modulate the power; iii) add filtering (a capacitor and a diode) so that the switching noise is minimized during the readings. As such, the modified circuit looks like the diagram below. The only things that were preserved unchanged were the capacitor at the left side, and the power LED (the detection LED was removed):


Close-up pictures of the modified PCB (the potentiometer was not removed in spite of not being used):



In order to control the heater and perform the measurements in the correct moment in Tasmota and obtain proper values, I had to come up with a solution using what was readily available at runtime: Rules and PWM.

So the basic idea was to control a digital output (connected to the D0 pin on the sensor) and set it at 100% PWM for 60 seconds, and then reduce it to 28% (and as such get roughly the 1.4 Volts mandated by the spec after filtering the PWM) for 90 seconds. During this time a few readings would be taken, and these would be considered the valid ones.

As such, the following rule was implemented:

on system#boot do
backlog BlinkTime 30; Power1 3; Power2 3; Power3 3; RuleTimer1 30; var1 0; var2 0; var3 0; event curr_state=0
endon 
on Rules#Timer=1 do
backlog add1 1; RuleTimer1 30
endon 
on tele-ADS1115#A0 do
var3 %value%
endon 
on var1#state==0 do
Dimmer 100
endon 
on var1#state==1 do
Dimmer 100
endon 
on var1#state==2 do
Dimmer 100
endon 
on var1#state==3 do
Dimmer 28
endon 
on var1#state==4 do
backlog Dimmer 28; var2 %var3%
endon 
on var1#state==5 do
backlog Dimmer 28; var1 0
endon

Dimmer corresponds to the PWM output (it is the normal use case for PWM in Tasmota).

In my case I have initialized the PWM frequency to 4000 Hz. This value may be relevant depending on the filter network adopted (a higher frequency will likely require smaller filter capacitors and inductors). In order to set this value, type the following command in the console:

PwmFrequency 4000

The GPIO configuration with the PWM enabled should look like:


In order to use the values, for example in Home Assistant, we look at the current value of var2, which is the variable in which a valid concentration can be found. 

To configure as a sensor in HA, and have a very rough conversion to ppm, we are doing the following:

  - platform: mqtt
    name: kitchen_co_gas_concentration
    state_topic: 'stat/kitchen-sensors/RESULT'
    unit_of_measurement: 'ppm'
    value_template: "{{ '%0.1f'| format(((value_json.Var2|float)) / 20) }}"

In order to obtain a calibrated measure of the CO gas concentration, the sensor would have to be placed under known concentrations of CO gas and different temperature and humidity conditions. This would enable the construction of a model against which the raw value of this sensor  + relative humidity + ambient temperature at the same location would be input, and approximate value of the CO gas concentration would be obtained. It is worth noting that very low concentrations of this gas can hardly ever be detected by this sensor, as the noise floor caused by the concentration of other gases will mask its presence.

Detecting Methane

For the detection of methane, the other sensor from this family was used, namely the MQ-4. This is also a very cheap sensor, and has a very similar principle of operation to the previous sensor, based on the same active materials as the previous sensor.



It differs however in the way it can be operated. Unlike the CO sensor, in the MQ-4 the heater is supposed to be running continuously at 5 Volts. As such the circuit in which is provided (the same as in the MQ-7) is adequate, and the analog comparator chip can be used (by adjusting the potentiometer) to output a TTL signal, when detection rises above a certain threshold. It also outputs an analog signal that is proportional to the presence of methane (and unfortunately of other gases as well..). For my particular application that was the output I was most interested in using.

Acquiring the data from the analog sensors

Each of the forementioned sensors outputs a analog signal. The caveat is that the NodeMCU only has a single analog input. As such the solution in this case would be to either obtain a analog multiplexer chip and use some digital output pins to select which analog input to use, or use an external DAC chip with multiple analog inputs.

Given the elegance of the later solution, and the fact that there are some popular chips that implement such function, I went for the second option. For that effect I have chosen the ADS1115 from Texas Instruments.


This device provides 4 analog inputs and is capable of 16 bits of resolution, and a maximum of 860 samples per second, which is quite interesting. On the digital side, it provides an I2C interface. Besides the intrinsic features, another positive aspect of ths converter is that it supported by Tasmota. Once connected, and a Tasmota build with the sensor drivers is used (e.g. tasmota-sensors), it is automatically recognized by the firmware, and its raw data output to the SENSOR topic:



Detecting Particulate Matter

Progress comes to a cost, and in modern days unfortunately we are paying that debt. The cost is the environmental impact that not only affects the planet and what surrounds us, but our health and life quality. Industrial activity and the lifestyle of the majority of us leads to an impact in the quality of the air that surrounds us. From the cars that we drive every day, to the operation of the heavy industries, passing by most types of activities in between, the smoke emissions that result, translate into tiny (micrometer size) particles that become suspended in the air. The exposure to these particles is hazardous as it can promote various types of respiratory deseases. As such, by detecting and measuring the quantity, we are able to take actions in controlling our exposure to low quality air.

Particulate matter sensors became widespread not only because these are key components of commercial air quality monitoring stations, but also because these are built into devices that actively filter particulate matter from the ambient air. Such devices became particularly common in massively industrialized countries such as China.


In order to enrich the suite of sensors, I have added a reasonably low cost device, the Nova PM Sensor, model SDS011.

You may find more details and a review of this sensor in this page:


It uses a laser to detect particles as these are transported by the air forced through a fan into the sensor cavity.


It has two channels, one that outputs the amount of particles around 2.5 micrometers (PM2.5), and another one for PM10 particules.

These readings are provided via an RS-232 serial port. As with the previous sensor, Tasmota has built in support for this one too. The user has to specify to which GPIOs the sensor is connected to (i.e. the corresponding TX and RX pins), and select the SDS0X1 driver:


After it is configured, the data from this sensor will also be available in the SENSOR topic:


Detecting VOCs

Volatile Organic Compounds (VOCs) are present almost everywhere. Their concentration is especially higher inside houses, as several materials release certain quantities of these compounds over time. Synthetic materials such as plastics can release some VOCs which are present in the solvents, but cigarettes, cleaning fluids, paints, etc will release VOCs in some quantity as well.

Depending on the concentration, these can be harmful, causing irritation, dizziness, and long term exposure can promote diseases such as cancer and several types of organ damage.

Detecting these chemicals in the air, places the same challenge as explained before regarding the CO and CH4 sensors. The available sensors are only so much selective, having its results easily influenced by the presence of other substances.

Looking forward to obtain a sensor reasonably tuned for this purpose, I considered two options: either the Bosch BME680, or the CCS811from AMS. The first is a pretty comprehensive device, featuring a temperature sensor, a barometric sensor, a relative humidity sensor, and the VOC sensor in a single package. The second one is a device which integrates a metal oxide / micro-hotplate sensor and microcontroller. The device is firmware upgradeable, and the internal microncontroller is capable of providing two different readings, one reflecting the total VOC emissions and the other one the equivalent Carbon Dioxide emissions (eCO2). The later is claimed to be derived from a model predicting the CO2 concentration as a funcion of the presence of VOCs emitted by humans.

Instead of acquiring the isolated sensor, I have selected a breakout board featuring two other sensors as well: the BMP280 barometric pressure and temperature sensor, and the HDC1080 relative humidity and temperature sensor. This breakout board has the reference CJMCU-8128, and can be acquired from the usual Asian suppliers:




Detecting Temperature and Relative Humidity

I was misled by the seller, as the relative humidity sensor was presented as being the Si7021, which was already supported by Tasmota. After receiving the board and doing some close inspection to the package, I realized that instead this was the Texas Instruments HDC1080 sensor. 


Functionally it was not a loss, as this sensor has slightly better perfomance than the Si7021 - the relative humidity conversion has a resolution of 14 bits instead of  the 12 bits of the Silicon Labs sensor.

But on the other hand, this sensor was not supported by Tasmota. This was both frustrating, and an opportunity to solve the problem and contribute to the community .

So I ended up implementing the driver for this sensor, and submitting  a Pull Request for the Tasmota project:


It is currently available as part of the v8.2.0 Elliot release:

https://github.com/arendst/Tasmota/releases/tag/v8.2.0

As with all of the previously described sensors, the data from these sensors is also exposed via MQTT in the SENSORS topic.


Besides the direct use of knowing the relative humidity and the temperature as provided by this sensor box, this information is also useful for compensating offsets in other sensors, and for achieving more accurate readings in other sensors such as the CO sensor, as explained before. For example in the CC811 it is possible to store ambient air conditions in a register which the sensor will use for calibrating its readings.

Currently this is not being done for any of the sensors, but it is an interesting improvement in future versions of  Tasmota and/or to be done outside, e.g. in Home Assistant.

2 comments:

Travis J. Terrell said...

This is awesome, thank you so much for sharing it! I was planning to implement something similar and this is super helpful. I'm also going to look into options for adding an oxygen sensor, I think (I'm pretty sure the heater in my shop consumes a ton of it--would be nice to keep tabs on the levels.)

Creation Factory said...

Hi Travis, thanks for the feedback!

In my scenario I didn't focus on O2 monitoring because of the price of these sensors, and but from an air quality/hazard detection point of view, how relevant it actually is. I believe that when there is combustion involved, you will run into dangerous concentrations of carbon monoxide much quicker than the oxygen depletion becoming a problem. Normally you will want to focus on detecting what is more imminently dangerous.

But of course it depends on the scenario you want to monitor. For example where there is risk of oxygen displacement, an O2 sensor can be very useful - our senses are not very good at detecting a reduction in the O2 concentration of the air - we usually fall unconscious before we realize there is something wrong. A good example is in places where liquefied gases are stored or manipulated - an MRI machine for example contains copious amounts of liquid helium inside. If it were to escape to the atmosphere, albeit it is not toxic, it would displace the oxygen potentially to dangerously low levels for humans to breathe.

Cheers