diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index 8d468394..4cff76a0 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -677,8 +677,8 @@ PROGMEM const char* const custom_reset_string[] = { #define I2C_SCL_PIN SCL // SCL GPIO (Sonoff => 14) #endif -#define I2C_CLOCK_STRETCH_TIME 50000 // BRZO clock stretch time -#define I2C_SCL_FREQUENCY 200 // BRZO SCL frequency +#define I2C_CLOCK_STRETCH_TIME 200 // BRZO clock stretch time +#define I2C_SCL_FREQUENCY 1000 // BRZO SCL frequency #define I2C_CLEAR_BUS 0 // Clear I2C bus at boot // ----------------------------------------------------------------------------- @@ -773,7 +773,7 @@ PROGMEM const char* const custom_reset_string[] = { #define SENSOR_VOLTAGE_DECIMALS 0 #define SENSOR_POWER_DECIMALS 0 #define SENSOR_POWER_FACTOR_DECIMALS 0 -#define SENSOR_ENERGY_DECIMALS 3 +#define SENSOR_ENERGY_DECIMALS 0 #define SENSOR_UNKNOWN_TOPIC "unknown" #define SENSOR_TEMPERATURE_TOPIC "temperature" diff --git a/code/espurna/config/sensors.h b/code/espurna/config/sensors.h index 5c705b02..44df8056 100644 --- a/code/espurna/config/sensors.h +++ b/code/espurna/config/sensors.h @@ -142,10 +142,9 @@ // Energy Monitor //-------------------------------------------------------------------------------- -#define EMON_FILTER_SPEED 512 - -#define EMON_MODE_SAMPLES 1 -#define EMON_MODE_MSECONDS 2 +#define EMON_MAX_SAMPLES 1500 // Max number of samples to get +#define EMON_MAX_TIME 200 // Max time in ms to sample +#define EMON_MAINS_VOLTAGE 230 // Mains voltage //-------------------------------------------------------------------------------- // Energy Monitor based on interval analog GPIO @@ -156,20 +155,13 @@ #define EMON_ANALOG_SUPPORT 0 // Do not build support by default #endif -#define EMON_ANALOG_MAINS_VOLTAGE 230 // Mains voltage #define EMON_ANALOG_CURRENT_RATIO 30 // Current ratio in the clamp (30V/1A) #define EMON_ANALOG_ADC_BITS 10 // ADC depth #define EMON_ANALOG_REFERENCE_VOLTAGE 3.3 // Reference voltage of the ADC -#define EMON_ANALOG_READ_VALUE 1000 -#define EMON_ANALOG_READ_MODE EMON_MODE_SAMPLES - -#define EMON_ANALOG_WARMUP_VALUE 1000 -#define EMON_ANALOG_WARMUP_MODE EMON_MODE_MSECONDS - #if EMON_ANALOG_SUPPORT #undef ADC_VCC_ENABLED - #define ADC_VCC_ENABLED 0 + #define ADC_VCC_ENABLED 0 #endif //-------------------------------------------------------------------------------- @@ -188,12 +180,6 @@ #define EMON_ADC121_ADC_BITS 12 // ADC depth #define EMON_ADC121_REFERENCE_VOLTAGE 3.3 // Reference voltage of the ADC -#define EMON_ADC121_READ_VALUE 200 -#define EMON_ADC121_READ_MODE EMON_MODE_MSECONDS - -#define EMON_ADC121_WARMUP_VALUE 1000 -#define EMON_ADC121_WARMUP_MODE EMON_MODE_MSECONDS - //-------------------------------------------------------------------------------- // Internal power montior // Enable support by passing ADC_VCC_ENABLED=1 build flag diff --git a/code/espurna/power_emon.ino b/code/espurna/power_emon.ino index f0593b47..9e800c9f 100644 --- a/code/espurna/power_emon.ino +++ b/code/espurna/power_emon.ino @@ -53,7 +53,7 @@ unsigned int currentCallback() { #if I2C_USE_BRZO uint8_t buffer[2]; - i2cStart(ADC121_I2C_ADDRESS); + brzo_i2c_start_transaction(ADC121_I2C_ADDRESS, I2C_SCL_FREQUENCY); buffer[0] = ADC121_REG_RESULT; brzo_i2c_write(buffer, 1, false); brzo_i2c_read(buffer, 2, false); diff --git a/code/espurna/sensor.ino b/code/espurna/sensor.ino index e057de19..401421e0 100644 --- a/code/espurna/sensor.ino +++ b/code/espurna/sensor.ino @@ -240,12 +240,12 @@ void sensorInit() { #if EMON_ANALOG_SUPPORT #include "sensors/EmonAnalogSensor.h" - sensorRegister(new EmonAnalogSensor(A0, EMON_ANALOG_MAINS_VOLTAGE, EMON_ANALOG_ADC_BITS, EMON_ANALOG_REFERENCE_VOLTAGE, EMON_ANALOG_CURRENT_RATIO)); + sensorRegister(new EmonAnalogSensor(A0, EMON_MAINS_VOLTAGE, EMON_ANALOG_ADC_BITS, EMON_ANALOG_REFERENCE_VOLTAGE, EMON_ANALOG_CURRENT_RATIO)); #endif #if EMON_ADC121_SUPPORT #include "sensors/EmonADC121Sensor.h" - sensorRegister(new EmonADC121Sensor(EMON_ADC121_I2C_ADDRESS, EMON_ANALOG_MAINS_VOLTAGE, EMON_ANALOG_ADC_BITS, EMON_ANALOG_REFERENCE_VOLTAGE, EMON_ANALOG_CURRENT_RATIO)); + sensorRegister(new EmonADC121Sensor(EMON_ADC121_I2C_ADDRESS, EMON_MAINS_VOLTAGE, EMON_ADC121_ADC_BITS, EMON_ADC121_REFERENCE_VOLTAGE, EMON_ADC121_CURRENT_RATIO)); #endif #if COUNTER_SUPPORT diff --git a/code/espurna/sensors/EmonADC121Sensor.h b/code/espurna/sensors/EmonADC121Sensor.h index 352884ff..d46f544e 100644 --- a/code/espurna/sensors/EmonADC121Sensor.h +++ b/code/espurna/sensors/EmonADC121Sensor.h @@ -32,6 +32,7 @@ class EmonADC121Sensor : public EmonSensor { // Cache _address = address; + _count = 4; // Init sensor #if I2C_USE_BRZO @@ -49,7 +50,7 @@ class EmonADC121Sensor : public EmonSensor { #endif // warmup - read(EMON_ADC121_WARMUP_VALUE, EMON_ADC121_WARMUP_MODE, _address); + read(_address); } @@ -70,6 +71,8 @@ class EmonADC121Sensor : public EmonSensor { _error = SENSOR_ERROR_OK; if (index == 0) return MAGNITUDE_CURRENT; if (index == 1) return MAGNITUDE_POWER_APPARENT; + if (index == 2) return MAGNITUDE_ENERGY; + if (index == 3) return MAGNITUDE_ENERGY_DELTA; _error = SENSOR_ERROR_OUT_OF_RANGE; return MAGNITUDE_NONE; } @@ -82,13 +85,19 @@ class EmonADC121Sensor : public EmonSensor { // Cache the value static unsigned long last = 0; static double current = 0; + static unsigned long energy_delta = 0; + if ((last == 0) || (millis() - last > 1000)) { - current = read(EMON_ADC121_READ_VALUE, EMON_ADC121_READ_MODE, _address); + current = read(_address); + energy_delta = current * _voltage * (millis() - last) / 1000; + _energy += energy_delta; last = millis(); } if (index == 0) return current; if (index == 1) return current * _voltage; + if (index == 2) return _energy; + if (index == 3) return energy_delta; _error = SENSOR_ERROR_OUT_OF_RANGE; return 0; @@ -124,6 +133,7 @@ class EmonADC121Sensor : public EmonSensor { } unsigned char _address; + unsigned long _energy = 0; }; diff --git a/code/espurna/sensors/EmonAnalogSensor.h b/code/espurna/sensors/EmonAnalogSensor.h index 404d8ab6..3d0d2769 100644 --- a/code/espurna/sensors/EmonAnalogSensor.h +++ b/code/espurna/sensors/EmonAnalogSensor.h @@ -16,12 +16,13 @@ class EmonAnalogSensor : public EmonSensor { // Cache _gpio = gpio; + _count = 4; // Prepare GPIO pinMode(gpio, INPUT); // warmup - read(EMON_ANALOG_WARMUP_VALUE, EMON_ANALOG_WARMUP_MODE, _gpio); + read(_gpio); } @@ -42,6 +43,8 @@ class EmonAnalogSensor : public EmonSensor { _error = SENSOR_ERROR_OK; if (index == 0) return MAGNITUDE_CURRENT; if (index == 1) return MAGNITUDE_POWER_APPARENT; + if (index == 2) return MAGNITUDE_ENERGY; + if (index == 3) return MAGNITUDE_ENERGY_DELTA; _error = SENSOR_ERROR_OUT_OF_RANGE; return MAGNITUDE_NONE; } @@ -54,13 +57,19 @@ class EmonAnalogSensor : public EmonSensor { // Cache the value static unsigned long last = 0; static double current = 0; + static unsigned long energy_delta = 0; + if ((last == 0) || (millis() - last > 1000)) { - current = read(EMON_ANALOG_READ_VALUE, EMON_ANALOG_READ_MODE, _gpio); + current = read(_gpio); + energy_delta = current * _voltage * (millis() - last) / 1000; + _energy += energy_delta; last = millis(); } if (index == 0) return current; if (index == 1) return current * _voltage; + if (index == 2) return _energy; + if (index == 3) return energy_delta; _error = SENSOR_ERROR_OUT_OF_RANGE; return 0; @@ -74,6 +83,7 @@ class EmonAnalogSensor : public EmonSensor { } unsigned char _gpio; + unsigned long _energy = 0; }; diff --git a/code/espurna/sensors/EmonSensor.h b/code/espurna/sensors/EmonSensor.h index b2bbb130..1ec3f1a3 100644 --- a/code/espurna/sensors/EmonSensor.h +++ b/code/espurna/sensors/EmonSensor.h @@ -7,7 +7,7 @@ #include "Arduino.h" #include "BaseSensor.h" -#define EMON_DEBUG 1 +#define EMON_DEBUG 0 class EmonSensor : public BaseSensor { @@ -19,7 +19,6 @@ class EmonSensor : public BaseSensor { _voltage = voltage; _adc_counts = 1 << bits; _pivot = _adc_counts >> 1; - _count = 2; // Calculate factor _current_factor = ratio * ref / _adc_counts; @@ -30,7 +29,7 @@ class EmonSensor : public BaseSensor { #if EMON_DEBUG Serial.print("[EMON] Current ratio: "); Serial.println(ratio); Serial.print("[EMON] Ref. Voltage: "); Serial.println(_voltage); - Serial.print("[EMON] ADC Couns: "); Serial.println(_adc_counts); + Serial.print("[EMON] ADC Counts: "); Serial.println(_adc_counts); Serial.print("[EMON] Current factor: "); Serial.println(_current_factor); Serial.print("[EMON] Multiplier: "); Serial.println(_multiplier); #endif @@ -53,7 +52,7 @@ class EmonSensor : public BaseSensor { } } - double read(unsigned long value, unsigned char mode, unsigned char port) { + double read(unsigned char port) { int sample; int max = 0; @@ -61,10 +60,8 @@ class EmonSensor : public BaseSensor { double filtered; double sum = 0; - unsigned long start = millis(); - unsigned long samples = 0; - - while (true) { + unsigned long time_span = millis(); + for (unsigned long i=0; i<_samples; i++) { // Read analog value sample = readADC(port); @@ -72,38 +69,30 @@ class EmonSensor : public BaseSensor { if (sample < min) min = sample; // Digital low pass filter extracts the VDC offset - _pivot = (_pivot + (sample - _pivot) / EMON_FILTER_SPEED); + _pivot = (_pivot + (sample - _pivot) / _adc_counts); filtered = sample - _pivot; // Root-mean-square method sum += (filtered * filtered); - ++samples; - - // Exit condition - if (mode == EMON_MODE_SAMPLES) { - if (samples >= value) break; - } else { - if (millis() - start >= value) break; - } - - yield(); } + time_span = millis() - time_span; // Quick fix if (_pivot < min || max < _pivot) { _pivot = (max + min) / 2.0; } - double rms = samples > 0 ? sqrt(sum / samples) : 0; + // Calculate current + double rms = _samples > 0 ? sqrt(sum / _samples) : 0; double current = _current_factor * rms; - current = (double) (round(current * _multiplier) - 1) / _multiplier; + current = (double) (int(current * _multiplier) - 1) / _multiplier; if (current < 0) current = 0; #if EMON_DEBUG - Serial.print("[EMON] Total samples: "); Serial.println(samples); - Serial.print("[EMON] Total time (ms): "); Serial.println(millis() - start); - Serial.print("[EMON] Sample frequency (1/s): "); Serial.println(1000 * samples / (millis() - start)); + Serial.print("[EMON] Total samples: "); Serial.println(_samples); + Serial.print("[EMON] Total time (ms): "); Serial.println(time_span); + Serial.print("[EMON] Sample frequency (Hz): "); Serial.println(1000 * _samples / time_span); Serial.print("[EMON] Max value: "); Serial.println(max); Serial.print("[EMON] Min value: "); Serial.println(min); Serial.print("[EMON] Midpoint value: "); Serial.println(_pivot); @@ -111,6 +100,11 @@ class EmonSensor : public BaseSensor { Serial.print("[EMON] Current: "); Serial.println(current); #endif + // Check timing + if (time_span > EMON_MAX_TIME) { + _samples = (_samples * EMON_MAX_TIME) / time_span; + } + return current; } @@ -121,5 +115,7 @@ class EmonSensor : public BaseSensor { double _current_factor; double _pivot; + unsigned long _samples = EMON_MAX_SAMPLES; + };