Creating a simple WiFi-enabled energy monitor

.. and using Kibana to display the data

TL,DR; I created a standalone top hat EN 500022 DIN-rail compatible device to monitor and log to a remote ELK server via WiFi my main room temperature and power consumption; The electronics is made up with a standard Arduino UNO board, a WiFi shield and a custom PCB. The casing is 3D printed and is made to fit in a standard electrical wall box, with only the screen, temperature sensor and antenna popping off.

![](/content/images/2015/03/closeup.jpg)
![](/content/images/2015/03/elk.png)
(yes, I woke up at noon that day. So what?)

Why ?

Winter was coming and I my living room was never at the right temperature — either too cold, or too hot. Or so I thought, since I had no way to tell (no thermometer at hand). I wanted to have a good insight on how the temperature was fluctuating in the room and moreover I wanted to be able to know if it was more efficient to leave the heating on when I'm not home to keep a constant comfy temperature or to leave it off and heat more when I went home at night.

Existing devices

Of course a lot of devices already exist for that purpose : some really nice commercial ones such as the Netatmo thermostat, or Google Nest for instance, or even a Home Energy Meter from Aeon Lab.

Open source initiatives exist as well, like OpenEnergyMonitor.


(image courtesy OpenEnergyMonitor)

But I wanted to build it all myself from scratch:

  • first and foremost to be able to understand how to build such a device,
  • because I wanted to be able to process the data the way I wanted,
  • and finally because I really wanted the device to fit in my electrical panel (this kind of panel)

0. So, what do we build ?

Let's note down what our device should do:

  • sense the temperature
  • calculate the instantaneous mains current
  • send this data over WiFi at a fixed interval
  • (optionally) display the temperature on the device
  • (optionally) display the power consumption in realtime

So I went on and built a first prototype. First things first : let's start building the electronics.

1. The electronics

I decided to base everything off the Arduino UNO since it's easy to program and has an easy mounting shield interface. It's clearly not the smallest device (I could have used a Nano or a Pro but at the prototype stage, I didn't feel confident I would easily manage to connect everything).


(image courtesy arduino.cc)

For the network connectivity, we add a WiFi shield, with a Texas Instruments CC3000 IE802.11b/g module that seem quite common, like on this one from Adafruit :


(image courtesy adafruit.com)

As for the rest, we need : a non-invasive current sensor, for example this one from Sparkfun :


(image courtesy sparkfun.com)

And some displays : a 7-segment to display the temperature, and a led strip (8 leds) to display the power consumption relative to the max power allowed for my installation.


(images courtesy adafruit.com)

To get a reading out of the current sensor, we need to add a burden resistor to read a voltage instead of a current, and shift the voltage to an acceptable 0 -> 5V range or the Arduino ADC. Here is a little diagram to show how to connect everything together :


(image courtesy some site I can't remember — if you're the author, let me know :) !)

The Bill Of Materials is as follows :

Element Where to find it
Resistor Hardware shop or Sparkfun
1x 1000µF capacitor Hardware shop or Sparkfun
1x 10µF capacitor Hardware shop or Sparkfun
2x 10kΩ resistor Hardware shop or Sparkfun
2x 200Ω resistor Hardware shop or Sparkfun
1x 47Ω resistor Hardware shop or Sparkfun
1x Stereo TRS connector (jack 3.5mm) Hardware shop or Sparkfun
1x JST connector 3pin and 1x JST connector 4pin Hardware shop or Sparkfun
1x antenna (U.FL connector) Hardware shop or Sparkfun
1x TMP36 temperature sensor Hardware shop or Sparkfun
Multi-strand wires Hardware shop or Sparkfun
Some pin headers Hardware shop or Sparkfun

A note on how we calculated the burden resistors values :

In the primary coil, the peak current is :

peak_current_primary = MAX_CURRENT * sqrt(2)

so in the secondary coil, we have :

peak_current_secondary = peak_current_primary / NB_TURNS

and we know we have 2000 turns on the sensor. The Arduino is roughly running at 5V, so

VCC = 5000; // in mV. Or readVcc(), see later

so burden_resistor_value = ((VCC/1000.0) / 2) / peak_current_secondary

