Here is how to setup a household power monitor using an ESP8266 module, some simple circuits and a few bits of software.

This is based off a guide from openenergymonitor.org.

https://learn.openenergymonitor.org/electricity-monitoring/ct-sensors/introduction

What you will need

  • ESP8266 NodeMCU ESP-12F
  • A passive Current Sensor YHDC SCT-013-000
  • 2x 10 Ohm Resistors
  • 2x 10K Ohm Resistors
  • A 10uF capacitor
  • A server/raspberry pi to host Grafana and Prometheus

The circuit diagram for this shows that we need a burden resistor to reduce the output voltage so it can be used with our module. In this case my module uses 3.3V logic levels, so using this burden calcuator the recommended Resistor size is 23 Ohms, however if you dont have the exact right one, go for a resistor smaller than the calculated one in order to prevent a higher voltage damaging your ESP module. In my case I used two 10 Ohm resistors in series to give me 20 Ohms.

We also need a voltage divider to reduce the voltage from the Current Sensor to a voltage safe for our ESP module. For this we use two 10K Ohm Resistors.

The positive lead from the current sensor does to our Analogue Input on the ESPModule, named A0 in my case.

Prototyping

I tested the circuit out in a breadboard and uploaded the code which I cobbled together attached at the end of this post.

The general idea is using the EmonLib package to pull the current sensor values and the ESP8266 example HTTP server I publish the current and power stats to the HTTP server in a format which Prometheus can scrape.

Prometheus is then configured to scrap the end point.

Grafana then integrates with Prometheus and gives us the ability to make awesome dashboards

After testing it out on the breadboard I moved the components to a protoboard.

Final Build

Code

For the below code update the SSID and PASSWORD so it can connect to your AP. There is some calibration values you can tweak if the output values don’t seem correct, please refer to OpenEnergyMonitor for more details.

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include "EmonLib.h"                   // Include Emon Library
#ifndef STASSID
#define STASSID "SSID"
#define STAPSK  "PASSWORD"
#endif

EnergyMonitor emon1;                   // Create an instance

const char* ssid = STASSID;
const char* password = STAPSK;

double pwr;
double Irms;

ESP8266WebServer server(80);

void handleRoot() {
  
  server.send(200, "text/plain", "Hello!");
}

void handleMetric() {
  Irms = emon1.calcIrms(1480);  // Calculate Irms only
  pwr = Irms*230.0;
  String powerMetric = "# HELP apparent_power The Apparent Power (VA)\napparent_power{device=\"mainspower\",location=\"home\"} " + String(pwr);
  String currentMetric = "# HELP rms_current The RMS Current (A)\nrms_current{device=\"mainspower\",location=\"home\"} " + String(Irms);
  Serial.println(powerMetric);         // Apparent power
  Serial.println(currentMetric);         // Current
  server.send(200, "text/plain", powerMetric + "\n"+ currentMetric);
}


void handleNotFound() {
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
}

void setup(void) {
  
  
  Serial.begin(115200);
  //pin 17 is A0
  emon1.current(A0, 111.1);             // Current: input pin, calibration.
  
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  if (MDNS.begin("esp8266")) {
    Serial.println("MDNS responder started");
  }

  server.on("/", handleRoot);
  server.on("/metrics", handleMetric);
  server.on("/inline", []() {
    server.send(200, "text/plain", "this works as well");
  });


  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("HTTP server started");
}

void loop(void) {
   
  server.handleClient();
  MDNS.update();
}