Browse Source

Option to save total energy in EEPROM after X reports, disabled by default

ech1560
Xose Pérez 6 years ago
parent
commit
d546a069e2
14 changed files with 5191 additions and 5002 deletions
  1. +8
    -0
      code/espurna/config/sensors.h
  2. BIN
      code/espurna/data/index.all.html.gz
  3. BIN
      code/espurna/data/index.sensor.html.gz
  4. +40
    -0
      code/espurna/filters/LastFilter.h
  5. +90
    -21
      code/espurna/sensor.ino
  6. +2
    -2
      code/espurna/sensors/CSE7766Sensor.h
  7. +15
    -0
      code/espurna/sensors/ECH1560Sensor.h
  8. +5
    -0
      code/espurna/sensors/EmonSensor.h
  9. +4
    -2
      code/espurna/sensors/HLW8012Sensor.h
  10. +12
    -1
      code/espurna/sensors/PZEM004TSensor.h
  11. +21
    -6
      code/espurna/sensors/V9261FSensor.h
  12. +3052
    -3046
      code/espurna/static/index.all.html.gz.h
  13. +1929
    -1923
      code/espurna/static/index.sensor.html.gz.h
  14. +13
    -1
      code/html/index.html

+ 8
- 0
code/espurna/config/sensors.h View File

@ -36,6 +36,14 @@
#define HUMIDITY_MIN_CHANGE 0 // Minimum humidity change to report #define HUMIDITY_MIN_CHANGE 0 // Minimum humidity change to report
#endif #endif
#ifndef SENSOR_SAVE_EVERY
#define SENSOR_SAVE_EVERY 0 // Save accumulating values to EEPROM (atm only energy)
// A 0 means do not save and it's the default value
// A number different from 0 means it should store the value in EEPROM
// after these many reports
// Warning: this might wear out flash fast!
#endif
#define SENSOR_PUBLISH_ADDRESSES 0 // Publish sensor addresses #define SENSOR_PUBLISH_ADDRESSES 0 // Publish sensor addresses
#define SENSOR_ADDRESS_TOPIC "address" // Topic to publish sensor addresses #define SENSOR_ADDRESS_TOPIC "address" // Topic to publish sensor addresses


BIN
code/espurna/data/index.all.html.gz View File


BIN
code/espurna/data/index.sensor.html.gz View File


+ 40
- 0
code/espurna/filters/LastFilter.h View File

@ -0,0 +1,40 @@
// -----------------------------------------------------------------------------
// Last Filter
// Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT
#pragma once
#include "BaseFilter.h"
class LastFilter : public BaseFilter {
public:
void add(double value) {
_value = value;
}
unsigned char count() {
return 1;
}
void reset() {
_value = 0;
}
double result() {
return _value;
}
void resize(unsigned char size) {}
protected:
double _value = 0;
};
#endif // SENSOR_SUPPORT

+ 90
- 21
code/espurna/sensor.ino View File

