From 22ae72c520b1317b89f52347de261d5ca9c97ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Tue, 5 Jul 2016 00:55:18 +0200 Subject: [PATCH] Added suport or energy monitoring --- code/lib/EmonLiteESP/EmonLiteESP.cpp | 65 +++++++++++++++++ code/lib/EmonLiteESP/EmonLiteESP.h | 35 +++++++++ code/src/code.ino | 102 +++++++++++++++++++++++++-- 3 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 code/lib/EmonLiteESP/EmonLiteESP.cpp create mode 100644 code/lib/EmonLiteESP/EmonLiteESP.h diff --git a/code/lib/EmonLiteESP/EmonLiteESP.cpp b/code/lib/EmonLiteESP/EmonLiteESP.cpp new file mode 100644 index 00000000..afc075f1 --- /dev/null +++ b/code/lib/EmonLiteESP/EmonLiteESP.cpp @@ -0,0 +1,65 @@ +/* + EmonLiteESP + + Energy Monitor Library for ESP8266 based on EmonLib + Currently only support current sensing +*/ + +#include "Arduino.h" +#include "EmonLiteESP.h" + +void EnergyMonitor::initCurrent(unsigned int pin, double ref, double ratio) { + _currentPin = pin; + _referenceVoltage = ref; + _currentRatio = ratio; + _currentMidPoint = (ADC_COUNTS>>1); + + // Calculate default precision + _currentFactor = _currentRatio * _referenceVoltage / ADC_COUNTS; + _precision = 0; + _multiplier = 1; + while (_multiplier * _currentFactor < 1) { + _multiplier *= 10; + ++_precision; + } + --_precision; + _multiplier /= 10; + +}; + +byte EnergyMonitor::getPrecision() { + return _precision; +} + +void EnergyMonitor::setPrecision(byte precision) { + _precision = precision; + _multiplier = 1; + for (byte i=0; i<_precision; i++) _multiplier *= 10; +} + +double EnergyMonitor::getCurrent(unsigned int samples) { + + int sample; + double filtered; + double sum; + + for (unsigned int n = 0; n < samples; n++) { + + // Read analog value + sample = analogRead(_currentPin); + + // Digital low pass filter extracts the VDC offset + _currentMidPoint = (_currentMidPoint + (sample - _currentMidPoint) / 1024.0); + filtered = sample - _currentMidPoint; + + // Root-mean-square method + sum += (filtered * filtered); + + } + + double rms = int(sqrt(sum / samples) - 0.5); + double current = _currentFactor * rms; + current = round(current * _multiplier) / _multiplier; + return current; + +}; diff --git a/code/lib/EmonLiteESP/EmonLiteESP.h b/code/lib/EmonLiteESP/EmonLiteESP.h new file mode 100644 index 00000000..f8d17ac8 --- /dev/null +++ b/code/lib/EmonLiteESP/EmonLiteESP.h @@ -0,0 +1,35 @@ +/* + EmonLiteESP + + Energy Monitor Library for ESP8266 based on EmonLib + Currently only support current sensing +*/ + +#ifndef EmonLiteESP_h +#define EmonLiteESP_h + +#define ADC_BITS 10 +#define ADC_COUNTS (1<. #include #include "FS.h" #include +#include // ----------------------------------------------------------------------------- // ConfiguraciĆ³ @@ -40,6 +41,7 @@ along with this program. If not, see . #define ENABLE_OTA 1 #define ENABLE_MQTT 1 #define ENABLE_WEBSERVER 1 +#define ENABLE_ENERGYMONITOR 1 #define APP_NAME "Espurna 0.9" #define APP_AUTHOR "xose.perez@gmail.com" @@ -64,6 +66,17 @@ along with this program. If not, see . #define RF_DEVICE 1 #define MQTT_RETAIN true +#define MQTT_TOPIC "/test/switch/{identifier}" +#define MQTT_PORT 1883 + +#define CURRENT_PIN A0 +#define REFERENCE_VOLTAGE 1.0 +#define MAINS_VOLTAGE 230.0 +#define CURRENT_RATIO 156 +#define CURRENT_PRECISION 1 +#define SAMPLES_X_MEASUREMENT 1500 +#define MEASUREMENT_INTERVAL 10000 +#define MEASUREMENTS_X_MESSAGE 6 // ----------------------------------------------------------------------------- // Globals @@ -85,12 +98,15 @@ DebounceEvent button1 = false; WiFiClient client; PubSubClient mqtt(client); String mqttServer = ""; - String mqttTopic = "/test/switch/{identifier}"; - String mqttPort = "1883"; + String mqttTopic = MQTT_TOPIC; + String mqttPort = String(MQTT_PORT); String mqttUser = ""; String mqttPassword = ""; char mqttStatusTopic[30]; char mqttIPTopic[30]; + #if ENABLE_ENERGYMONITOR + char mqttPowerTopic[30]; + #endif bool isMQTTMessage = false; #endif @@ -102,6 +118,10 @@ DebounceEvent button1 = false; String rfDevice = String(RF_DEVICE); #endif +#if ENABLE_ENERGYMONITOR + EnergyMonitor monitor; +#endif + // ----------------------------------------------------------------------------- // Utils // ----------------------------------------------------------------------------- @@ -533,6 +553,13 @@ void wifiLoop() { tmp.toCharArray(mqttIPTopic, tmp.length()+1); mqttIPTopic[tmp.length()+1] = 0; + // Get publish current topic + #if ENABLE_ENERGYMONITOR + tmp = base + "/power"; + tmp.toCharArray(mqttPowerTopic, tmp.length()+1); + mqttPowerTopic[tmp.length()+1] = 0; + #endif + } void mqttCallback(char* topic, byte* payload, unsigned int length) { @@ -573,16 +600,25 @@ void wifiLoop() { mqtt.setServer(buffer, mqttPort.toInt()); #ifdef DEBUG - Serial.print("Connecting to MQTT broker: "); + Serial.print("Connecting to MQTT broker at "); + Serial.print(mqttServer); #endif if (mqttUser.length() > 0) { + #ifdef DEBUG + Serial.print(" as user "); + Serial.print(mqttUser); + Serial.print(": "); + #endif char user[mqttUser.length() + 1]; mqttUser.toCharArray(user, mqttUser.length() + 1); char password[mqttPassword.length() + 1]; mqttPassword.toCharArray(password, mqttPassword.length() + 1); mqtt.connect(getIdentifier(), user, password); } else { + #ifdef DEBUG + Serial.print(" anonymously: "); + #endif mqtt.connect(getIdentifier()); } @@ -798,7 +834,7 @@ bool loadConfig() { ArduinoOTA.setPassword((const char *) ADMIN_PASS); ArduinoOTA.onStart([]() { - #ifdef ENABLE_RF + #if ENABLE_RF RemoteReceiver::disable(); #endif #ifdef DEBUG @@ -810,7 +846,7 @@ bool loadConfig() { #ifdef DEBUG Serial.println("OTA - End"); #endif - #ifdef ENABLE_RF + #if ENABLE_RF RemoteReceiver::enable(); #endif }); @@ -842,6 +878,56 @@ bool loadConfig() { #endif +// ----------------------------------------------------------------------------- +// Energy Monitor +// ----------------------------------------------------------------------------- + +#if ENABLE_ENERGYMONITOR + + void energyMonitorSetup() { + monitor.initCurrent(CURRENT_PIN, REFERENCE_VOLTAGE, CURRENT_RATIO); + monitor.setPrecision(CURRENT_PRECISION); + } + + void energyMonitorLoop() { + + static unsigned long next_measurement = millis(); + static byte measurements = 0; + static double sum = 0; + + if (millis() > next_measurement) { + + double current = monitor.getCurrent(SAMPLES_X_MEASUREMENT); + sum += current; + ++measurements; + + #ifdef DEBUG + Serial.print("Power reading: "); + Serial.println(current * MAINS_VOLTAGE); + #endif + + if (measurements == MEASUREMENTS_X_MESSAGE) { + char buffer[8]; + sprintf(buffer, "%d", int(sum * MAINS_VOLTAGE / measurements)); + #ifdef DEBUG + Serial.print("Power sending: "); + Serial.println(buffer); + #endif + #if ENABLE_MQTT + mqtt.publish(mqttPowerTopic, buffer, MQTT_RETAIN); + #endif + sum = 0; + measurements = 0; + } + + next_measurement += MEASUREMENT_INTERVAL; + + } + + } + +#endif + // ----------------------------------------------------------------------------- // Hardware (buttons, LEDs,...) // ----------------------------------------------------------------------------- @@ -918,6 +1004,9 @@ void setup() { #if ENABLE_RF rfSetup(); #endif + #if ENABLE_ENERGYMONITOR + energyMonitorSetup(); + #endif } @@ -936,6 +1025,9 @@ void loop() { #if ENABLE_WEBSERVER webServerLoop(); #endif + #if ENABLE_ENERGYMONITOR + energyMonitorLoop(); + #endif hardwareLoop(); delay(1);