Cheap Home Air Quality Monitoring

I’ve wanted to monitor room temperature and humidity in my home for quite some time and I recently came across the ESP8266 Wi-Fi microcontrollers that were ideal for the job. Prior to the ESP8266 becoming mainstream, I was considering running a 1wire network over spare phone wires, similar to this weather station setup.


Thankfully, the ESP8266 chips are cheap enough that fitting one in each room of a house is practical. On top of that, people had already made inroads to getting code running on the ESP, including a webserver returning readings from a DHT22 temperature and humidity sensor.

The ESP8266 chip itself includes a Tensilica Diamond Standard core, although documentation is a little sparse. Fortunately, setting up a toolchain is relatively straight forward, and there is a (proprietary) SDK available that allows custom firmware to be built and flashed onto the modules.


The hardware I threw together is very simple, and hooks up a DS18B20 1wire temperature sensor and a DHT11 temperature and humidity sensor up to the two GPIOs hooked up to pins on the module. Since I wanted a handful of the the boards, I opted to design the circuit in Fritzing and got a pack of boards from DirtyPCBs. The schematic and board are below:


Temp Mon PCB

The schematic is straight-forward; 5V comes in from a USB socket and goes through a 250mA fuse and gets dropped to 3.3V by a TS1086CZ or AMS1117 module. The switch S1 allows the GPIO pin to be grounded to program the module, with the UART pins broken out to a separate header.

Software – ESP8266

The software is quite simple. Using sprite_tm’s webserver code and building on Martin’s additions for the DHT sensor, my code adds a DS18B20 driver and support for the cheaper DHT11 sensor.

In addition to serving the sensor values over HTTP, the code periodically sends a JSON packet over UDP to a logging host (a Raspberry Pi) which stores it in a MySQL database and an rrdtool database.

I noticed after a few days of running, the ESP boards can get quite warm. Although I don’t think it affected the sensors, it seemed sensible to avoid leaving the ESP8266 online if it only needed to periodically log data. Fortunately, there is a “deep sleep” function in the SDK, but unfortunately this requires the RESET pin to be soldered to the RTC pin to trigger wakeups. With the chips spending most of the time asleep, they don’t get warm at all.

Software – Logging

A python script listens on the UDP port for incoming packets, deserialises them, and logs them. The readings from the DHT sensor are susceptible to noise (possibly a bug in the driver), so the script includes logic to reject samples that are outside a window.

RRDTool expects updates for every value at once, so it’s not possible to use a single RRD to store the data from multiple hosts as it comes in at different times. Instead, each host needs its own RRD, so I use a script to create them as I add hosts to the network.

Software – Visualising

I initially used a Shiny app to load the data from the SQL database, but this became unworkable quite quickly; without a lot of spare RAM, MySQL resorts to creating temporary tables on the SD card which is tragically slow.

Shiny Dashboard

For quick at-a-glance readouts, I switched to RRDTool. Although it’s not as pretty as ggplot2, it’s lightweight enough to render graphs regularly and serve them as static images, which fits far more comfortably on the Raspberry pi. The script just iterates over each host and plots it for various intervals, saving the images to a webserver’s directory.

Bill of Materials & Cost

  • PCBs: $14/12 – £0.78ea
  • USB B Connector: £2.51/5 – £0.50ea
  • Fuse holder: £1.29/10 – £0.13ea
  • Fuse: ~£0.10ea
  • ESP8266: £8.36/4 – £2.09ea
  • DS18B20: £4.99/5 – £1.00ea
  • DHT11: £3.04/5 – £0.61ea
  • AMS1117 module: £2.62/5 – £0.52ea
  • Switch: £1.99/5 – £0.40ea
  • 4.7kR resistor: 2x~£0.02ea
  • Project box: £3.36/5 – £0.67ea

That works out at approximately £6.84 (amortising the cost of the PCBs), or £7.93 each for the 5 nodes I built. I’m ignoring the cost of power supplies as I have at least one USB power source and cable in the rooms I’m monitoring. Given there are more GPIOs on board to the ESP8266, there’s also scope for adding more sensors to them later on.


