Skip to content

Instantly share code, notes, and snippets.

@jorgeassuncao
Last active January 23, 2019 19:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jorgeassuncao/40956bbe4ac8db9fdb8f0526a4e0c0fe to your computer and use it in GitHub Desktop.
Save jorgeassuncao/40956bbe4ac8db9fdb8f0526a4e0c0fe to your computer and use it in GitHub Desktop.
ESP_Energy_Monitor_MQTT
/**
* This script is based on these sources:
*
* To count pulses using interruptions: https://github.com/mysensors/MySensors/blob/master/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino
* To connect to Wifi and publish MQTT messages: https://github.com/knolleary/pubsubclient/blob/master/examples/mqtt_esp8266/mqtt_esp8266.ino
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
*******************************
*
* DESCRIPTION
* Use this sensor to measure kWh and Watt of your house meter.
* You need to set the correct pulsefactor of your meter (pulses per kWh).
* You have to update the information related to the MQTT server
* Reports to different MQTT topics every SEND_FREQUENCY miliseconds:
* (1)- Energy (in kWh) consumed in the last SEND_FREQUENCY/1000 seconds
* (2)- Power (in W) consumed in the last SEND_FREQUENCY/1000 seconds
* (3)- Energy (in kWh) consumed since the device was switched on
* There could be errors in (1) and (2) since pulse counting and information sending events
* do not take place at the same time. (3), if enough time has passed by, is as accurate as
* the one from the measuring device
*/
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
/************************* WiFi Access Point *********************************/
const char* ssid = "XXXXXXXX"; // Wifi SSID
const char* password = "XXXXXXXX"; // Wifi password
byte mac[6]; // the MAC address of your Wifi shield
IPAddress ip(192,168,1,XXX); // IP address
IPAddress dns(192,168,1,1); // DNS server
IPAddress gateway(8,8,8,8); // Gateway
IPAddress subnet(255,255,255,0); // Subnet mask
/**************************** MQTT Broker ************************************/
const char* mqtt_server = "192.168.1.XXX";
const char* mqtt_username = "XXXXXXXX";
const char* mqtt_password = "XXXXXXXX";
/**************************** MQTT topics ************************************/
const char* mqtt_topic_watt = "ESP_Energy_Meter_01/watt"; // MQTT topic - watt
const char* mqtt_topic_kwh = "ESP_Energy_Meter_01/kwh"; // MQTT topic - kwh
const char* mqtt_topic_pulse = "ESP_Energy_Meter_01/pulse"; // MQTT topic - pulse
const char* mqtt_topic_ip = "ESP_Energy_Meter_01/ip"; // MQTT topic - ip
const char* mqtt_topic_mac = "ESP_Energy_Meter_01/mac"; // MQTT topic - mac
/**************************** Pins ************************************/
int LED_pin = 2;
#define DIGITAL_INPUT_SENSOR 12 // The digital input D6 in Wemos D1 mini
/**************************** Pulses per kWh ************************************/
#define PULSE_FACTOR 1000 // Number of pulses per kWh of your meeter
/**************************** Breathing LED ************************************/
#define BRIGHT 350 // Max led intensity (1-500)
#define INHALE 1250 // Inhalation time in milliseconds.
#define PULSE INHALE*1000/BRIGHT // Pulse
#define REST 1000 // Rest Between Inhalations.
/**************************** ************************************/
unsigned long SEND_FREQUENCY = 15000; // Minimum time between send (in milliseconds)
volatile unsigned long pulseCount = 0;
volatile unsigned long lastBlink = 0;
double kwh;
unsigned long lastSend;
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
char wattString[7];
char kwhString[7];
char kwhaccumString[7];
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.config(ip, dns, gateway, subnet);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
WiFi.macAddress(mac);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.print("MAC: ");
Serial.print(mac[5],HEX);
Serial.print(":");
Serial.print(mac[4],HEX);
Serial.print(":");
Serial.print(mac[3],HEX);
Serial.print(":");
Serial.print(mac[2],HEX);
Serial.print(":");
Serial.print(mac[1],HEX);
Serial.print(":");
Serial.println(mac[0],HEX);
}
// Setup a MQTT subscription
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("ESP8266Client", mqtt_username, mqtt_password)) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup()
{
pinMode(LED_pin, OUTPUT); // Initialize the LED_pin as an output
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
// Use the internal pullup to be able to hook up this sketch directly to an energy meter with S0 output
// If no pullup is used, the reported usage will be too high because of the floating pin
pinMode(DIGITAL_INPUT_SENSOR,INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), onPulse, RISING);
// Initialization of variables
kwh = 0;
lastSend=millis();
}
void loop()
{
//ramp increasing intensity, Inhalation:
for (int i=1;i<BRIGHT;i++){
digitalWrite(LED_pin, LOW); // turn the LED on.
delayMicroseconds(i*10); // wait
digitalWrite(LED_pin, HIGH); // turn the LED off.
delayMicroseconds(PULSE-i*10); // wait
delay(0); //to prevent watchdog firing.
}
//ramp decreasing intensity, Exhalation (half time):
for (int i=BRIGHT-1;i>0;i--){
digitalWrite(LED_pin, LOW); // turn the LED on.
delayMicroseconds(i*10); // wait
digitalWrite(LED_pin, HIGH); // turn the LED off.
delayMicroseconds(PULSE-i*10); // wait
i--;
delay(0); //to prevent watchdog firing.
}
delay(REST); //take a rest...
if (!client.connected()) {
reconnect();
}
client.loop();
unsigned long now = millis();
// Only send values at a maximum frequency
bool sendTime = now - lastSend > SEND_FREQUENCY;
if (sendTime) {
// convert to a string with 2 digits before the comma and 2 digits for precision
dtostrf(kwh, 2, 4, kwhString);
client.publish(mqtt_topic_kwh,kwhString); // Publish kwh to MQTT topic
lastSend = now; // once every thing is published we update the send time
// We calculate the power using the energy
double watt = kwh * 1000.0 * 3600.0 / (double)SEND_FREQUENCY * 1000.0;
dtostrf(watt, 4, 2, wattString);
client.publish(mqtt_topic_watt,wattString); // Publish watt to MQTT topic
Serial.print("Watt:");
Serial.println(wattString);
// We calculate the accumulated energy since the begining using pulses count
double kwhaccum = ((double)pulseCount/((double)PULSE_FACTOR));
dtostrf(kwhaccum, 3, 3, kwhaccumString);
client.publish(mqtt_topic_pulse,kwhaccumString); // Publish pulses to MQTT topic
kwh = 0;
// Send IP address
String ipaddress = WiFi.localIP().toString();
char ipchar[ipaddress.length()+1];
ipaddress.toCharArray(ipchar,ipaddress.length()+1);
client.publish(mqtt_topic_ip,ipchar); // Publish IP address
}
}
void onPulse()
{
unsigned long newBlink = micros();
unsigned long interval = newBlink-lastBlink;
if (interval<10000L) { // Sometimes we get interrupt on RISING
return;
}
// Every time there is a pulse, the energy consumption is 1 [pulse] / PULSE_FACTOR [pulses/kWh]
// We also want to accumulate the energy (it will be initialized again once MQTT message is sent)
kwh += 1.0 / (double)PULSE_FACTOR;
lastBlink = newBlink;
pulseCount++;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment