mirror of
https://github.com/xoseperez/espurna.git
synced 2026-03-09 17:57:08 +01:00
Added analog energy monitor sensor to new sensors module
This commit is contained in:
@@ -766,12 +766,27 @@ PROGMEM const char* const custom_reset_string[] = {
|
||||
|
||||
#define SENSOR_TEMPERATURE_DECIMALS 1
|
||||
#define SENSOR_HUMIDITY_DECIMALS 0
|
||||
#define SENSOR_PRESSURE_DECIMALS 2
|
||||
#define SENSOR_ANALOG_DECIMALS 0
|
||||
#define SENSOR_EVENTS_DECIMALS 0
|
||||
#define SENSOR_CURRENT_DECIMALS 3
|
||||
#define SENSOR_VOLTAGE_DECIMALS 0
|
||||
#define SENSOR_POWER_DECIMALS 0
|
||||
#define SENSOR_POWER_FACTOR_DECIMALS 0
|
||||
#define SENSOR_ENERGY_DECIMALS 3
|
||||
|
||||
#define SENSOR_UNKNOWN_TOPIC "unknown"
|
||||
#define SENSOR_TEMPERATURE_TOPIC "temperature"
|
||||
#define SENSOR_HUMIDITY_TOPIC "humidity"
|
||||
#define SENSOR_PRESSURE_TOPIC "pressure"
|
||||
#define SENSOR_CURRENT_TOPIC "current"
|
||||
#define SENSOR_VOLTAGE_TOPIC "voltage"
|
||||
#define SENSOR_ACTIVE_POWER_TOPIC "power"
|
||||
#define SENSOR_APPARENT_POWER_TOPIC "apparent"
|
||||
#define SENSOR_REACTIVE_POWER_TOPIC "reactive"
|
||||
#define SENSOR_POWER_FACTOR_TOPIC "factor"
|
||||
#define SENSOR_ENERGY_TOPIC "energy"
|
||||
#define SENSOR_ENERGY_DELTA_TOPIC "energy_delta"
|
||||
#define SENSOR_ANALOG_TOPIC "analog"
|
||||
#define SENSOR_EVENTS_TOPIC "events"
|
||||
|
||||
@@ -892,3 +907,20 @@ PROGMEM const char* const custom_reset_string[] = {
|
||||
|
||||
#endif
|
||||
#endif // IR_SUPPORT
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Custom RF module
|
||||
// Check http://tinkerman.cat/adding-rf-to-a-non-rf-itead-sonoff/
|
||||
// Enable support by passing RF_SUPPORT=1 build flag
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
#ifndef RF_SUPPORT
|
||||
#define RF_SUPPORT 0
|
||||
#endif
|
||||
|
||||
#ifndef RF_PIN
|
||||
#define RF_PIN 14
|
||||
#endif
|
||||
|
||||
#define RF_CHANNEL 31
|
||||
#define RF_DEVICE 1
|
||||
|
||||
@@ -1,20 +1,3 @@
|
||||
//--------------------------------------------------------------------------------
|
||||
// Custom RF module
|
||||
// Check http://tinkerman.cat/adding-rf-to-a-non-rf-itead-sonoff/
|
||||
// Enable support by passing RF_SUPPORT=1 build flag
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
#ifndef RF_SUPPORT
|
||||
#define RF_SUPPORT 0
|
||||
#endif
|
||||
|
||||
#ifndef RF_PIN
|
||||
#define RF_PIN 14
|
||||
#endif
|
||||
|
||||
#define RF_CHANNEL 31
|
||||
#define RF_DEVICE 1
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// General
|
||||
//--------------------------------------------------------------------------------
|
||||
@@ -62,6 +45,46 @@
|
||||
#define HUMIDITY_DRY 2
|
||||
#define HUMIDITY_WET 3
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// SI7021 temperature & humidity sensor
|
||||
// Enable support by passing SI7021_SUPPORT=1 build flag
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
#ifndef SI7021_SUPPORT
|
||||
#define SI7021_SUPPORT 0
|
||||
#endif
|
||||
|
||||
#ifndef SI7021_ADDRESS
|
||||
#define SI7021_ADDRESS 0x40
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// DS18B20 temperature sensor
|
||||
// Enable support by passing DS18B20_SUPPORT=1 build flag
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
#ifndef DS18B20_SUPPORT
|
||||
#define DS18B20_SUPPORT 0
|
||||
#endif
|
||||
|
||||
#ifndef DS18B20_PIN
|
||||
#define DS18B20_PIN 13
|
||||
#endif
|
||||
|
||||
#ifndef DS18B20_PULLUP
|
||||
#define DS18B20_PULLUP 1
|
||||
#endif
|
||||
|
||||
#ifndef DS18B20_UPDATE_INTERVAL
|
||||
#define DS18B20_UPDATE_INTERVAL 60000
|
||||
#endif
|
||||
|
||||
#ifndef DS18B20_TEMPERATURE_TOPIC
|
||||
#define DS18B20_TEMPERATURE_TOPIC "temperature"
|
||||
#endif
|
||||
|
||||
#define DS18B20_RESOLUTION 9
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Analog sensor
|
||||
// Enable support by passing ANALOG_SUPPORT=1 build flag
|
||||
@@ -116,45 +139,36 @@
|
||||
#define COUNTER_TOPIC "counter" // Default topic for MQTT, API and InfluxDB
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// SI7021 temperature & humidity sensor
|
||||
// Enable support by passing SI7021_SUPPORT=1 build flag
|
||||
// Analog Energy Monitor
|
||||
// Enable support by passing EMON_ANALOG_SUPPORT=1 build flag
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
#ifndef SI7021_SUPPORT
|
||||
#define SI7021_SUPPORT 0
|
||||
#ifndef EMON_ANALOG_SUPPORT
|
||||
#define EMON_ANALOG_SUPPORT 0 // Do not build support by default
|
||||
#endif
|
||||
|
||||
#ifndef SI7021_ADDRESS
|
||||
#define SI7021_ADDRESS 0x40
|
||||
#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_FILTER_SPEED 512
|
||||
|
||||
#define EMON_ANALOG_MODE_SAMPLES 1
|
||||
#define EMON_ANALOG_MODE_MSECONDS 2
|
||||
|
||||
#define EMON_ANALOG_READ_VALUE 1000
|
||||
#define EMON_ANALOG_READ_MODE EMON_ANALOG_MODE_SAMPLES
|
||||
|
||||
#define EMON_ANALOG_WARMUP_VALUE 1000
|
||||
#define EMON_ANALOG_WARMUP_MODE EMON_ANALOG_MODE_MSECONDS
|
||||
|
||||
|
||||
#if EMON_ANALOG_SUPPORT
|
||||
#undef ADC_VCC_ENABLED
|
||||
#define ADC_VCC_ENABLED 0
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// DS18B20 temperature sensor
|
||||
// Enable support by passing DS18B20_SUPPORT=1 build flag
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
#ifndef DS18B20_SUPPORT
|
||||
#define DS18B20_SUPPORT 0
|
||||
#endif
|
||||
|
||||
#ifndef DS18B20_PIN
|
||||
#define DS18B20_PIN 14
|
||||
#endif
|
||||
|
||||
#ifndef DS18B20_PULLUP
|
||||
#define DS18B20_PULLUP 1
|
||||
#endif
|
||||
|
||||
#ifndef DS18B20_UPDATE_INTERVAL
|
||||
#define DS18B20_UPDATE_INTERVAL 60000
|
||||
#endif
|
||||
|
||||
#ifndef DS18B20_TEMPERATURE_TOPIC
|
||||
#define DS18B20_TEMPERATURE_TOPIC "temperature"
|
||||
#endif
|
||||
|
||||
#define DS18B20_RESOLUTION 9
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Internal power montior
|
||||
// Enable support by passing ADC_VCC_ENABLED=1 build flag
|
||||
|
||||
Binary file not shown.
@@ -37,43 +37,52 @@ unsigned char _sensor_isr = 0xFF;
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
String _sensorTopic(magnitude_t type) {
|
||||
if (type == MAGNITUDE_TEMPERATURE) {
|
||||
return String(SENSOR_TEMPERATURE_TOPIC);
|
||||
} else if (type == MAGNITUDE_HUMIDITY) {
|
||||
return String(SENSOR_HUMIDITY_TOPIC);
|
||||
} else if (type == MAGNITUDE_ANALOG) {
|
||||
return String(SENSOR_ANALOG_TOPIC);
|
||||
} else if (type == MAGNITUDE_EVENTS) {
|
||||
return String(SENSOR_EVENTS_TOPIC);
|
||||
}
|
||||
if (type == MAGNITUDE_TEMPERATURE) return String(SENSOR_TEMPERATURE_TOPIC);
|
||||
if (type == MAGNITUDE_HUMIDITY) return String(SENSOR_HUMIDITY_TOPIC);
|
||||
if (type == MAGNITUDE_PRESSURE) return String(SENSOR_PRESSURE_TOPIC);
|
||||
if (type == MAGNITUDE_CURRENT) return String(SENSOR_CURRENT_TOPIC);
|
||||
if (type == MAGNITUDE_VOLTAGE) return String(SENSOR_VOLTAGE_TOPIC);
|
||||
if (type == MAGNITUDE_POWER_ACTIVE) return String(SENSOR_ACTIVE_POWER_TOPIC);
|
||||
if (type == MAGNITUDE_POWER_APPARENT) return String(SENSOR_APPARENT_POWER_TOPIC);
|
||||
if (type == MAGNITUDE_POWER_REACTIVE) return String(SENSOR_REACTIVE_POWER_TOPIC);
|
||||
if (type == MAGNITUDE_POWER_FACTOR) return String(SENSOR_POWER_FACTOR_TOPIC);
|
||||
if (type == MAGNITUDE_ENERGY) return String(SENSOR_ENERGY_TOPIC);
|
||||
if (type == MAGNITUDE_ENERGY_DELTA) return String(SENSOR_ENERGY_DELTA_TOPIC);
|
||||
if (type == MAGNITUDE_ANALOG) return String(SENSOR_ANALOG_TOPIC);
|
||||
if (type == MAGNITUDE_EVENTS) return String(SENSOR_EVENTS_TOPIC);
|
||||
return String(SENSOR_UNKNOWN_TOPIC);
|
||||
}
|
||||
|
||||
unsigned char _sensorDecimals(magnitude_t type) {
|
||||
if (type == MAGNITUDE_TEMPERATURE) {
|
||||
return SENSOR_TEMPERATURE_DECIMALS;
|
||||
} else if (type == MAGNITUDE_HUMIDITY) {
|
||||
return SENSOR_HUMIDITY_DECIMALS;
|
||||
} else if (type == MAGNITUDE_ANALOG) {
|
||||
return SENSOR_ANALOG_DECIMALS;
|
||||
} else if (type == MAGNITUDE_EVENTS) {
|
||||
return SENSOR_EVENTS_DECIMALS;
|
||||
}
|
||||
if (type == MAGNITUDE_TEMPERATURE) return SENSOR_TEMPERATURE_DECIMALS;
|
||||
if (type == MAGNITUDE_HUMIDITY) return SENSOR_HUMIDITY_DECIMALS;
|
||||
if (type == MAGNITUDE_PRESSURE) return SENSOR_PRESSURE_DECIMALS;
|
||||
if (type == MAGNITUDE_CURRENT) return SENSOR_CURRENT_DECIMALS;
|
||||
if (type == MAGNITUDE_VOLTAGE) return SENSOR_VOLTAGE_DECIMALS;
|
||||
if (type == MAGNITUDE_POWER_ACTIVE) return SENSOR_POWER_DECIMALS;
|
||||
if (type == MAGNITUDE_POWER_APPARENT) return SENSOR_POWER_DECIMALS;
|
||||
if (type == MAGNITUDE_POWER_REACTIVE) return SENSOR_POWER_DECIMALS;
|
||||
if (type == MAGNITUDE_POWER_FACTOR) return SENSOR_POWER_FACTOR_DECIMALS;
|
||||
if (type == MAGNITUDE_ENERGY) return SENSOR_ENERGY_DECIMALS;
|
||||
if (type == MAGNITUDE_ENERGY_DELTA) return SENSOR_ENERGY_DECIMALS;
|
||||
if (type == MAGNITUDE_ANALOG) return SENSOR_ANALOG_DECIMALS;
|
||||
if (type == MAGNITUDE_EVENTS) return SENSOR_EVENTS_DECIMALS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
String _sensorUnits(magnitude_t type) {
|
||||
if (type == MAGNITUDE_TEMPERATURE) {
|
||||
if (_sensor_temperature_units == TMP_CELSIUS) {
|
||||
return String("C");
|
||||
} else {
|
||||
return String("F");
|
||||
}
|
||||
} else if (type == MAGNITUDE_HUMIDITY) {
|
||||
return String("%");
|
||||
} else if (type == MAGNITUDE_EVENTS) {
|
||||
return String("/m");
|
||||
}
|
||||
if (type == MAGNITUDE_TEMPERATURE) return (_sensor_temperature_units == TMP_CELSIUS) ? String("C") : String("F");
|
||||
if (type == MAGNITUDE_HUMIDITY) return String("%");
|
||||
if (type == MAGNITUDE_PRESSURE) return String("hPa");
|
||||
if (type == MAGNITUDE_CURRENT) return String("A");
|
||||
if (type == MAGNITUDE_VOLTAGE) return String("V");
|
||||
if (type == MAGNITUDE_POWER_ACTIVE) return String("W");
|
||||
if (type == MAGNITUDE_POWER_APPARENT) return String("W");
|
||||
if (type == MAGNITUDE_POWER_REACTIVE) return String("W");
|
||||
if (type == MAGNITUDE_POWER_FACTOR) return String("%");
|
||||
if (type == MAGNITUDE_ENERGY) return String("J");
|
||||
if (type == MAGNITUDE_ENERGY_DELTA) return String("J");
|
||||
if (type == MAGNITUDE_EVENTS) return String("/m");
|
||||
return String();
|
||||
}
|
||||
|
||||
@@ -229,6 +238,12 @@ void sensorInit() {
|
||||
sensorRegister(new AnalogSensor(ANALOG_PIN));
|
||||
#endif
|
||||
|
||||
#if EMON_ANALOG_SUPPORT
|
||||
#include "sensors/AnalogEmonSensor.h"
|
||||
sensorRegister(new AnalogEmonSensor(A0, EMON_ANALOG_MAINS_VOLTAGE, EMON_ANALOG_ADC_BITS, EMON_ANALOG_REFERENCE_VOLTAGE, EMON_ANALOG_CURRENT_RATIO));
|
||||
#endif
|
||||
|
||||
|
||||
#if COUNTER_SUPPORT
|
||||
if (_sensor_isr == 0xFF) {
|
||||
#include "sensors/EventSensor.h"
|
||||
|
||||
156
code/espurna/sensors/AnalogEmonSensor.h
Normal file
156
code/espurna/sensors/AnalogEmonSensor.h
Normal file
@@ -0,0 +1,156 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// Eergy monitor sensor
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "BaseSensor.h"
|
||||
|
||||
class AnalogEmonSensor : public BaseSensor {
|
||||
|
||||
public:
|
||||
|
||||
AnalogEmonSensor(unsigned char gpio, double voltage, unsigned char bits, double ref, double ratio): BaseSensor() {
|
||||
|
||||
// Prepare GPIO
|
||||
pinMode(gpio, INPUT);
|
||||
|
||||
// Cache
|
||||
_gpio = gpio;
|
||||
_voltage = voltage;
|
||||
_adc_counts = 1 << bits;
|
||||
_pivot = _adc_counts >> 1;
|
||||
_count = 2;
|
||||
|
||||
// Calculate factor
|
||||
_current_factor = ratio * ref / _adc_counts;
|
||||
|
||||
// Calculate multiplier
|
||||
calculateMultiplier();
|
||||
|
||||
// warmup
|
||||
read(EMON_ANALOG_WARMUP_VALUE, EMON_ANALOG_WARMUP_MODE, _gpio);
|
||||
|
||||
}
|
||||
|
||||
// Descriptive name of the sensor
|
||||
String name() {
|
||||
char buffer[20];
|
||||
snprintf(buffer, sizeof(buffer), "ANALOG EMON @ GPIO%d", _gpio);
|
||||
return String(buffer);
|
||||
}
|
||||
|
||||
// Descriptive name of the slot # index
|
||||
String slot(unsigned char index) {
|
||||
return name();
|
||||
}
|
||||
|
||||
// Type for slot # index
|
||||
magnitude_t type(unsigned char index) {
|
||||
_error = SENSOR_ERROR_OK;
|
||||
if (index == 0) return MAGNITUDE_CURRENT;
|
||||
if (index == 1) return MAGNITUDE_POWER_APPARENT;
|
||||
_error = SENSOR_ERROR_OUT_OF_RANGE;
|
||||
return MAGNITUDE_NONE;
|
||||
}
|
||||
|
||||
// Current value for slot # index
|
||||
double value(unsigned char index) {
|
||||
|
||||
_error = SENSOR_ERROR_OK;
|
||||
|
||||
// Cache the value
|
||||
static unsigned long last = 0;
|
||||
static double current = 0;
|
||||
if ((last == 0) || (millis() - last > 1000)) {
|
||||
current = read(EMON_ANALOG_READ_VALUE, EMON_ANALOG_READ_MODE, _gpio);
|
||||
last = millis();
|
||||
}
|
||||
|
||||
if (index == 0) return current;
|
||||
if (index == 1) return current * _voltage;
|
||||
|
||||
_error = SENSOR_ERROR_OUT_OF_RANGE;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
unsigned int readADC(unsigned char port) {
|
||||
return analogRead(port);
|
||||
}
|
||||
|
||||
void calculateMultiplier() {
|
||||
unsigned int s = 1;
|
||||
unsigned int i = 1;
|
||||
unsigned int m = s * i;
|
||||
while (m * _current_factor < 1) {
|
||||
_multiplier = m;
|
||||
i = (i == 1) ? 2 : (i == 2) ? 5 : 1;
|
||||
if (i == 1) s *= 10;
|
||||
m = s * i;
|
||||
}
|
||||
}
|
||||
|
||||
double read(unsigned long value, unsigned char mode, unsigned char port) {
|
||||
|
||||
int sample;
|
||||
int max = 0;
|
||||
int min = _adc_counts;
|
||||
double filtered;
|
||||
double sum = 0;
|
||||
|
||||
unsigned long start = millis();
|
||||
unsigned long samples = 0;
|
||||
|
||||
while (true) {
|
||||
|
||||
// Read analog value
|
||||
sample = readADC(port);
|
||||
if (sample > max) max = sample;
|
||||
if (sample < min) min = sample;
|
||||
|
||||
// Digital low pass filter extracts the VDC offset
|
||||
_pivot = (_pivot + (sample - _pivot) / EMON_ANALOG_FILTER_SPEED);
|
||||
filtered = sample - _pivot;
|
||||
|
||||
// Root-mean-square method
|
||||
sum += (filtered * filtered);
|
||||
++samples;
|
||||
|
||||
// Exit condition
|
||||
if (mode == EMON_ANALOG_MODE_SAMPLES) {
|
||||
if (samples >= value) break;
|
||||
} else {
|
||||
if (millis() - start >= value) break;
|
||||
}
|
||||
|
||||
yield();
|
||||
|
||||
}
|
||||
|
||||
// Quick fix
|
||||
if (_pivot < min || max < _pivot) {
|
||||
_pivot = (max + min) / 2.0;
|
||||
}
|
||||
|
||||
double rms = samples > 0 ? sqrt(sum / samples) : 0;
|
||||
double current = _current_factor * rms;
|
||||
current = (double) (round(current * _multiplier) - 1) / _multiplier;
|
||||
if (current < 0) current = 0;
|
||||
|
||||
return current;
|
||||
|
||||
}
|
||||
|
||||
double _voltage;
|
||||
unsigned char _gpio;
|
||||
unsigned int _adc_counts;
|
||||
unsigned int _multiplier = 1;
|
||||
double _current_factor;
|
||||
double _pivot;
|
||||
|
||||
|
||||
};
|
||||
@@ -12,12 +12,13 @@ typedef enum magnitude_t {
|
||||
MAGNITUDE_HUMIDITY,
|
||||
MAGNITUDE_PRESSURE,
|
||||
|
||||
MAGNITUDE_ACTIVE_POWER,
|
||||
MAGNITUDE_APPARENT_POWER,
|
||||
MAGNITUDE_REACTIVE_POWER,
|
||||
MAGNITUDE_VOLTAGE_POWER,
|
||||
MAGNITUDE_CURRENT_POWER,
|
||||
MAGNITUDE_ENERGY_POWER,
|
||||
MAGNITUDE_CURRENT,
|
||||
MAGNITUDE_VOLTAGE,
|
||||
MAGNITUDE_POWER_ACTIVE,
|
||||
MAGNITUDE_POWER_APPARENT,
|
||||
MAGNITUDE_POWER_REACTIVE,
|
||||
MAGNITUDE_ENERGY,
|
||||
MAGNITUDE_ENERGY_DELTA,
|
||||
MAGNITUDE_POWER_FACTOR,
|
||||
|
||||
MAGNITUDE_ANALOG,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -30,8 +30,17 @@ function initMessages() {
|
||||
function sensorType(type) {
|
||||
if (type == 1) return "Temperature";
|
||||
if (type == 2) return "Humidity";
|
||||
if (type == 11) return "Analog";
|
||||
if (type == 12) return "Events";
|
||||
if (type == 3) return "Pressure";
|
||||
if (type == 4) return "Current";
|
||||
if (type == 5) return "Voltage";
|
||||
if (type == 6) return "Active Power";
|
||||
if (type == 7) return "Apparent Power";
|
||||
if (type == 8) return "Reactive Power";
|
||||
if (type == 9) return "Energy";
|
||||
if (type == 10) return "Energy (delta)";
|
||||
if (type == 11) return "Power Factor";
|
||||
if (type == 12) return "Analog";
|
||||
if (type == 13) return "Events";
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user