Using an Efergy Current Transformer to Monitor Power Consumption

Household power consumption can be estimated non-invasively by attaching a current transformer(s) to the incoming phase(s). There are quite a few commercial kits available that do this, plus EmonTX. I wanted a solution that allowed me to log power consumption over the network, and bought an Efergy “Smart” sensor, designed for Efergy’s E2 and Elite monitors.

Unlike other current transformers, the Efergy sensor contains some more interesting components. There’s a long discussion on the OpenEnergyMonitor forums about this sensor, including internals, and response characteristics, that ultimately concludes the components should be replaced to get it to work with EmonTX’s design. I wanted to keep the sensor as a unit for safety, so opted to embrace the odd design.

In a nutshell, the EmonTX reference design is to take the AC signal from a transformer fitted with an appropriate burden resistor, DC-bias it to lift the whole signal so it’s always positive, and then scale it to a range that the microcontroller on the board can tolerate (5V or 3.3V).

This design is very simple, requires very few components (resistors and a capacitor), and makes estimation easy: sample the waveform, scale the value according to the burden resistance and turns ratio, then compute the RMS of those samples to get an estimate of current. Multiplying this by an estimated (or measured) voltage and power factor generates a power consumption estimate in Watts.

Efergy's current transformer internal circuit (modelled in LTSPICE)
Efergy’s current transformer internal circuit (modelled in LTSPICE)

The Efergy sensor’s extra components do a couple of things. Firstly, a half-wave rectifier diode (D2 in the schematic) chops half of the waveform off (in practice, this limits the voltage on one half of the signal to 0.7V). This immediately means sampling the waveform won’t work without extra logic.

The diode D1 serves to decrease the burden resistance for larger loads. This results in a non-linear response to the current through the primary. Both of these components allow more of the ADC’s resolution to be used measuring the waveform at lower (expected) loads.

I threw this circuit into LTSPICE, and simulated it under a sinusoidal current source with an amplitude of 110mA, corresponding to a sinusoidal current through the primary of about 100A with a turns ratio of 1350. The waveform’s shown below:

Efergy current transformer AC response for 100A RMS.
Efergy current transformer AC response for 100A RMS.

This shows the clipped waveform, limited by D2, and the non-linear “kink” in the output voltage as the current increases, roughly at -52mA on the secondary (about 73A on the primary).

I’m using an MSP430G2553 for this project, which includes a 10-bit ADC. Unfortunately, TI advises against applying voltages outside the region of 0-3.3V to the microcontroller, and the ADC only converts inputs between 0V and 3V.

Like the EmonTX design, this signal requires at least two transforms, one to shift it so it’s all positive, and another to scale it to the safe input range. The shift can be achieved by biasing the circuit from a voltage divider (as EmonTX does), and the scale can also be achieved using a voltage divider.

However, half of the waveform isn’t useful at all, so it doesn’t make sense to waste the ADC’s range on it. The negative voltage still needs to be removed, however, so the sensor needs to be biased by the drop of D2.

To claw back some useful range, and to clamp the negative cycle to (close to) zero, I placed a diode in line with the signal, which drops the signal by about 0.7V. With a 0.8V bas, this takes the 0mA offset for the positive cycle from 0.7V to about 0.4V. This bias also ensures (at least theoretically) that the rectifier diode is biased when the interesting signal is going through it. Putting this together with an output divider:

Efergy monitor circuit design

This produces the following waveforms, measured at the current transformer (red), at the diode D5 (green), and at the output (blue), against current (cyan):

Output Waveforms

This scales the input (roughly) into the 0-3V range. At the top end, the output does increase to around 3.3V, but this occurs when the current drawn at the primary is around 95A; at this point, I have bigger problems than a blown MSP430.

Up to now, I’ve only been simulating the circuit, so practical considerations might change things. I still need to build the hardware and deal with mapping the signal to estimates of instantaneous AC usage. I’ll cover these issues in later posts.

The LTSPICE model for this post is available here.