For a max current of 15A (3kW at 230V), we have 235Ω which is close to a standard value of 247Ω — a double check here

Ta-da! :


(Maybe I should round that 24.98°C up ...)

Now, let's have a look at the Arduino code structure. We need different routines : code for the WiFi module, code for reading the sensors value, code for displaying everything and sending it out.

The whole code is available here on github and is conveniently divided into files for readability. Some interesting bits :

a readVcc() function to get more accurate readings, thanks to Matt and Jérôme, which boils down to :

 // (...)
delay(2);                    	// Wait for Vref to settle
ADCSRA |= _BV(ADSC);             // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = 1126400L / result;  	// 1100mV*1024 ADC steps
return result;

a reset function used to reboot the Arduino when the WiFi crashes :

void(* resetFunc) (void) = 0;

The calcIrms() function is almost directly taken from the OpenEnergyMonitor library here, thanks guys !

2. A custom PCB

To include all the components seen on the previous picture, I thought a custom PCB would be great.

I used Fritzing again (and Fritzing Fab) to design and produce the board. The design is not very difficult (and, to be honest, not very well thought, but hey), it's just an attempt to put everything on a board with connectors (JST) to allow for plugging/unplugging the displays.

You can see that the pin headers are offset : that is because I soldered the corresponding pins with an offset as well on the WiFi shield. Not a necessity though, just a choice.

3. Server-side : process the data

I already have an ELK stack that process all my server logs and a nice dashboard for the sanity of the whole infrastructure. I use it a lot, and it seemed a good platform to send the data to, as it is quite made for this kind of time series.

So I decided to give it a try.

First mission : get the data and store it nicely for logstash

Logstash knows how to reads log file, so let's write a log file !
I fired up a text editor and created a little node.js app that would get the requests and process them.

As per the Arduino code, the request coming is something like :

POST /api/endpoint HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: XX
key=myPriVaTeKey&t=22.1&w=1340

Express is perfectly fit to easily create a simplistic app that will take care of all that :

// We have defined a config object beforehand
app.post(config.PATH, function (req, res) {
  if (req.body.key == config.PRIVATE_KEY) {
    temperature = req.body.t
    power = req.body.w
    date = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '').replace(/-/g, '\/')

    var log_message = date + " " + temperature + " " + power

    fs.appendFile(config.LOG_FILE, log_message + "\n", function (err) {
      if (err) {
        res.json({ code: 0 })
      } else {
        res.json({ code: 1 })
      }
    });
  }
})

The log file would thus basically be like this :

2015/03/03 20:34:13 21.2 71
2015/03/03 20:34:17 21.2 72
2015/03/03 20:34:22 21.2 71
2015/03/03 20:34:26 21.2 71

Second mission : process the data in logstash

To process the log in logstash, we're going to create a little grok rule, and duplicate the logs using ruby since we need a log line per figure to make kibana behave :

First, we tag the incoming data :

input {
  file {
    path => "/var/log/energy/energy.log"
    type => "energy"
  }
}

Then, we filter it out and clone each log line. The aim is to create a common pattern for all lines, with the value (energy or temperature) stored under a common "value" key :

filter {
  if [type] == "energy" {
    # Extracts the values
    grok { 
      match => { "message" => "(?<timestamp>%{YEAR}/%{MONTHNUM:month}/%{MONTHDAY:day} %{TIME}) %{NUMBER:temperature:float} %{NUMBER:power:float}" }
    }
    # Gives it a type first
    mutate {
      update => [ "type", "temperature" ]
    }
    # Clones the event
    clone {
      clones => ["power"]
    }
  }
  ruby {
    code => "
        if event['type'] == 'temperature'
            event['value'] = event['temperature'].to_f
        elsif event['type'] == 'power'
            event['value'] = event['power'].to_f
        end
    "
  }
}

Our logs now get nicely into Elasticsearch. Yeah !

Third mission : create a nice dashboard

Now that is quite an easy task since all the hard work has already been done. Some charts and a nice trend graph, and boom :

4. Casing

Now for some hardware design !

We have quite a bunch of constraints to take into account: The DIN-rail (a standard for circuit-breakers inside electrical box), the limited volume inside the electrical box, the opening to let the screen, led strip and antenna out.