@ -9,6 +9,7 @@ Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
#if SENSOR_SUPPORT #if SENSOR_SUPPORT
#include <vector> #include <vector>
#include "filters/LastFilter.h"
#include "filters/MaxFilter.h" #include "filters/MaxFilter.h"
#include "filters/MedianFilter.h" #include "filters/MedianFilter.h"
#include "filters/MovingAverageFilter.h" #include "filters/MovingAverageFilter.h"
@ -34,6 +35,7 @@ unsigned char _counts[MAGNITUDE_MAX];
bool _sensor_realtime = API_REAL_TIME_VALUES; bool _sensor_realtime = API_REAL_TIME_VALUES;
unsigned long _sensor_read_interval = 1000 * SENSOR_READ_INTERVAL; unsigned long _sensor_read_interval = 1000 * SENSOR_READ_INTERVAL;
unsigned char _sensor_report_every = SENSOR_REPORT_EVERY; unsigned char _sensor_report_every = SENSOR_REPORT_EVERY;
unsigned char _sensor_save_every = SENSOR_SAVE_EVERY;
unsigned char _sensor_power_units = SENSOR_POWER_UNITS; unsigned char _sensor_power_units = SENSOR_POWER_UNITS;
unsigned char _sensor_energy_units = SENSOR_ENERGY_UNITS; unsigned char _sensor_energy_units = SENSOR_ENERGY_UNITS;
unsigned char _sensor_temperature_units = SENSOR_TEMPERATURE_UNITS; unsigned char _sensor_temperature_units = SENSOR_TEMPERATURE_UNITS;
@ -100,7 +102,7 @@ bool _sensorWebSocketOnReceive(const char * key, JsonVariant& value) {
if (strncmp(key, "sns", 3) == 0) return true; if (strncmp(key, "sns", 3) == 0) return true;
if (strncmp(key, "tmp", 3) == 0) return true; if (strncmp(key, "tmp", 3) == 0) return true;
if (strncmp(key, "hum", 3) == 0) return true; if (strncmp(key, "hum", 3) == 0) return true;
if (strncmp(key, "energy", 6) == 0) return true;
if (strncmp(key, "ene", 3) == 0) return true;
return false; return false;
} }
@ -127,8 +129,8 @@ void _sensorWebSocketSendData(JsonObject& root) {
element["error"] = magnitude.sensor->error(); element["error"] = magnitude.sensor->error();
if (magnitude.type == MAGNITUDE_ENERGY) { if (magnitude.type == MAGNITUDE_ENERGY) {
if (_sensor_energy_reset_ts.length() == 0) _sensorReset();
element["description"] = magnitude.sensor->slot(magnitude.local) + _sensor_energy_reset_ts;
if (_sensor_energy_reset_ts.length() == 0) _sensorResetTS();
element["description"] = magnitude.sensor->slot(magnitude.local) + String(" (since ") + _sensor_energy_reset_ts + String(")");
} else { } else {
element["description"] = magnitude.sensor->slot(magnitude.local); element["description"] = magnitude.sensor->slot(magnitude.local);
} }
@ -196,12 +198,13 @@ void _sensorWebSocketStart(JsonObject& root) {
root["snsVisible"] = 1; root["snsVisible"] = 1;
//root["apiRealTime"] = _sensor_realtime; //root["apiRealTime"] = _sensor_realtime;
root["pwrUnits"] = _sensor_power_units; root["pwrUnits"] = _sensor_power_units;
root["energyUnits"] = _sensor_energy_units;
root["eneUnits"] = _sensor_energy_units;
root["tmpUnits"] = _sensor_temperature_units; root["tmpUnits"] = _sensor_temperature_units;
root["tmpCorrection"] = _sensor_temperature_correction; root["tmpCorrection"] = _sensor_temperature_correction;
root["humCorrection"] = _sensor_humidity_correction; root["humCorrection"] = _sensor_humidity_correction;
root["snsRead"] = _sensor_read_interval / 1000; root["snsRead"] = _sensor_read_interval / 1000;
root["snsReport"] = _sensor_report_every; root["snsReport"] = _sensor_report_every;
root["snsSave"] = _sensor_save_every;
} }
/* /*
@ -293,11 +296,18 @@ void _sensorPost() {
} }
} }
void _sensorReset() {
void _sensorResetTS() {
#if NTP_SUPPORT #if NTP_SUPPORT
if (ntpSynced()) { if (ntpSynced()) {
_sensor_energy_reset_ts = String(" (since ") + ntpDateTime() + String(")");
if (_sensor_energy_reset_ts.length() == 0) {
_sensor_energy_reset_ts = ntpDateTime(now() - millis() / 1000);
} else {
_sensor_energy_reset_ts = ntpDateTime(now());
}
} else {
_sensor_energy_reset_ts = String();
} }
setSetting("snsResetTS", _sensor_energy_reset_ts);
#endif #endif
} }
@ -613,6 +623,7 @@ void _sensorCallback(unsigned char i, unsigned char type, double value) {
void _sensorInit() { void _sensorInit() {
_sensors_ready = true; _sensors_ready = true;
_sensor_save_every = getSetting("snsSave", 0).toInt();
for (unsigned char i=0; i<_sensors.size(); i++) { for (unsigned char i=0; i<_sensors.size(); i++) {
@ -642,9 +653,11 @@ void _sensorInit() {
new_magnitude.filtered = 0; new_magnitude.filtered = 0;
new_magnitude.reported = 0; new_magnitude.reported = 0;
new_magnitude.min_change = 0; new_magnitude.min_change = 0;
if (type == MAGNITUDE_DIGITAL) {
if (MAGNITUDE_ENERGY == type) {
new_magnitude.filter = new LastFilter();
} else if (MAGNITUDE_DIGITAL == type) {
new_magnitude.filter = new MaxFilter(); new_magnitude.filter = new MaxFilter();
} else if (type == MAGNITUDE_COUNT || type == MAGNITUDE_GEIGER_CPM|| type == MAGNITUDE_GEIGER_SIEVERT) { // For geiger counting moving average filter is the most appropriate if needed at all.
} else if (MAGNITUDE_COUNT == type || MAGNITUDE_GEIGER_CPM == type || MAGNITUDE_GEIGER_SIEVERT == type) { // For geiger counting moving average filter is the most appropriate if needed at all.
new_magnitude.filter = new MovingAverageFilter(); new_magnitude.filter = new MovingAverageFilter();
} else { } else {
new_magnitude.filter = new MedianFilter(); new_magnitude.filter = new MedianFilter();
@ -671,6 +684,8 @@ void _sensorInit() {
EmonAnalogSensor * sensor = (EmonAnalogSensor *) _sensors[i]; EmonAnalogSensor * sensor = (EmonAnalogSensor *) _sensors[i];
sensor->setCurrentRatio(0, getSetting("pwrRatioC", EMON_CURRENT_RATIO).toFloat()); sensor->setCurrentRatio(0, getSetting("pwrRatioC", EMON_CURRENT_RATIO).toFloat());
sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE).toInt()); sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE).toInt());
double value = (_sensor_save_every > 0) ? getSetting("eneTotal", 0).toInt() : 0;
if (value > 0) sensor->resetEnergy(0, value);
} }
#endif // EMON_ANALOG_SUPPORT #endif // EMON_ANALOG_SUPPORT
@ -692,6 +707,9 @@ void _sensorInit() {
value = getSetting("pwrRatioP", HLW8012_POWER_RATIO).toFloat(); value = getSetting("pwrRatioP", HLW8012_POWER_RATIO).toFloat();
if (value > 0) sensor->setPowerRatio(value); if (value > 0) sensor->setPowerRatio(value);
value = (_sensor_save_every > 0) ? getSetting("eneTotal", 0).toInt() : 0;
if (value > 0) sensor->resetEnergy(value);
} }
#endif // HLW8012_SUPPORT #endif // HLW8012_SUPPORT
@ -713,6 +731,9 @@ void _sensorInit() {
value = getSetting("pwrRatioP", 0).toFloat(); value = getSetting("pwrRatioP", 0).toFloat();
if (value > 0) sensor->setPowerRatio(value); if (value > 0) sensor->setPowerRatio(value);
value = (_sensor_save_every > 0) ? getSetting("eneTotal", 0).toInt() : 0;
if (value > 0) sensor->resetEnergy(value);
} }
#endif // CSE7766_SUPPORT #endif // CSE7766_SUPPORT
@ -726,12 +747,14 @@ void _sensorConfigure() {
// General sensor settings // General sensor settings
_sensor_read_interval = 1000 * constrain(getSetting("snsRead", SENSOR_READ_INTERVAL).toInt(), SENSOR_READ_MIN_INTERVAL, SENSOR_READ_MAX_INTERVAL); _sensor_read_interval = 1000 * constrain(getSetting("snsRead", SENSOR_READ_INTERVAL).toInt(), SENSOR_READ_MIN_INTERVAL, SENSOR_READ_MAX_INTERVAL);
_sensor_report_every = constrain(getSetting("snsReport", SENSOR_REPORT_EVERY).toInt(), SENSOR_REPORT_MIN_EVERY, SENSOR_REPORT_MAX_EVERY); _sensor_report_every = constrain(getSetting("snsReport", SENSOR_REPORT_EVERY).toInt(), SENSOR_REPORT_MIN_EVERY, SENSOR_REPORT_MAX_EVERY);
_sensor_save_every = getSetting("snsSave", SENSOR_SAVE_EVERY).toInt();
_sensor_realtime = getSetting("apiRealTime", API_REAL_TIME_VALUES).toInt() == 1; _sensor_realtime = getSetting("apiRealTime", API_REAL_TIME_VALUES).toInt() == 1;
_sensor_power_units = getSetting("pwrUnits", SENSOR_POWER_UNITS).toInt(); _sensor_power_units = getSetting("pwrUnits", SENSOR_POWER_UNITS).toInt();
_sensor_energy_units = getSetting("energyUnits", SENSOR_ENERGY_UNITS).toInt();
_sensor_energy_units = getSetting("eneUnits", SENSOR_ENERGY_UNITS).toInt();
_sensor_temperature_units = getSetting("tmpUnits", SENSOR_TEMPERATURE_UNITS).toInt(); _sensor_temperature_units = getSetting("tmpUnits", SENSOR_TEMPERATURE_UNITS).toInt();
_sensor_temperature_correction = getSetting("tmpCorrection", SENSOR_TEMPERATURE_CORRECTION).toFloat(); _sensor_temperature_correction = getSetting("tmpCorrection", SENSOR_TEMPERATURE_CORRECTION).toFloat();
_sensor_humidity_correction = getSetting("humCorrection", SENSOR_HUMIDITY_CORRECTION).toFloat(); _sensor_humidity_correction = getSetting("humCorrection", SENSOR_HUMIDITY_CORRECTION).toFloat();
_sensor_energy_reset_ts = getSetting("snsResetTS", "");
// Specific sensor settings // Specific sensor settings
for (unsigned char i=0; i<_sensors.size(); i++) { for (unsigned char i=0; i<_sensors.size(); i++) {
@ -755,7 +778,8 @@ void _sensorConfigure() {
if (getSetting("pwrResetE", 0).toInt() == 1) { if (getSetting("pwrResetE", 0).toInt() == 1) {
sensor->resetEnergy(); sensor->resetEnergy();
_sensorReset();
delSetting("eneTotal");
_sensorResetTS();
} }
sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE).toInt()); sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE).toInt());
@ -769,7 +793,8 @@ void _sensorConfigure() {
EmonADC121Sensor * sensor = (EmonADC121Sensor *) _sensors[i]; EmonADC121Sensor * sensor = (EmonADC121Sensor *) _sensors[i];
if (getSetting("pwrResetE", 0).toInt() == 1) { if (getSetting("pwrResetE", 0).toInt() == 1) {
sensor->resetEnergy(); sensor->resetEnergy();
_sensorReset();
delSetting("eneTotal");
_sensorResetTS();
} }
} }
#endif #endif
@ -779,7 +804,8 @@ void _sensorConfigure() {
EmonADS1X15Sensor * sensor = (EmonADS1X15Sensor *) _sensors[i]; EmonADS1X15Sensor * sensor = (EmonADS1X15Sensor *) _sensors[i];
if (getSetting("pwrResetE", 0).toInt() == 1) { if (getSetting("pwrResetE", 0).toInt() == 1) {
sensor->resetEnergy(); sensor->resetEnergy();
_sensorReset();
delSetting("eneTotal");
_sensorResetTS();
} }
} }
#endif #endif
@ -809,7 +835,8 @@ void _sensorConfigure() {
if (getSetting("pwrResetE", 0).toInt() == 1) { if (getSetting("pwrResetE", 0).toInt() == 1) {
sensor->resetEnergy(); sensor->resetEnergy();
_sensorReset();
delSetting("eneTotal");
_sensorResetTS();
} }
if (getSetting("pwrResetCalibration", 0).toInt() == 1) { if (getSetting("pwrResetCalibration", 0).toInt() == 1) {
@ -847,7 +874,8 @@ void _sensorConfigure() {
if (getSetting("pwrResetE", 0).toInt() == 1) { if (getSetting("pwrResetE", 0).toInt() == 1) {
sensor->resetEnergy(); sensor->resetEnergy();
_sensorReset();
delSetting("eneTotal");
_sensorResetTS();
} }
if (getSetting("pwrResetCalibration", 0).toInt() == 1) { if (getSetting("pwrResetCalibration", 0).toInt() == 1) {
@ -868,6 +896,11 @@ void _sensorConfigure() {
_magnitudes[i].filter->resize(_sensor_report_every); _magnitudes[i].filter->resize(_sensor_report_every);
} }
// General processing
if (0 == _sensor_save_every) {
delSetting("eneTotal");
}
// Save settings // Save settings
delSetting("pwrExpectedP"); delSetting("pwrExpectedP");
delSetting("pwrExpectedC"); delSetting("pwrExpectedC");
@ -1024,6 +1057,7 @@ void sensorSetup() {
// Backwards compatibility // Backwards compatibility
moveSetting("powerUnits", "pwrUnits"); moveSetting("powerUnits", "pwrUnits");
moveSetting("energyUnits", "eneUnits");
// Load sensors // Load sensors
_sensorLoad(); _sensorLoad();
@ -1074,6 +1108,7 @@ void sensorLoop() {
// Check if we should read new data // Check if we should read new data
static unsigned long last_update = 0; static unsigned long last_update = 0;
static unsigned long report_count = 0; static unsigned long report_count = 0;
static unsigned long save_count = 0;
if (millis() - last_update > _sensor_read_interval) { if (millis() - last_update > _sensor_read_interval) {
last_update = millis(); last_update = millis();
@ -1097,6 +1132,10 @@ void sensorLoop() {
if (magnitude.sensor->status()) { if (magnitude.sensor->status()) {
// -------------------------------------------------------------
// Instant value
// -------------------------------------------------------------
current = magnitude.sensor->value(magnitude.local); current = magnitude.sensor->value(magnitude.local);
// Completely remove spurious values if relay is OFF // Completely remove spurious values if relay is OFF
@ -1113,17 +1152,26 @@ void sensorLoop() {
} }
#endif #endif
// -------------------------------------------------------------
// Processing (filters)
// -------------------------------------------------------------
magnitude.filter->add(current); magnitude.filter->add(current);
// Special case
if (magnitude.type == MAGNITUDE_COUNT) {
// Special case for MovingAvergaeFilter
if (MAGNITUDE_COUNT == magnitude.type ||
MAGNITUDE_GEIGER_CPM ==magnitude. type ||
MAGNITUDE_GEIGER_SIEVERT == magnitude.type) {
current = magnitude.filter->result(); current = magnitude.filter->result();
} }
current = _magnitudeProcess(magnitude.type, current); current = _magnitudeProcess(magnitude.type, current);
_magnitudes[i].current = current; _magnitudes[i].current = current;
// -------------------------------------------------------------
// Debug // Debug
// -------------------------------------------------------------
#if SENSOR_DEBUG #if SENSOR_DEBUG
{ {
char buffer[64]; char buffer[64];
@ -1137,8 +1185,12 @@ void sensorLoop() {
} }
#endif // SENSOR_DEBUG #endif // SENSOR_DEBUG
// Time to report (we do it every _sensor_report_every readings)
if (report_count == 0) {
// -------------------------------------------------------------
// Report
// (we do it every _sensor_report_every readings)
// -------------------------------------------------------------
if (0 == report_count) {
filtered = magnitude.filter->result(); filtered = magnitude.filter->result();
magnitude.filter->reset(); magnitude.filter->reset();
@ -1147,13 +1199,30 @@ void sensorLoop() {
// Check if there is a minimum change threshold to report // Check if there is a minimum change threshold to report
if (fabs(filtered - magnitude.reported) >= magnitude.min_change) { if (fabs(filtered - magnitude.reported) >= magnitude.min_change) {
_magnitudes[i].reported = filtered; _magnitudes[i].reported = filtered;
_sensorReport(i, filtered); _sensorReport(i, filtered);
} // if (fabs(filtered - magnitude.reported) >= magnitude.min_change) } // if (fabs(filtered - magnitude.reported) >= magnitude.min_change)
// -------------------------------------------------------------
// Saving to EEPROM
// (we do it every _sensor_save_every readings)
// -------------------------------------------------------------
if (_sensor_save_every > 0) {
save_count = (save_count + 1) % _sensor_save_every;
if (0 == save_count) {
if (MAGNITUDE_ENERGY == magnitude.type) {
setSetting("eneTotal", current);
saveSettings();
}
} // if (0 == save_count)
} // if (_sensor_save_every > 0)
} // if (report_count == 0) } // if (report_count == 0)
} // if (magnitude.sensor->status()) } // if (magnitude.sensor->status())
} // for (unsigned char i=0; i<_magnitudes.size(); i++) } // for (unsigned char i=0; i<_magnitudes.size(); i++)


+ 2
- 2
code/espurna/sensors/CSE7766Sensor.h View File

@ -102,8 +102,8 @@ class CSE7766Sensor : public BaseSensor {
_ratioC = _ratioV = _ratioP = 1.0; _ratioC = _ratioV = _ratioP = 1.0;
} }
void resetEnergy() {
_energy = 0;
void resetEnergy(double value = 0) {
_energy = value;
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------


+ 15
- 0
code/espurna/sensors/ECH1560Sensor.h View File

@ -59,6 +59,12 @@ class ECH1560Sensor : public BaseSensor {
return _inverted; return _inverted;
} }
// ---------------------------------------------------------------------
void resetEnergy(double value = 0) {
_energy = value;
}
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Sensor API // Sensor API
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -106,6 +112,7 @@ class ECH1560Sensor : public BaseSensor {
if (index == 0) return MAGNITUDE_CURRENT; if (index == 0) return MAGNITUDE_CURRENT;
if (index == 1) return MAGNITUDE_VOLTAGE; if (index == 1) return MAGNITUDE_VOLTAGE;
if (index == 2) return MAGNITUDE_POWER_APPARENT; if (index == 2) return MAGNITUDE_POWER_APPARENT;
if (index == 3) return MAGNITUDE_ENERGY;
return MAGNITUDE_NONE; return MAGNITUDE_NONE;
} }
@ -114,6 +121,7 @@ class ECH1560Sensor : public BaseSensor {
if (index == 0) return _current; if (index == 0) return _current;
if (index == 1) return _voltage; if (index == 1) return _voltage;
if (index == 2) return _apparent; if (index == 2) return _apparent;
if (index == 3) return _energy;
return 0; return 0;
} }
@ -260,6 +268,12 @@ class ECH1560Sensor : public BaseSensor {
_apparent = ( (float) byte1 * 255 + (float) byte2 + (float) byte3 / 255.0) / 2; _apparent = ( (float) byte1 * 255 + (float) byte2 + (float) byte3 / 255.0) / 2;
_current = _apparent / _voltage; _current = _apparent / _voltage;
static unsigned long last = 0;
if (last > 0) {
_energy += (_apparent * (millis() - last) / 1000);
}
last = millis();
_dosync = false; _dosync = false;
} }
@ -287,6 +301,7 @@ class ECH1560Sensor : public BaseSensor {
double _apparent = 0; double _apparent = 0;
double _voltage = 0; double _voltage = 0;
double _current = 0; double _current = 0;
double _energy = 0;
unsigned char _data[24]; unsigned char _data[24];


+ 5
- 0
code/espurna/sensors/EmonSensor.h View File

@ -55,6 +55,11 @@ class EmonSensor : public I2CSensor {
} }
} }
void resetEnergy(unsigned char channel, double value = 0) {
if (channel >= _channels) return;
_energy[i] = value;
}
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
void setVoltage(double voltage) { void setVoltage(double voltage) {


+ 4
- 2
code/espurna/sensors/HLW8012Sensor.h View File

@ -48,7 +48,8 @@ class HLW8012Sensor : public BaseSensor {
_hlw8012->resetMultipliers(); _hlw8012->resetMultipliers();
} }
void resetEnergy() {
void resetEnergy(double value = 0) {
_energy_offset = value;
_hlw8012->resetEnergy(); _hlw8012->resetEnergy();
} }
@ -200,7 +201,7 @@ class HLW8012Sensor : public BaseSensor {
if (index == 3) return _hlw8012->getReactivePower(); if (index == 3) return _hlw8012->getReactivePower();
if (index == 4) return _hlw8012->getApparentPower(); if (index == 4) return _hlw8012->getApparentPower();
if (index == 5) return 100 * _hlw8012->getPowerFactor(); if (index == 5) return 100 * _hlw8012->getPowerFactor();
if (index == 6) return _hlw8012->getEnergy();
if (index == 6) return (_energy_offset + _hlw8012->getEnergy());
return 0; return 0;
} }
@ -261,6 +262,7 @@ class HLW8012Sensor : public BaseSensor {
unsigned char _cf = GPIO_NONE; unsigned char _cf = GPIO_NONE;
unsigned char _cf1 = GPIO_NONE; unsigned char _cf1 = GPIO_NONE;
bool _sel_current = true; bool _sel_current = true;
double _energy_offset = 0;
HLW8012 * _hlw8012 = NULL; HLW8012 * _hlw8012 = NULL;


+ 12
- 1
code/espurna/sensors/PZEM004TSensor.h View File

@ -59,6 +59,16 @@ class PZEM004TSensor : public BaseSensor {
return _pin_tx; return _pin_tx;
} }
// ---------------------------------------------------------------------
void resetEnergy(double value = 0) {
if (_ready) {
_energy_offset = value - (_pzem->energy(_ip) * 3600);
} else {
_energy_offset = value;
}
}
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Sensor API // Sensor API
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -117,7 +127,7 @@ class PZEM004TSensor : public BaseSensor {
if (index == 0) response = _pzem->current(_ip); if (index == 0) response = _pzem->current(_ip);
if (index == 1) response = _pzem->voltage(_ip); if (index == 1) response = _pzem->voltage(_ip);
if (index == 2) response = _pzem->power(_ip); if (index == 2) response = _pzem->power(_ip);
if (index == 3) response = _pzem->energy(_ip) * 3600;
if (index == 3) response = _energy_offset + (_pzem->energy(_ip) * 3600);
if (response < 0) response = 0; if (response < 0) response = 0;
return response; return response;
} }
@ -133,6 +143,7 @@ class PZEM004TSensor : public BaseSensor {
IPAddress _ip; IPAddress _ip;
HardwareSerial * _serial = NULL; HardwareSerial * _serial = NULL;
PZEM004T * _pzem = NULL; PZEM004T * _pzem = NULL;
double _energy_offset = 0;
}; };


+ 21
- 6
code/espurna/sensors/V9261FSensor.h View File

@ -56,6 +56,12 @@ class V9261FSensor : public BaseSensor {
return _inverted; return _inverted;
} }
// ---------------------------------------------------------------------
void resetEnergy(double value = 0) {
_energy = value;
}
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Sensor API // Sensor API
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -106,6 +112,7 @@ class V9261FSensor : public BaseSensor {
if (index == 3) return MAGNITUDE_POWER_REACTIVE; if (index == 3) return MAGNITUDE_POWER_REACTIVE;
if (index == 4) return MAGNITUDE_POWER_APPARENT; if (index == 4) return MAGNITUDE_POWER_APPARENT;
if (index == 5) return MAGNITUDE_POWER_FACTOR; if (index == 5) return MAGNITUDE_POWER_FACTOR;
if (index == 6) return MAGNITUDE_ENERGY;
return MAGNITUDE_NONE; return MAGNITUDE_NONE;
} }
@ -117,6 +124,7 @@ class V9261FSensor : public BaseSensor {
if (index == 3) return _reactive; if (index == 3) return _reactive;
if (index == 4) return _apparent; if (index == 4) return _apparent;
if (index == 5) return _apparent > 0 ? 100 * _active / _apparent : 100; if (index == 5) return _apparent > 0 ? 100 * _active / _apparent : 100;
if (index == 6) return _energy;
return 0; return 0;
} }
@ -130,6 +138,7 @@ class V9261FSensor : public BaseSensor {
static unsigned char state = 0; static unsigned char state = 0;
static unsigned long last = 0; static unsigned long last = 0;
static unsigned long ts = 0;
static bool found = false; static bool found = false;
static unsigned char index = 0; static unsigned char index = 0;
@ -138,10 +147,10 @@ class V9261FSensor : public BaseSensor {
while (_serial->available()) { while (_serial->available()) {
_serial->flush(); _serial->flush();
found = true; found = true;
last = millis();
ts = millis();
} }
if (found && (millis() - last > V9261F_SYNC_INTERVAL)) {
if (found && (millis() - ts > V9261F_SYNC_INTERVAL)) {
_serial->flush(); _serial->flush();
index = 0; index = 0;
state = 1; state = 1;
@ -164,7 +173,7 @@ class V9261FSensor : public BaseSensor {
_data[index] = _serial->read(); _data[index] = _serial->read();
if (index++ >= 19) { if (index++ >= 19) {
_serial->flush(); _serial->flush();
last = millis();
ts = millis();
state = 3; state = 3;
} }
} }
@ -208,9 +217,14 @@ class V9261FSensor : public BaseSensor {
_apparent = fs_sqrt(_reactive * _reactive + _active * _active); _apparent = fs_sqrt(_reactive * _reactive + _active * _active);
if (last > 0) {
_energy += (_active * (millis() - last) / 1000);
}
last = millis();
} }
last = millis();
ts = millis();
index = 0; index = 0;
state = 4; state = 4;
@ -218,10 +232,10 @@ class V9261FSensor : public BaseSensor {
while (_serial->available()) { while (_serial->available()) {
_serial->flush(); _serial->flush();
last = millis();
ts = millis();
} }
if (millis() - last > V9261F_SYNC_INTERVAL) {
if (millis() - ts > V9261F_SYNC_INTERVAL) {
state = 1; state = 1;
} }
@ -249,6 +263,7 @@ class V9261FSensor : public BaseSensor {
double _voltage = 0; double _voltage = 0;
double _current = 0; double _current = 0;
double _apparent = 0; double _apparent = 0;
double _energy = 0;
double _ratioP = V9261F_POWER_FACTOR; double _ratioP = V9261F_POWER_FACTOR;
double _ratioC = V9261F_CURRENT_FACTOR; double _ratioC = V9261F_CURRENT_FACTOR;


+ 3052
- 3046
code/espurna/static/index.all.html.gz.h
File diff suppressed because it is too large
View File


+ 1929
- 1923
code/espurna/static/index.sensor.html.gz.h
File diff suppressed because it is too large
View File


+ 13
- 1
code/html/index.html View File

@ -1183,6 +1183,18 @@
</div> </div>
</div> </div>
<div class="pure-g module module-pwr">
<label class="pure-u-1 pure-u-lg-1-4">Save every</label>
<div class="pure-u-1 pure-u-lg-1-4"><input name="snsSave" class="pure-u-1" type="number" min="0" step="1" max="200" /></div>
<div class="pure-u-0 pure-u-lg-1-2"></div>
<div class="pure-u-0 pure-u-lg-1-4"></div>
<div class="pure-u-1 pure-u-lg-3-4 hint">
Save aggregated data to EEPROM after these many reports. At the moment this only applies to total energy readings.
Please mind: saving data to EEPROM too often will wear out the flash memory quickly.
Set it to 0 to disable this feature (default value).
</div>
</div>
<div class="pure-g module module-pwr"> <div class="pure-g module module-pwr">
<label class="pure-u-1 pure-u-lg-1-4">Power units</label> <label class="pure-u-1 pure-u-lg-1-4">Power units</label>
<select name="pwrUnits" tabindex="16" class="pure-u-1 pure-u-lg-1-4"> <select name="pwrUnits" tabindex="16" class="pure-u-1 pure-u-lg-1-4">
@ -1191,7 +1203,7 @@
</select> </select>
</div> </div>
<div class="pure-g module module-hlw module-cse module-emon module-pzem">
<div class="pure-g module module-pwr">
<label class="pure-u-1 pure-u-lg-1-4">Energy units</label> <label class="pure-u-1 pure-u-lg-1-4">Energy units</label>
<select name="energyUnits" tabindex="16" class="pure-u-1 pure-u-lg-1-4"> <select name="energyUnits" tabindex="16" class="pure-u-1 pure-u-lg-1-4">
<option value="0">Joules (J)</option> <option value="0">Joules (J)</option>


Loading…
Cancel
Save