So what volume do we have ?

Between the DIN rail and the outer casing of the electrical box, there's a distance of 45mm. That is the actual length (depth?) of a conventional circuit breaker (at least here in France):

The part of the breaker with the switch pops out of the box so it is easily accessible in case you need to reengage or disengage it.

So our electronics needs to fit in this 45mm. We can take more width obvisouly, but we'll try to make it small nonetheless. I designed the boards approximately at scale to see the volume I needed for the UNO, the WiFi shield and the custom PCB :

Looks like we have something like 30mm, plus the components we need to account for, and that will be soldered on the (outer) custom PCB. Not that much space left, but if fits ! ;)

The box

With that in mind, let's create a box around these guys, to hold the shields :

There's a hinge on the left, for a closing panel where the screen and leds, and the antenna hole, will be. On the sides, I left holes so I could access the USB port of the UNO and the power plug.

The big round hole on the right is for the current clamp plug (a standard jack 3.5mm).

Obviously, the oblong holes are for cooling the whole device.

Inside, I planed 4 mounting holes for M3 screws so that the Arduino board is thightly held in place :


Some parts are pink — they are supports I created in the design that help when 3D printing the case

The lid

And now for the lid. It must hold the screen, the led strip, the antenna hole, and a hole for the thermometer (so it is on the outside).

We have the dimensions for all these items, so we can define what the outer plate will look like :

On top of that, we need to add the hinge counterparts, some holes for cooling, the screw holes (M2 here) and some bevels, chamfers and fillets to be able to print the parts on a 3D printer.

To keep the 7 segment and led strip in place, I had to add another little plastic plate (in green below), screwed on the lid from the inside with M2 screws:


(view from the outside, with the lid being greyed ("transparenced") out)

Notice on the left, the hole for the thermometer. Both parts assembled give something like this :

5. The final design

After some trial and error adjustments, I came up with a relatively satisfying design :

It's quite big. But if fits in my electrical box, which was the goal. An Arduino Nano would have been enough I guess, in terms of processing power and inputs, but the shield system was more convenient with the UNO.

All the 3D files (STL) are here but you can also grab the source CATIA files in the corresponding directory in the repo. If anyone needs, I can output STEP files easily.

The last thing I decided to add was a little plastic plate in front of the displays, since they were far too bright otherwise. I laser-cutted it in plexiglas 3mm, and you can find the Illustrator file here.

So ... now let's print that "IRL", here are some pictures of the various parts (at different prototyping stages) :


the lid with its inside piece, holding the screen and the led bar


box and lid printed and mounted on a DIN rail (note it's one of the early prototype that doesnt't have all the correct holes and mounts on the lid)


the "yellow" prototype, with all the functionning electronics inside, and a far too big antenna. This was not the final version though (there is no hole for the thermometer


the "blue" final device, with the plexiglass plate and the antenna connector (sorry for the blurry shot)


While building and coding the last adjustments, I ran into some interesting things to note :

  • Code size can become an issue if you don't pay attention :


Ooops, that was close! 809 bytes for local variables is not that much as well, but it works

  • The WiFi shield consumes a lot of power : I was using a cheap AC/DC and experienced unstable behaviours and frequent brownouts. As noted here, it needs a good 1A to work properly. So the whole device needs at leats 1.5A to be on the safe side

  • Sensing temperature is tricky : you need to sense it not too close from the Arduino shields, or you get wrong readings, since the shields heat up a little and confuse the sensor.

  • The CC3000 is not very resilient to network errors, so you have to account for it. It can sometimes hang for no reason, which is a pain in the a**. Note to self : it may be a better idea to transmit via simple RF the readings to a base station that is a bit more powerful and does the networking part for you.

Conclusion

All of this is open-source as usual so do not hesitate to contribute and share, improve, hijack the project : https://github.com/tchapi/Arduino-Energy-Monitor

Now what's next ? I guess miniaturization could be the next evolution, or using a base station and create multiple sensors, but then I guess I'd rather use a ready-made solution like OpenEnergyMonitor.

Interested? Drop me a line at cyril[at]foobarflies.io