Browse Source

Migrate HLW8012 sensor to new sensor module, remove old code

fastled
Xose Pérez 7 years ago
parent
commit
1ac4a61206
18 changed files with 3454 additions and 4555 deletions
  1. +0
    -114
      code/espurna/config/general.h
  2. +4
    -8
      code/espurna/config/hardware.h
  3. +20
    -1
      code/espurna/config/sensors.h
  4. BIN
      code/espurna/data/index.html.gz
  5. +0
    -423
      code/espurna/power.ino
  6. +0
    -207
      code/espurna/power_ech1560.ino
  7. +0
    -184
      code/espurna/power_emon.ino
  8. +0
    -170
      code/espurna/power_hlw8012.ino
  9. +0
    -234
      code/espurna/power_v9261f.ino
  10. +78
    -17
      code/espurna/sensor.ino
  11. +10
    -10
      code/espurna/sensors/BaseSensor.h
  12. +1
    -1
      code/espurna/sensors/ECH1560Sensor.h
  13. +1
    -1
      code/espurna/sensors/EventSensor.h
  14. +258
    -0
      code/espurna/sensors/HLW8012Sensor.h
  15. +3063
    -3048
      code/espurna/static/index.html.gz.h
  16. +0
    -44
      code/espurna/ws.ino
  17. +0
    -17
      code/html/custom.js
  18. +19
    -76
      code/html/index.html

+ 0
- 114
code/espurna/config/general.h View File

@ -553,120 +553,6 @@ PROGMEM const char* const custom_reset_string[] = {
#define LIGHT_TRANSITION_STEP 10 // Time in millis between each transtion step #define LIGHT_TRANSITION_STEP 10 // Time in millis between each transtion step
#define LIGHT_TRANSITION_STEPS 50 // Number of steps to acomplish transition #define LIGHT_TRANSITION_STEPS 50 // Number of steps to acomplish transition
// -----------------------------------------------------------------------------
// POWER METERING
// -----------------------------------------------------------------------------
// Available power-metering providers (do not change this)
#define POWER_PROVIDER_NONE 0x00
#define POWER_PROVIDER_EMON_ANALOG 0x10
#define POWER_PROVIDER_EMON_ADC121 0x11
#define POWER_PROVIDER_HLW8012 0x20
#define POWER_PROVIDER_V9261F 0x30
#define POWER_PROVIDER_ECH1560 0x40
// Available magnitudes (do not change this)
#define POWER_MAGNITUDE_CURRENT 1
#define POWER_MAGNITUDE_VOLTAGE 2
#define POWER_MAGNITUDE_ACTIVE 4
#define POWER_MAGNITUDE_APPARENT 8
#define POWER_MAGNITUDE_REACTIVE 16
#define POWER_MAGNITUDE_POWER_FACTOR 32
#define POWER_MAGNITUDE_ALL 63
// No power provider defined (do not change this)
#ifndef POWER_PROVIDER
#define POWER_PROVIDER POWER_PROVIDER_NONE
#endif
// Identify available magnitudes (do not change this)
#if (POWER_PROVIDER == POWER_PROVIDER_HLW8012) || (POWER_PROVIDER == POWER_PROVIDER_V9261F)
#define POWER_HAS_ACTIVE 1
#else
#define POWER_HAS_ACTIVE 0
#endif
#if (POWER_PROVIDER == POWER_PROVIDER_HLW8012)
#define POWER_HAS_ENERGY 1
#else
#define POWER_HAS_ENERGY 0
#endif
#define POWER_VOLTAGE 230 // Default voltage
#define POWER_MIN_READ_INTERVAL 2000 // Minimum read interval
#define POWER_READ_INTERVAL 6000 // Default reading interval (6 seconds)
#define POWER_REPORT_INTERVAL 60000 // Default report interval (1 minute)
#define POWER_CURRENT_DECIMALS 2 // Decimals for current values
#define POWER_VOLTAGE_DECIMALS 0 // Decimals for voltage values
#define POWER_POWER_DECIMALS 0 // Decimals for power values
#define POWER_ENERGY_DECIMALS 3 // Decimals for energy values
#define POWER_ENERGY_DECIMALS_KWH 6 // Decimals for energy values
#define POWER_ENERGY_FACTOR 1 // Watt * seconds == Joule (Ws == J)
#define POWER_ENERGY_FACTOR_KWH (1. / 1000. / 3600.) // kWh
#if POWER_PROVIDER == POWER_PROVIDER_EMON_ANALOG
#define EMON_CURRENT_RATIO 30 // Current ratio in the clamp (30V/1A)
#define EMON_SAMPLES 1000 // Number of samples to get for each reading
#define EMON_ADC_BITS 10 // ADC depth
#define EMON_REFERENCE_VOLTAGE 1.0 // Reference voltage of the ADC
#define EMON_CURRENT_OFFSET 0.25 // Current offset (error)
#undef ADC_VCC_ENABLED
#define ADC_VCC_ENABLED 0 // Disable internal battery measurement
#endif
#if POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121
#define EMON_CURRENT_RATIO 30 // Current ratio in the clamp (30V/1A)
#define EMON_SAMPLES 1000 // Number of samples to get for each reading
#define EMON_ADC_BITS 12 // ADC depth
#define EMON_REFERENCE_VOLTAGE 3.3 // Reference voltage of the ADC
#define EMON_CURRENT_OFFSET 0.10 // Current offset (error)
#define ADC121_I2C_ADDRESS 0x50 // I2C address of the ADC121
#undef I2C_SUPPORT
#define I2C_SUPPORT 1 // Enabled I2C support
#endif
#if POWER_PROVIDER == POWER_PROVIDER_HLW8012
#define HLW8012_USE_INTERRUPTS 1 // Use interrupts to trap HLW8012 signals
#define HLW8012_SEL_CURRENT HIGH // SEL pin to HIGH to measure current
#define HLW8012_CURRENT_R 0.001 // Current resistor
#define HLW8012_VOLTAGE_R_UP ( 5 * 470000 ) // Upstream voltage resistor
#define HLW8012_VOLTAGE_R_DOWN ( 1000 ) // Downstream voltage resistor
#endif
#if POWER_PROVIDER == POWER_PROVIDER_V9261F
#ifndef V9261F_PIN
#define V9261F_PIN 2 // TX pin from the V9261F
#endif
#ifndef V9261F_PIN_INVERSE
#define V9261F_PIN_INVERSE 1 // Signal is inverted
#endif
#define V9261F_SYNC_INTERVAL 600 // Sync signal length (ms)
#define V9261F_BAUDRATE 4800 // UART baudrate
// Default ratios
#define V9261F_CURRENT_FACTOR 79371434.0
#define V9261F_VOLTAGE_FACTOR 4160651.0
#define V9261F_POWER_FACTOR 153699.0
#define V9261F_RPOWER_FACTOR V9261F_CURRENT_FACTOR
#endif
#if POWER_PROVIDER == POWER_PROVIDER_ECH1560
#ifndef ECH1560_CLK_PIN
#define ECH1560_CLK_PIN 4 // Default CLK pin
#endif
#ifndef ECH1560_MISO_PIN
#define ECH1560_MISO_PIN 5 // Default MISO pin
#endif
#ifndef ECH1560_INVERTED
#define ECH1560_INVERTED 0 // Power signal is inverted
#endif
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// DOMOTICZ // DOMOTICZ
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


+ 4
- 8
code/espurna/config/hardware.h View File

@ -105,9 +105,7 @@
#define LED1_PIN_INVERSE 1 #define LED1_PIN_INVERSE 1
// HLW8012 // HLW8012
#ifndef POWER_PROVIDER
#define POWER_PROVIDER POWER_PROVIDER_HLW8012
#endif
#define HLW8012_SUPPORT 1
#define HLW8012_SEL_PIN 2 #define HLW8012_SEL_PIN 2
#define HLW8012_CF1_PIN 13 #define HLW8012_CF1_PIN 13
#define HLW8012_CF_PIN 14 #define HLW8012_CF_PIN 14
@ -148,9 +146,7 @@
#define LED1_PIN_INVERSE 0 #define LED1_PIN_INVERSE 0
// HLW8012 // HLW8012
#ifndef POWER_PROVIDER
#define POWER_PROVIDER POWER_PROVIDER_HLW8012
#endif
#define HLW8012_SUPPORT 1
#define HLW8012_SEL_PIN 5 #define HLW8012_SEL_PIN 5
#define HLW8012_CF1_PIN 13 #define HLW8012_CF1_PIN 13
#define HLW8012_CF_PIN 14 #define HLW8012_CF_PIN 14
@ -322,7 +318,7 @@
#define LED1_PIN_INVERSE 0 #define LED1_PIN_INVERSE 0
// HLW8012 // HLW8012
#define POWER_PROVIDER POWER_PROVIDER_HLW8012
#define HLW8012_SUPPORT 1
#define HLW8012_SEL_PIN 5 #define HLW8012_SEL_PIN 5
#define HLW8012_CF1_PIN 13 #define HLW8012_CF1_PIN 13
#define HLW8012_CF_PIN 14 #define HLW8012_CF_PIN 14
@ -1042,7 +1038,7 @@
#define ALEXA_SUPPORT 0 #define ALEXA_SUPPORT 0
// ECH1560 // ECH1560
#define POWER_PROVIDER POWER_PROVIDER_ECH1560
#define ECH1560_SUPPORT 1
#define ECH1560_CLK_PIN 4 #define ECH1560_CLK_PIN 4
#define ECH1560_MISO_PIN 5 #define ECH1560_MISO_PIN 5
#define ECH1560_INVERTED 0 #define ECH1560_INVERTED 0


+ 20
- 1
code/espurna/config/sensors.h View File

@ -191,7 +191,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#ifndef ECH1560_SUPPORT #ifndef ECH1560_SUPPORT
#define ECH1560_SUPPORT 1
#define ECH1560_SUPPORT 0
#endif #endif
#ifndef ECH1560_CLK_PIN #ifndef ECH1560_CLK_PIN
@ -301,6 +301,24 @@
#define HLW8012_SUPPORT 0 #define HLW8012_SUPPORT 0
#endif #endif
#ifndef HLW8012_SEL_PIN
#define HLW8012_SEL_PIN 5
#endif
#ifndef HLW8012_CF1_PIN
#define HLW8012_CF1_PIN 13
#endif
#ifndef HLW8012_CF_PIN
#define HLW8012_CF_PIN 14
#endif
#define HLW8012_USE_INTERRUPTS 1 // Use interrupts to trap HLW8012 signals
#define HLW8012_SEL_CURRENT HIGH // SEL pin to HIGH to measure current
#define HLW8012_CURRENT_R 0.001 // Current resistor
#define HLW8012_VOLTAGE_R_UP ( 5 * 470000 ) // Upstream voltage resistor
#define HLW8012_VOLTAGE_R_DOWN ( 1000 ) // Downstream voltage resistor
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// MHZ19 CO2 sensor // MHZ19 CO2 sensor
// Enable support by passing MHZ19_SUPPORT=1 build flag // Enable support by passing MHZ19_SUPPORT=1 build flag
@ -476,6 +494,7 @@
#endif #endif
#if HLW8012_SUPPORT #if HLW8012_SUPPORT
#include <HLW8012.h>
#include "sensors/HLW8012Sensor.h" #include "sensors/HLW8012Sensor.h"
#endif #endif


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


+ 0
- 423
code/espurna/power.ino View File

@ -1,423 +0,0 @@
/*
POWER MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if POWER_PROVIDER != POWER_PROVIDER_NONE
// -----------------------------------------------------------------------------
// MODULE GLOBALS AND CACHE
// -----------------------------------------------------------------------------
#include "filters/MedianFilter.h"
#include <Hash.h>
#include <ArduinoJson.h>
bool _power_enabled = false;
bool _power_newdata = false;
bool _power_realtime = API_REAL_TIME_VALUES;
unsigned long _power_read_interval = POWER_READ_INTERVAL;
unsigned long _power_report_interval = POWER_REPORT_INTERVAL;
double _power_current = 0;
double _power_voltage = 0;
double _power_apparent = 0;
double _power_energy = 0;
MedianFilter _filter_current = MedianFilter();
#if POWER_HAS_ACTIVE
double _power_active = 0;
double _power_reactive = 0;
double _power_factor = 0;
MedianFilter _filter_voltage = MedianFilter();
MedianFilter _filter_active = MedianFilter();
MedianFilter _filter_apparent = MedianFilter();
#endif
#if POWER_HAS_ENERGY
double _power_last_energy = 0;
#endif
// -----------------------------------------------------------------------------
// PRIVATE METHODS
// -----------------------------------------------------------------------------
#if WEB_SUPPORT
void _powerWebSocketOnSend(JsonObject& root) {
root["pwrVisible"] = 1;
root["pwrCurrent"] = getCurrent();
root["pwrVoltage"] = getVoltage();
root["pwrApparent"] = getApparentPower();
root["pwrEnergy"] = getPowerEnergy();
root["pwrReadEvery"] = powerReadInterval();
root["pwrReportEvery"] = powerReportInterval();
#if POWER_HAS_ACTIVE
root["pwrActive"] = getActivePower();
root["pwrReactive"] = getReactivePower();
root["pwrFactor"] = int(100 * getPowerFactor());
#endif
#if (POWER_PROVIDER == POWER_PROVIDER_EMON_ANALOG) || (POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121)
root["emonVisible"] = 1;
#endif
#if POWER_PROVIDER == POWER_PROVIDER_HLW8012
root["hlwVisible"] = 1;
#endif
#if POWER_PROVIDER == POWER_PROVIDER_V9261F
root["v9261fVisible"] = 1;
#endif
#if POWER_PROVIDER == POWER_PROVIDER_ECH1560
root["ech1560fVisible"] = 1;
#endif
}
void _powerAPISetup() {
apiRegister(MQTT_TOPIC_CURRENT, MQTT_TOPIC_CURRENT, [](char * buffer, size_t len) {
dtostrf(_power_realtime ? _powerCurrent() : getCurrent(), 1-len, POWER_CURRENT_DECIMALS, buffer);
});
apiRegister(MQTT_TOPIC_VOLTAGE, MQTT_TOPIC_VOLTAGE, [](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%d"), (int) (_power_realtime ? _powerVoltage() : getVoltage()));
});
apiRegister(MQTT_TOPIC_POWER_APPARENT, MQTT_TOPIC_POWER_APPARENT, [](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%d"), (int) (_power_realtime ? _powerApparentPower() : getApparentPower()));
});
#if POWER_HAS_ENERGY
apiRegister(MQTT_TOPIC_ENERGY_TOTAL, MQTT_TOPIC_ENERGY_TOTAL, [](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%lu"), (int) (_power_realtime ? _powerEnergy() : getPowerEnergy()));
});
#endif
#if POWER_HAS_ACTIVE
apiRegister(MQTT_TOPIC_POWER_ACTIVE, MQTT_TOPIC_POWER_ACTIVE, [](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%d"), (int) (_power_realtime ? _powerActivePower() : getActivePower()));
});
apiRegister(MQTT_TOPIC_POWER_FACTOR, MQTT_TOPIC_POWER_FACTOR, [](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%d"), (int) (100 * (_power_realtime ? _powerPowerFactor() : getPowerFactor())));
});
#endif
}
#endif // WEB_SUPPORT
void _powerReset() {
_filter_current.reset();
#if POWER_HAS_ACTIVE
_filter_apparent.reset();
_filter_voltage.reset();
_filter_active.reset();
#endif
}
void _powerRead() {
// Get instantaneous values from HAL
double current = _powerCurrent();
double voltage = _powerVoltage();
double apparent = _powerApparentPower();
#if POWER_HAS_ACTIVE
double active = _powerActivePower();
double reactive = (apparent > active) ? sqrt(apparent * apparent - active * active) : 0;
double factor = (apparent > 0) ? active / apparent : 1;
if (factor > 1) factor = 1;
#endif
#if POWER_HAS_ENERGY
_power_energy = _powerEnergy(); // Due to its nature this value doesn't have to be filtered
#endif
// Filters
_filter_current.add(current);
#if POWER_HAS_ACTIVE
_filter_apparent.add(apparent);
_filter_voltage.add(voltage);
_filter_active.add(active);
#endif
// Debug
/*
char current_buffer[10];
dtostrf(current, 1-sizeof(current_buffer), POWER_CURRENT_DECIMALS, current_buffer);
DEBUG_MSG_P(PSTR("[POWER] Current: %sA\n"), current_buffer);
DEBUG_MSG_P(PSTR("[POWER] Voltage: %dV\n"), (int) voltage);
DEBUG_MSG_P(PSTR("[POWER] Apparent Power: %dW\n"), (int) apparent);
DEBUG_MSG_P(PSTR("[POWER] Energy: %dJ\n"), (int) _power_energy);
#if POWER_HAS_ACTIVE
DEBUG_MSG_P(PSTR("[POWER] Active Power: %dW\n"), (int) active);
DEBUG_MSG_P(PSTR("[POWER] Reactive Power: %dW\n"), (int) reactive);
DEBUG_MSG_P(PSTR("[POWER] Power Factor: %d%%\n"), (int) (100 * factor));
#endif
*/
// Update websocket clients
#if WEB_SUPPORT
if (wsConnected()) {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["pwrVisible"] = 1;
root["pwrCurrent"] = roundTo(current, POWER_CURRENT_DECIMALS);
root["pwrVoltage"] = roundTo(voltage, POWER_VOLTAGE_DECIMALS);
root["pwrApparent"] = roundTo(apparent, POWER_POWER_DECIMALS);
root["pwrEnergy"] = roundTo(_power_energy, POWER_ENERGY_DECIMALS);
#if POWER_HAS_ACTIVE
root["pwrActive"] = roundTo(active, POWER_POWER_DECIMALS);
root["pwrReactive"] = roundTo(reactive, POWER_POWER_DECIMALS);
root["pwrFactor"] = int(100 * factor);
#endif
#if (POWER_PROVIDER == POWER_PROVIDER_EMON_ANALOG) || (POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121)
root["emonVisible"] = 1;
#endif
#if POWER_PROVIDER == POWER_PROVIDER_HLW8012
root["hlwVisible"] = 1;
#endif
#if POWER_PROVIDER == POWER_PROVIDER_V9261F
root["v9261fVisible"] = 1;
#endif
#if POWER_PROVIDER == POWER_PROVIDER_ECH1560
root["ech1560Visible"] = 1;
#endif
String output;
root.printTo(output);
wsSend(output.c_str());
}
#endif
}
void _powerReport() {
// Get the fitered values
#if POWER_HAS_ACTIVE
double max_power = _filter_active.max();
_power_current = _filter_current.result();
_power_voltage = _filter_voltage.result();
_power_active = _filter_active.result();
_power_apparent = _filter_apparent.result();
if (_power_active > _power_apparent) _power_apparent = _power_active;
_power_reactive = (_power_apparent > _power_active) ? sqrt(_power_apparent * _power_apparent - _power_active * _power_active) : 0;
_power_factor = (_power_apparent > 0) ? _power_active / _power_apparent : 1;
if (_power_factor > 1) _power_factor = 1;
double power = _power_active;
#else
double max_power = _filter_current.max() * _power_voltage;
_power_current = _filter_current.result();
_power_apparent = _power_current * _power_voltage;
double power = _power_apparent;
#endif
#if POWER_HAS_ENERGY
double energy_delta = _power_energy - _power_last_energy;
_power_last_energy = _power_energy;
#else
double energy_delta = power * (_power_report_interval / 1000.);
_power_energy += energy_delta;
#endif
char buf_current[10];
char buf_energy_delta[20];
char buf_energy_total[20];
dtostrf(_power_current, 1-sizeof(buf_current), POWER_CURRENT_DECIMALS, buf_current);
dtostrf(energy_delta * POWER_ENERGY_FACTOR, 1-sizeof(buf_energy_delta), POWER_ENERGY_DECIMALS, buf_energy_delta);
dtostrf(_power_energy * POWER_ENERGY_FACTOR, 1-sizeof(buf_energy_total), POWER_ENERGY_DECIMALS, buf_energy_total);
#if MQTT_SUPPORT
{
mqttSend(MQTT_TOPIC_CURRENT, buf_current);
mqttSend(MQTT_TOPIC_POWER_APPARENT, String((int) _power_apparent).c_str());
mqttSend(MQTT_TOPIC_MAX_POWER, String((int) max_power).c_str());
mqttSend(MQTT_TOPIC_ENERGY_DELTA, buf_energy_delta);
mqttSend(MQTT_TOPIC_ENERGY_TOTAL, buf_energy_total);
#if POWER_HAS_ACTIVE
mqttSend(MQTT_TOPIC_POWER_ACTIVE, String((int) _power_active).c_str());
mqttSend(MQTT_TOPIC_POWER_REACTIVE, String((int) _power_reactive).c_str());
mqttSend(MQTT_TOPIC_VOLTAGE, String((int) _power_voltage).c_str());
mqttSend(MQTT_TOPIC_POWER_FACTOR, String((int) 100 * _power_factor).c_str());
#endif
}
#endif
#if DOMOTICZ_SUPPORT
if (domoticzEnabled()) {
// Domoticz expects energy in kWh
char buf_energy_kwh[10];
dtostrf(energy_delta * POWER_ENERGY_FACTOR_KWH, 1-sizeof(buf_energy_kwh), POWER_ENERGY_DECIMALS_KWH, buf_energy_kwh);
char buffer[20];
snprintf_P(buffer, sizeof(buffer), PSTR("%d;%s"), (int) power, buf_energy_kwh);
domoticzSend("dczPowIdx", 0, buffer);
domoticzSend("dczCurrentIdx", 0, buf_current);
domoticzSend("dczEnergyIdx", 0, buf_energy_kwh);
#if POWER_HAS_ACTIVE
snprintf_P(buffer, sizeof(buffer), PSTR("%d"), (int) _power_voltage);
domoticzSend("dczVoltIdx", 0, buffer);
#endif
}
#endif
#if INFLUXDB_SUPPORT
if (idbEnabled()) {
idbSend(MQTT_TOPIC_CURRENT, buf_current);
idbSend(MQTT_TOPIC_POWER_APPARENT, String((int) _power_apparent).c_str());
idbSend(MQTT_TOPIC_MAX_POWER, String((int) max_power).c_str());
idbSend(MQTT_TOPIC_ENERGY_DELTA, buf_energy_delta);
idbSend(MQTT_TOPIC_ENERGY_TOTAL, buf_energy_total);
#if POWER_HAS_ACTIVE
idbSend(MQTT_TOPIC_POWER_ACTIVE, String((int) _power_active).c_str());
idbSend(MQTT_TOPIC_POWER_REACTIVE, String((int) _power_reactive).c_str());
idbSend(MQTT_TOPIC_VOLTAGE, String((int) _power_voltage).c_str());
idbSend(MQTT_TOPIC_POWER_FACTOR, String((int) 100 * _power_factor).c_str());
#endif
}
#endif
_powerReset();
}
void _powerConfigure() {
_power_realtime = getSetting("apiRealTime", API_REAL_TIME_VALUES).toInt() == 1;
_power_read_interval = atol(getSetting("pwrReadEvery", POWER_READ_INTERVAL).c_str());
_power_report_interval = atol(getSetting("pwrReportEvery", POWER_REPORT_INTERVAL).c_str());
if (_power_read_interval < POWER_MIN_READ_INTERVAL) {
_power_read_interval = POWER_MIN_READ_INTERVAL;
setSetting("pwrReadEvery", _power_read_interval);
}
if (_power_report_interval < _power_read_interval) {
_power_report_interval = _power_read_interval;
setSetting("pwrReportEvery", _power_report_interval);
}
_powerConfigureProvider();
}
// -----------------------------------------------------------------------------
// MAGNITUDE API
// -----------------------------------------------------------------------------
bool hasActivePower() {
return POWER_HAS_ACTIVE;
}
double getCurrent() {
return roundTo(_power_current, POWER_CURRENT_DECIMALS);
}
double getVoltage() {
return roundTo(_power_voltage, POWER_VOLTAGE_DECIMALS);
}
double getApparentPower() {
return roundTo(_power_apparent, POWER_POWER_DECIMALS);
}
double getPowerEnergy() {
roundTo(_power_energy, POWER_ENERGY_DECIMALS);
}
#if POWER_HAS_ACTIVE
double getActivePower() {
return roundTo(_power_active, POWER_POWER_DECIMALS);
}
double getReactivePower() {
return roundTo(_power_reactive, POWER_POWER_DECIMALS);
}
double getPowerFactor() {
return roundTo(_power_factor, 2);
}
#endif
// -----------------------------------------------------------------------------
// PUBLIC API
// -----------------------------------------------------------------------------
unsigned long powerReadInterval() {
return _power_read_interval;
}
unsigned long powerReportInterval() {
return _power_report_interval;
}
bool powerEnabled() {
return _power_enabled;
}
void powerEnabled(bool enabled) {
if (enabled & !_power_enabled) _powerReset();
_power_enabled = enabled;
_powerEnabledProvider();
}
void powerCalibrate(unsigned char magnitude, double value) {
_powerCalibrateProvider(magnitude, value);
}
void powerResetCalibration() {
_powerResetCalibrationProvider();
}
void powerSetup() {
// backwards compatibility
moveSetting("pwMainsVoltage", "pwrVoltage");
moveSetting("emonMains", "pwrVoltage");
moveSetting("emonVoltage", "pwrVoltage");
moveSetting("pwCurrentRatio", "pwrRatioC");
moveSetting("emonRatio", "pwrRatioC");
moveSetting("powPowerMult", "pwrRatioP");
moveSetting("powCurrentMult", "pwrRatioC");
moveSetting("powVoltageMult", "pwrRatioV");
moveSetting("powerVoltage", "pwrVoltage");
moveSetting("powerRatioC", "pwrRatioC");
moveSetting("powerRatioV", "pwrRatioV");
moveSetting("powerRatioP", "pwrRatioP");
_powerSetupProvider();
_powerConfigure();
// API
#if WEB_SUPPORT
wsOnSendRegister(_powerWebSocketOnSend);
wsOnAfterParseRegister(_powerConfigure);
_powerAPISetup();
#endif
DEBUG_MSG_P(PSTR("[POWER] POWER_PROVIDER = %d\n"), POWER_PROVIDER);
}
void powerLoop() {
_powerLoopProvider(true);
if (_power_newdata) {
_power_newdata = false;
_powerRead();
}
static unsigned long last = 0;
if (millis() - last > _power_report_interval) {
last = millis();
_powerReport();
}
_powerLoopProvider(false);
}
#endif // POWER_PROVIDER != POWER_PROVIDER_NONE

+ 0
- 207
code/espurna/power_ech1560.ino View File

@ -1,207 +0,0 @@
/*
POWER ECH1560 MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if POWER_PROVIDER == POWER_PROVIDER_ECH1560
// -----------------------------------------------------------------------------
// MODULE GLOBALS AND CACHE
// -----------------------------------------------------------------------------
volatile long _ech1560_bits_count = 0;
volatile long _ech1560_clk_count = 0;
volatile bool _ech1560_dosync = false;
volatile bool _ech1560_nextbit = true;
double _ech1560_apparent = 0;
double _ech1560_voltage = 0;
double _ech1560_current = 0;
// -----------------------------------------------------------------------------
// HAL
// -----------------------------------------------------------------------------
void _ech1560_sync() {
unsigned int byte1 = 0;
unsigned int byte2 = 0;
unsigned int byte3 = 0;
_ech1560_bits_count = 0;
while (_ech1560_bits_count < 40); // skip the uninteresting 5 first bytes
_ech1560_bits_count = 0;
while (_ech1560_bits_count < 24) { // loop through the next 3 Bytes (6-8) and save byte 6 and 7 in Ba and Bb
if (_ech1560_nextbit) {
if (_ech1560_bits_count < 9) { // first Byte/8 bits in Ba
byte1 = byte1 << 1;
if (digitalRead(ECH1560_MISO_PIN) == HIGH) byte1 |= 1;
_ech1560_nextbit = false;
} else if (_ech1560_bits_count < 17) { // bit 9-16 is byte 7, stor in Bb
byte2 = byte2 << 1;
if (digitalRead(ECH1560_MISO_PIN) == HIGH) byte2 |= 1;
_ech1560_nextbit = false;
}
}
}
if (byte2 != 3) { // if bit Bb is not 3, we have reached the important part, U is allready in Ba and Bb and next 8 Bytes will give us the Power.
// voltage = 2 * (Ba + Bb / 255)
_ech1560_voltage = 2.0 * ((float) byte1 + (float) byte2 / 255.0);
// power:
_ech1560_bits_count = 0;
while (_ech1560_bits_count < 40); // skip the uninteresting 5 first bytes
_ech1560_bits_count = 0;
byte1 = 0;
byte2 = 0;
byte3 = 0;
while (_ech1560_bits_count < 24) { //store byte 6, 7 and 8 in Ba and Bb & Bc.
if (_ech1560_nextbit) {
if (_ech1560_bits_count < 9) {
byte1 = byte1 << 1;
if (digitalRead(ECH1560_MISO_PIN) == HIGH) byte1 |= 1;
_ech1560_nextbit = false;
} else if (_ech1560_bits_count < 17) {
byte2 = byte2 << 1;
if (digitalRead(ECH1560_MISO_PIN) == HIGH) byte2 |= 1;
_ech1560_nextbit = false;
} else {
byte3 = byte3 << 1;
if (digitalRead(ECH1560_MISO_PIN) == HIGH) byte3 |= 1;
_ech1560_nextbit = false;
}
}
}
#if ECH1560_INVERTED
byte1 = 255 - byte1;
byte2 = 255 - byte2;
byte3 = 255 - byte3;
#endif
// power = (Ba*255+Bb+Bc/255)/2
_ech1560_apparent = ( (float) byte1 * 255 + (float) byte2 + (float) byte3 / 255.0) / 2;
_ech1560_current = _ech1560_apparent / _ech1560_voltage;
_power_newdata = true;
_ech1560_dosync = false;
}
// If Bb is not 3 or something else than 0, something is wrong!
if (byte2 == 0) _ech1560_dosync = false;
}
void ICACHE_RAM_ATTR _ech1560_isr() {
// if we are trying to find the sync-time (CLK goes high for 1-2ms)
if (_ech1560_dosync == false) {
_ech1560_clk_count = 0;
// register how long the ClkHigh is high to evaluate if we are at the part wher clk goes high for 1-2 ms
while (digitalRead(ECH1560_CLK_PIN) == HIGH) {
_ech1560_clk_count += 1;
delayMicroseconds(30); //can only use delayMicroseconds in an interrupt.
}
// if the Clk was high between 1 and 2 ms than, its a start of a SPI-transmission
if (_ech1560_clk_count >= 33 && _ech1560_clk_count <= 67) {
_ech1560_dosync = true;
}
// we are in sync and logging CLK-highs
} else {
// increment an integer to keep track of how many bits we have read.
_ech1560_bits_count += 1;
_ech1560_nextbit = true;
}
}
// -----------------------------------------------------------------------------
// POWER API
// -----------------------------------------------------------------------------
double _powerCurrent() {
return _ech1560_current;
}
double _powerVoltage() {
return _ech1560_voltage;
}
double _powerActivePower() {
return 0;
}
double _powerApparentPower() {
return _ech1560_apparent;
}
double _powerReactivePower() {
return 0;
}
double _powerPowerFactor() {
return 1;
}
void _powerEnabledProvider() {
// Nothing to do
}
void _powerConfigureProvider() {
// Nothing to do
}
void _powerCalibrateProvider(unsigned char magnitude, double value) {
// Nothing to do
}
void _powerResetCalibrationProvider() {
// Nothing to do
}
void _powerSetupProvider() {
pinMode(ECH1560_CLK_PIN, INPUT);
pinMode(ECH1560_MISO_PIN, INPUT);
attachInterrupt(ECH1560_CLK_PIN, _ech1560_isr, RISING);
}
void _powerLoopProvider(bool before) {
if (!before) {
if (_ech1560_dosync) _ech1560_sync();
}
}
#endif // POWER_PROVIDER == POWER_PROVIDER_ECH1560

+ 0
- 184
code/espurna/power_emon.ino View File

@ -1,184 +0,0 @@
/*
POWER EMON MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if (POWER_PROVIDER == POWER_PROVIDER_EMON_ANALOG) || (POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121)
// -----------------------------------------------------------------------------
// MODULE GLOBALS AND CACHE
// -----------------------------------------------------------------------------
#include <EmonLiteESP.h>
EmonLiteESP _emon;
#if POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121
#if I2C_USE_BRZO
#include "brzo_i2c.h"
#else
#include "Wire.h"
#endif
// ADC121 Registers
#define ADC121_REG_RESULT 0x00
#define ADC121_REG_ALERT 0x01
#define ADC121_REG_CONFIG 0x02
#define ADC121_REG_LIMITL 0x03
#define ADC121_REG_LIMITH 0x04
#define ADC121_REG_HYST 0x05
#define ADC121_REG_CONVL 0x06
#define ADC121_REG_CONVH 0x07
#endif // POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121
// -----------------------------------------------------------------------------
// HAL
// -----------------------------------------------------------------------------
unsigned int currentCallback() {
#if POWER_PROVIDER == POWER_PROVIDER_EMON_ANALOG
return analogRead(A0);
#endif // POWER_PROVIDER == POWER_PROVIDER_EMON_ANALOG
#if POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121
unsigned int value;
#if I2C_USE_BRZO
uint8_t buffer[2];
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);
brzo_i2c_end_transaction();
value = (buffer[0] & 0x0F) << 8;
value |= buffer[1];
#else
Wire.beginTransmission(ADC121_I2C_ADDRESS);
Wire.write(ADC121_REG_RESULT);
Wire.endTransmission();
Wire.requestFrom(ADC121_I2C_ADDRESS, 2);
value = (Wire.read() & 0x0F) << 8;
value = value + Wire.read();
#endif
return value;
#endif // POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121
}
// -----------------------------------------------------------------------------
// POWER API
// -----------------------------------------------------------------------------
double _powerCurrent() {
static unsigned long last = 0;
static double current = 0;
if (millis() - last > 1000) {
last = millis();
current = _emon.getCurrent(EMON_SAMPLES);
current -= EMON_CURRENT_OFFSET;
if (current < 0) current = 0;
}
return current;
}
double _powerVoltage() {
return _power_voltage;
}
double _powerActivePower() {
return 0;
}
double _powerApparentPower() {
return _powerCurrent() * _powerVoltage();
}
double _powerReactivePower() {
return 0;
}
double _powerPowerFactor() {
return 1;
}
void _powerEnabledProvider() {
// Nothing to do
}
void _powerCalibrateProvider(unsigned char magnitude, double value) {
if (value <= 0) return;
if (magnitude == POWER_MAGNITUDE_ACTIVE) {
double power = _powerApparentPower();
double ratio = getSetting("pwrRatioC", EMON_CURRENT_RATIO).toFloat();
ratio = ratio * (value / power);
_emon.setCurrentRatio(ratio);
setSetting("pwrRatioC", ratio);
saveSettings();
}
if (magnitude == POWER_MAGNITUDE_VOLTAGE) {
_power_voltage = value;
setSetting("pwrVoltage", value);
saveSettings();
}
}
void _powerResetCalibrationProvider() {
delSetting("pwrRatioC");
_powerConfigureProvider();
saveSettings();
}
void _powerConfigureProvider() {
_emon.setCurrentRatio(getSetting("pwrRatioC", EMON_CURRENT_RATIO).toFloat());
_power_voltage = getSetting("pwrVoltage", POWER_VOLTAGE).toFloat();
}
void _powerSetupProvider() {
_emon.initCurrent(currentCallback, EMON_ADC_BITS, EMON_REFERENCE_VOLTAGE, EMON_CURRENT_RATIO);
#if POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121
#if I2C_USE_BRZO
uint8_t buffer[2];
buffer[0] = ADC121_REG_CONFIG;
buffer[1] = 0x00;
brzo_i2c_start_transaction(ADC121_I2C_ADDRESS, I2C_SCL_FREQUENCY);
brzo_i2c_write(buffer, 2, false);
brzo_i2c_end_transaction();
#else
Wire.beginTransmission(ADC121_I2C_ADDRESS);
Wire.write(ADC121_REG_CONFIG);
Wire.write(0x00);
Wire.endTransmission();
#endif
#endif
_emon.warmup();
}
void _powerLoopProvider(bool before) {
if (before) {
static unsigned long last = 0;
if (millis() - last > powerReadInterval()) {
last = millis();
_power_newdata = true;
}
}
}
#endif // (POWER_PROVIDER == POWER_PROVIDER_EMON_ANALOG) || (POWER_PROVIDER == POWER_PROVIDER_EMON_ADC121)

+ 0
- 170
code/espurna/power_hlw8012.ino View File

@ -1,170 +0,0 @@
/*
POWER HLW8012 MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if POWER_PROVIDER == POWER_PROVIDER_HLW8012
// -----------------------------------------------------------------------------
// MODULE GLOBALS AND CACHE
// -----------------------------------------------------------------------------
#include <HLW8012.h>
#include <ESP8266WiFi.h>
HLW8012 _hlw8012;
WiFiEventHandler _power_wifi_onconnect;
WiFiEventHandler _power_wifi_ondisconnect;
// -----------------------------------------------------------------------------
// HAL
// -----------------------------------------------------------------------------
void ICACHE_RAM_ATTR _hlw_cf1_isr() {
_hlw8012.cf1_interrupt();
}
void ICACHE_RAM_ATTR _hlw_cf_isr() {
_hlw8012.cf_interrupt();
}
void _hlwRestoreCalibration() {
double value;
value = getSetting("pwrRatioP", 0).toFloat();
if (value > 0) _hlw8012.setPowerMultiplier(value);
value = getSetting("pwrRatioC", 0).toFloat();
if (value > 0) _hlw8012.setCurrentMultiplier(value);
value = getSetting("pwrRatioV", 0).toFloat();
if (value > 0) _hlw8012.setVoltageMultiplier(value);
}
void _hlwPersistCalibration() {
setSetting("pwrRatioP", _hlw8012.getPowerMultiplier());
setSetting("pwrRatioC", _hlw8012.getCurrentMultiplier());
setSetting("pwrRatioV", _hlw8012.getVoltageMultiplier());
saveSettings();
}
// -----------------------------------------------------------------------------
// POWER API
// -----------------------------------------------------------------------------
double _powerCurrent() {
return _hlw8012.getCurrent();
}
double _powerVoltage() {
return _hlw8012.getVoltage();
}
double _powerActivePower() {
return _hlw8012.getActivePower();
}
double _powerApparentPower() {
return _hlw8012.getApparentPower();
}
double _powerReactivePower() {
return _hlw8012.getReactivePower();
}
double _powerPowerFactor() {
return _hlw8012.getPowerFactor();
}
double _powerEnergy() {
return _hlw8012.getEnergy();
}
void _powerEnabledProvider() {
#if HLW8012_USE_INTERRUPTS
if (_power_enabled) {
attachInterrupt(HLW8012_CF1_PIN, _hlw_cf1_isr, CHANGE);
attachInterrupt(HLW8012_CF_PIN, _hlw_cf_isr, CHANGE);
} else {
detachInterrupt(HLW8012_CF1_PIN);
detachInterrupt(HLW8012_CF_PIN);
}
#endif
}
void _powerCalibrateProvider(unsigned char magnitude, double value) {
if (value <= 0) return;
if (magnitude == POWER_MAGNITUDE_ACTIVE) _hlw8012.expectedActivePower(value);
if (magnitude == POWER_MAGNITUDE_CURRENT) _hlw8012.expectedCurrent(value);
if (magnitude == POWER_MAGNITUDE_VOLTAGE) _hlw8012.expectedVoltage(value);
_hlwPersistCalibration();
}
void _powerResetCalibrationProvider() {
_hlw8012.resetMultipliers();
delSetting("pwrRatioC");
delSetting("pwrRatioV");
delSetting("pwrRatioP");
saveSettings();
}
void _powerConfigureProvider() {
// Nothing to do
}
void _powerSetupProvider() {
// Initialize HLW8012
// void begin(unsigned char cf_pin, unsigned char cf1_pin, unsigned char sel_pin, unsigned char currentWhen = HIGH, bool use_interrupts = false, unsigned long pulse_timeout = PULSE_TIMEOUT);
// * cf_pin, cf1_pin and sel_pin are GPIOs to the HLW8012 IC
// * currentWhen is the value in sel_pin to select current sampling
// * set use_interrupts to true to use interrupts to monitor pulse widths
// * leave pulse_timeout to the default value, recommended when using interrupts
#if HLW8012_USE_INTERRUPTS
_hlw8012.begin(HLW8012_CF_PIN, HLW8012_CF1_PIN, HLW8012_SEL_PIN, HLW8012_SEL_CURRENT, true);
#else
_hlw8012.begin(HLW8012_CF_PIN, HLW8012_CF1_PIN, HLW8012_SEL_PIN, HLW8012_SEL_CURRENT, false, 1000000);
#endif
// These values are used to calculate current, voltage and power factors as per datasheet formula
// These are the nominal values for the Sonoff POW resistors:
// * The CURRENT_RESISTOR is the 1milliOhm copper-manganese resistor in series with the main line
// * The VOLTAGE_RESISTOR_UPSTREAM are the 5 470kOhm resistors in the voltage divider that feeds the V2P pin in the HLW8012
// * The VOLTAGE_RESISTOR_DOWNSTREAM is the 1kOhm resistor in the voltage divider that feeds the V2P pin in the HLW8012
_hlw8012.setResistors(HLW8012_CURRENT_R, HLW8012_VOLTAGE_R_UP, HLW8012_VOLTAGE_R_DOWN);
_hlwRestoreCalibration();
#if HLW8012_USE_INTERRUPTS
powerEnabled(true); //Always keep measurement active to keep track of energy used
#else
_power_wifi_onconnect = WiFi.onStationModeGotIP([](WiFiEventStationModeGotIP ipInfo) {
powerEnabled(true);
});
_power_wifi_ondisconnect = WiFi.onStationModeDisconnected([](WiFiEventStationModeDisconnected ipInfo) {
powerEnabled(false);
});
#endif
}
void _powerLoopProvider(bool before) {
if (before) {
static unsigned long last = 0;
if (millis() - last > powerReadInterval()) {
last = millis();
_power_newdata = true;
// Toggle between current and voltage monitoring
#if (HLW8012_USE_INTERRUPTS == 0)
_hlw8012.toggleMode();
#endif // (HLW8012_USE_INTERRUPTS == 0)
}
}
}
#endif // POWER_PROVIDER == POWER_PROVIDER_HLW8012

+ 0
- 234
code/espurna/power_v9261f.ino View File

@ -1,234 +0,0 @@
/*
POWER V9261F MODULE
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
*/
#if POWER_PROVIDER == POWER_PROVIDER_V9261F
// -----------------------------------------------------------------------------
// MODULE GLOBALS AND CACHE
// -----------------------------------------------------------------------------
#include <SoftwareSerial.h>
SoftwareSerial * _v9261f_uart;
double _v9261f_active = 0;
double _v9261f_reactive = 0;
double _v9261f_voltage = 0;
double _v9261f_current = 0;
double _v9261f_ratioP = V9261F_POWER_FACTOR;
double _v9261f_ratioC = V9261F_CURRENT_FACTOR;
double _v9261f_ratioV = V9261F_VOLTAGE_FACTOR;
double _v9261f_ratioR = V9261F_RPOWER_FACTOR;
unsigned char _v9261f_data[24];
// -----------------------------------------------------------------------------
// HAL
// -----------------------------------------------------------------------------
void _v9261fRead() {
static unsigned char state = 0;
static unsigned long last = 0;
static bool found = false;
static unsigned char index = 0;
if (state == 0) {
while (_v9261f_uart->available()) {
_v9261f_uart->flush();
found = true;
last = millis();
}
if (found && (millis() - last > V9261F_SYNC_INTERVAL)) {
_v9261f_uart->flush();
index = 0;
state = 1;
}
} else if (state == 1) {
while (_v9261f_uart->available()) {
_v9261f_uart->read();
if (index++ >= 7) {
_v9261f_uart->flush();
index = 0;
state = 2;
}
}
} else if (state == 2) {
while (_v9261f_uart->available()) {
_v9261f_data[index] = _v9261f_uart->read();
if (index++ >= 19) {
_v9261f_uart->flush();
last = millis();
state = 3;
}
}
} else if (state == 3) {
if (_v9261fChecksum()) {
_v9261f_active = (double) (
(_v9261f_data[3]) +
(_v9261f_data[4] << 8) +
(_v9261f_data[5] << 16) +
(_v9261f_data[6] << 24)
) / _v9261f_ratioP;
_v9261f_reactive = (double) (
(_v9261f_data[7]) +
(_v9261f_data[8] << 8) +
(_v9261f_data[9] << 16) +
(_v9261f_data[10] << 24)
) / _v9261f_ratioR;
_v9261f_voltage = (double) (
(_v9261f_data[11]) +
(_v9261f_data[12] << 8) +
(_v9261f_data[13] << 16) +
(_v9261f_data[14] << 24)
) / _v9261f_ratioV;
_v9261f_current = (double) (
(_v9261f_data[15]) +
(_v9261f_data[16] << 8) +
(_v9261f_data[17] << 16) +
(_v9261f_data[18] << 24)
) / _v9261f_ratioC;
if (_v9261f_active < 0) _v9261f_active = 0;
if (_v9261f_reactive < 0) _v9261f_reactive = 0;
if (_v9261f_voltage < 0) _v9261f_voltage = 0;
if (_v9261f_current < 0) _v9261f_current = 0;
_power_newdata = true;
}
last = millis();
index = 0;
state = 4;
} else if (state == 4) {
while (_v9261f_uart->available()) {
_v9261f_uart->flush();
last = millis();
}
if (millis() - last > V9261F_SYNC_INTERVAL) {
state = 1;
}
}
}
bool _v9261fChecksum() {
unsigned char checksum = 0;
for (unsigned char i = 0; i < 19; i++) {
checksum = checksum + _v9261f_data[i];
}
checksum = ~checksum + 0x33;
return checksum == _v9261f_data[19];
}
// -----------------------------------------------------------------------------
// POWER API
// -----------------------------------------------------------------------------
double _powerCurrent() {
return _v9261f_current;
}
double _powerVoltage() {
return _v9261f_voltage;
}
double _powerActivePower() {
return _v9261f_active;
}
double _powerApparentPower() {
return sqrt(_v9261f_reactive * _v9261f_reactive + _v9261f_active * _v9261f_active);
}
double _powerReactivePower() {
return _v9261f_reactive;
}
double _powerPowerFactor() {
double apparent = _powerApparentPower();
if (apparent > 0) return _powerActivePower() / apparent;
return 1;
}
void _powerEnabledProvider() {
// Nothing to do
}
void _powerConfigureProvider() {
_v9261f_ratioP = getSetting("pwrRatioP", V9261F_POWER_FACTOR).toFloat();
_v9261f_ratioV = getSetting("pwrRatioV", V9261F_VOLTAGE_FACTOR).toFloat();
_v9261f_ratioC = getSetting("pwrRatioC", V9261F_CURRENT_FACTOR).toFloat();
_v9261f_ratioR = getSetting("pwrRatioR", V9261F_RPOWER_FACTOR).toFloat();
}
void _powerCalibrateProvider(unsigned char magnitude, double value) {
if (value <= 0) return;
if (magnitude == POWER_MAGNITUDE_ACTIVE) {
_v9261f_ratioP = _v9261f_ratioP * (_v9261f_active / value);
setSetting("pwrRatioP", _v9261f_ratioP);
}
if (magnitude == POWER_MAGNITUDE_CURRENT) {
_v9261f_ratioC = _v9261f_ratioC * (_v9261f_current / value);
setSetting("pwrRatioC", _v9261f_ratioC);
}
if (magnitude == POWER_MAGNITUDE_VOLTAGE) {
_v9261f_ratioV = _v9261f_ratioV * (_v9261f_voltage / value);
setSetting("pwrRatioV", _v9261f_ratioV);
}
if (magnitude == POWER_MAGNITUDE_POWER_FACTOR) {
if (value < 100) {
double apparent = _v9261f_ratioP / (value / 100);
value = sqrt(apparent * apparent - _v9261f_ratioP * _v9261f_ratioP);
_v9261f_ratioR = _v9261f_ratioR * (_v9261f_reactive / value);
setSetting("pwrRatioR", _v9261f_ratioR);
}
}
saveSettings();
}
void _powerResetCalibrationProvider() {
delSetting("pwrRatioP");
delSetting("pwrRatioC");
delSetting("pwrRatioV");
delSetting("pwrRatioR");
_powerConfigureProvider();
saveSettings();
}
void _powerSetupProvider() {
_v9261f_uart = new SoftwareSerial(V9261F_PIN, SW_SERIAL_UNUSED_PIN, V9261F_PIN_INVERSE, 256);
_v9261f_uart->begin(V9261F_BAUDRATE);
}
void _powerLoopProvider(bool before) {
if (before) {
_v9261fRead();
}
}
#endif // POWER_PROVIDER == POWER_PROVIDER_V9261F

+ 78
- 17
code/espurna/sensor.ino View File

@ -149,8 +149,14 @@ void _sensorWebSocketStart(JsonObject& root) {
#if EMON_ANALOG_SUPPORT #if EMON_ANALOG_SUPPORT
if (sensor->getID() == SENSOR_EMON_ANALOG_ID) { if (sensor->getID() == SENSOR_EMON_ANALOG_ID) {
root["emonVisible"] = 1; root["emonVisible"] = 1;
root["pwrRatioC"] = ((EmonAnalogSensor *) sensor)->getCurrentRatio(0);
root["pwrVoltage"] = ((EmonAnalogSensor *) sensor)->getVoltage();
root["pwrVoltage"] = _sensors[i]->getVoltage();
hasSensors = true;
}
#endif
#if HLW8012_SUPPORT
if (sensor->getID() == SENSOR_HLW8012_ID) {
root["hlwVisible"] = 1;
hasSensors = true; hasSensors = true;
} }
#endif #endif
@ -329,6 +335,17 @@ void _sensorInit() {
} }
#endif #endif
#if HLW8012_SUPPORT
{
HLW8012Sensor * sensor = new HLW8012Sensor();
sensor->setSEL(HLW8012_SEL_PIN);
sensor->setCF(HLW8012_CF_PIN);
sensor->setCF1(HLW8012_CF1_PIN);
sensor->setSELCurrent(HLW8012_SEL_CURRENT);
_sensors.push_back(sensor);
}
#endif
#if MHZ19_SUPPORT #if MHZ19_SUPPORT
{ {
MHZ19Sensor * sensor = new MHZ19Sensor(); MHZ19Sensor * sensor = new MHZ19Sensor();
@ -376,35 +393,75 @@ void _sensorInit() {
void _sensorConfigure() { void _sensorConfigure() {
for (unsigned char i=0; i<_sensors.size(); i++) {
double value;
BaseSensor * sensor = _sensors[i];
for (unsigned char i=0; i<_sensors.size(); i++) {
#if EMON_ANALOG_SUPPORT #if EMON_ANALOG_SUPPORT
if (sensor->getID() == SENSOR_EMON_ANALOG_ID) {
if (_sensors[i]->getID() == SENSOR_EMON_ANALOG_ID) {
AnalogSensor * sensor = (AnalogSensor *) _sensors[i];
unsigned int expected = getSetting("pwrExpectedP", 0).toInt();
if (expected > 0) {
((EmonAnalogSensor *) sensor)->expectedPower(0, expected);
setSetting("pwrRatioC", ((EmonAnalogSensor *) sensor)->getCurrentRatio(0));
if (value = getSetting("pwrExpectedP", 0).toInt() == 0) {
value = getSetting("pwrRatioC", EMON_CURRENT_RATIO).toFloat();
if (value > 0) sensor->setCurrentRatio(0, value);
} else {
sensor->expectedPower(0, value);
setSetting("pwrRatioC", sensor->getCurrentRatio(0));
} }
if (getSetting("pwrResetCalibration", 0).toInt() == 1) { if (getSetting("pwrResetCalibration", 0).toInt() == 1) {
((EmonAnalogSensor *) sensor)->setCurrentRatio(0, EMON_CURRENT_RATIO);
sensor->setCurrentRatio(0, EMON_CURRENT_RATIO);
delSetting("pwrRatioC"); delSetting("pwrRatioC");
} }
((EmonAnalogSensor *) sensor)->setCurrentRatio(0, getSetting("pwrRatioC", EMON_CURRENT_RATIO).toFloat());
((EmonAnalogSensor *) sensor)->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE).toInt());
sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE).toInt());
delSetting("pwrExpectedP");
delSetting("pwrResetCalibration");
} }
#endif
#endif // EMON_ANALOG_SUPPORT
#if HLW8012_SUPPORT
if (_sensors[i]->getID() == SENSOR_HLW8012_ID) {
HLW8012Sensor * sensor = (HLW8012Sensor *) _sensors[i];
if (value = getSetting("pwrExpectedC", 0).toInt() == 0) {
value = getSetting("pwrRatioC", 0).toFloat();
if (value > 0) sensor->setCurrentRatio(value);
} else {
sensor->expectedCurrent(value);
setSetting("pwrRatioC", sensor->getCurrentRatio());
}
if (value = getSetting("pwrExpectedV", 0).toInt() == 0) {
value = getSetting("pwrRatioV", 0).toFloat();
if (value > 0) sensor->setVoltageRatio(value);
} else {
sensor->expectedVoltage(value);
setSetting("pwrRatioV", sensor->getVoltageRatio());
}
if (value = getSetting("pwrExpectedP", 0).toInt() == 0) {
value = getSetting("pwrRatioP", 0).toFloat();
if (value > 0) sensor->setPowerRatio(value);
} else {
sensor->expectedPower(value);
setSetting("pwrRatioP", sensor->getPowerRatio());
}
if (getSetting("pwrResetCalibration", 0).toInt() == 1) {
sensor->resetRatios();
delSetting("pwrRatioC");
delSetting("pwrRatioV");
delSetting("pwrRatioP");
}
}
#endif // HLW8012_SUPPORT
// Force sensor to reload config // Force sensor to reload config
sensor->begin();
_sensors[i]->begin();
} }
@ -414,7 +471,11 @@ void _sensorConfigure() {
_sensor_temperature_correction = getSetting("tmpCorrection", SENSOR_TEMPERATURE_CORRECTION).toFloat(); _sensor_temperature_correction = getSetting("tmpCorrection", SENSOR_TEMPERATURE_CORRECTION).toFloat();
// Save settings // Save settings
saveSettings();
delSetting("pwrExpectedP");
delSetting("pwrExpectedC");
delSetting("pwrExpectedV");
delSetting("pwrResetCalibration");
//saveSettings();
} }


+ 10
- 10
code/espurna/sensors/BaseSensor.h View File

@ -147,7 +147,7 @@ class BaseSensor {
unsigned char count() { return _count; } unsigned char count() { return _count; }
// Handle interrupt calls // Handle interrupt calls
virtual void handleInterrupt(unsigned char gpio) {}
void ICACHE_RAM_ATTR handleInterrupt(unsigned char gpio) {}
protected: protected:
@ -174,20 +174,20 @@ class BaseSensor {
BaseSensor * _isr_sensor_instance[16] = {NULL}; BaseSensor * _isr_sensor_instance[16] = {NULL};
void _sensor_isr(unsigned char gpio) {
void ICACHE_RAM_ATTR _sensor_isr(unsigned char gpio) {
if (_isr_sensor_instance[gpio]) { if (_isr_sensor_instance[gpio]) {
_isr_sensor_instance[gpio]->handleInterrupt(gpio); _isr_sensor_instance[gpio]->handleInterrupt(gpio);
} }
} }
void _sensor_isr_0() { _sensor_isr(0); }
void _sensor_isr_2() { _sensor_isr(2); }
void _sensor_isr_4() { _sensor_isr(4); }
void _sensor_isr_5() { _sensor_isr(5); }
void _sensor_isr_12() { _sensor_isr(12); }
void _sensor_isr_13() { _sensor_isr(13); }
void _sensor_isr_14() { _sensor_isr(14); }
void _sensor_isr_15() { _sensor_isr(15); }
void ICACHE_RAM_ATTR _sensor_isr_0() { _sensor_isr(0); }
void ICACHE_RAM_ATTR _sensor_isr_2() { _sensor_isr(2); }
void ICACHE_RAM_ATTR _sensor_isr_4() { _sensor_isr(4); }
void ICACHE_RAM_ATTR _sensor_isr_5() { _sensor_isr(5); }
void ICACHE_RAM_ATTR _sensor_isr_12() { _sensor_isr(12); }
void ICACHE_RAM_ATTR _sensor_isr_13() { _sensor_isr(13); }
void ICACHE_RAM_ATTR _sensor_isr_14() { _sensor_isr(14); }
void ICACHE_RAM_ATTR _sensor_isr_15() { _sensor_isr(15); }
void (*_sensor_isrs[16])() = { void (*_sensor_isrs[16])() = {
_sensor_isr_0, NULL, _sensor_isr_2, NULL, _sensor_isr_4, _sensor_isr_5, _sensor_isr_0, NULL, _sensor_isr_2, NULL, _sensor_isr_4, _sensor_isr_5,


+ 1
- 1
code/espurna/sensors/ECH1560Sensor.h View File

@ -86,7 +86,7 @@ class ECH1560Sensor : public BaseSensor {
if (_interrupt_gpio == gpio) _interrupt_gpio = GPIO_NONE; if (_interrupt_gpio == gpio) _interrupt_gpio = GPIO_NONE;
} }
void handleInterrupt() {
void ICACHE_RAM_ATTR handleInterrupt() {
_isr(); _isr();
} }


+ 1
- 1
code/espurna/sensors/EventSensor.h View File

@ -101,7 +101,7 @@ class EventSensor : public BaseSensor {
} }
// Handle interrupt calls // Handle interrupt calls
void handleInterrupt(unsigned char gpio) {
void ICACHE_RAM_ATTR handleInterrupt(unsigned char gpio) {
(void) gpio; (void) gpio;
static unsigned long last = 0; static unsigned long last = 0;
if (millis() - last > _debounce) { if (millis() - last > _debounce) {


+ 258
- 0
code/espurna/sensors/HLW8012Sensor.h View File

@ -0,0 +1,258 @@
// -----------------------------------------------------------------------------
// Event Counter Sensor
// Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#pragma once
#include "Arduino.h"
#include "BaseSensor.h"
#include <ESP8266WiFi.h>
#include <HLW8012.h>
class HLW8012Sensor : public BaseSensor {
public:
// ---------------------------------------------------------------------
// Public
// ---------------------------------------------------------------------
HLW8012Sensor(): BaseSensor() {
_count = 7;
_sensor_id = SENSOR_HLW8012_ID;
}
~HLW8012Sensor() {
detach(_interrupt_cf);
detach(_interrupt_cf1);
}
void expectedCurrent(double expected) {
_hlw8012->expectedCurrent(expected);
}
void expectedVoltage(unsigned int expected) {
_hlw8012->expectedVoltage(expected);
}
void expectedPower(unsigned int expected) {
_hlw8012->expectedActivePower(expected);
}
void resetRatios() {
_hlw8012->resetMultipliers();
}
// ---------------------------------------------------------------------
void setSEL(unsigned char sel) {
if (_sel == sel) return;
_sel = sel;
_dirty = true;
}
void setCF(unsigned char cf) {
if (_cf == cf) return;
_cf = cf;
_dirty = true;
}
void setCF1(unsigned char cf1) {
if (_cf1 == cf1) return;
_cf1 = cf1;
_dirty = true;
}
void setSELCurrent(bool value) {
_sel_current = value;
}
void setCurrentRatio(double value) {
_hlw8012->setCurrentMultiplier(value);
};
void setVoltageRatio(double value) {
_hlw8012->setVoltageMultiplier(value);
};
void setPowerRatio(double value) {
_hlw8012->setPowerMultiplier(value);
};
// ---------------------------------------------------------------------
unsigned char getSEL() {
return _sel;
}
unsigned char getCF() {
return _cf;
}
unsigned char getCF1() {
return _cf1;
}
unsigned char getSELCurrent() {
return _sel_current;
}
double getCurrentRatio() {
return _hlw8012->getCurrentMultiplier();
};
double getVoltageRatio() {
return _hlw8012->getVoltageMultiplier();
};
double getPowerRatio() {
return _hlw8012->getPowerMultiplier();
};
// ---------------------------------------------------------------------
// Sensors API
// ---------------------------------------------------------------------
// Initialization method, must be idempotent
// Defined outside the class body
void begin() {
if (_hlw8012) delete _hlw8012;
_hlw8012 = new HLW8012();
// Initialize HLW8012
// void begin(unsigned char cf_pin, unsigned char cf1_pin, unsigned char sel_pin, unsigned char currentWhen = HIGH, bool use_interrupts = false, unsigned long pulse_timeout = PULSE_TIMEOUT);
// * cf_pin, cf1_pin and sel_pin are GPIOs to the HLW8012 IC
// * currentWhen is the value in sel_pin to select current sampling
// * set use_interrupts to true to use interrupts to monitor pulse widths
// * leave pulse_timeout to the default value, recommended when using interrupts
#if HLW8012_USE_INTERRUPTS
_hlw8012->begin(_cf, _cf1, _sel, _sel_current, true);
#else
_hlw8012->begin(_cf, _cf1, _sel, _sel_current, false, 1000000);
#endif
// These values are used to calculate current, voltage and power factors as per datasheet formula
// These are the nominal values for the Sonoff POW resistors:
// * The CURRENT_RESISTOR is the 1milliOhm copper-manganese resistor in series with the main line
// * The VOLTAGE_RESISTOR_UPSTREAM are the 5 470kOhm resistors in the voltage divider that feeds the V2P pin in the HLW8012
// * The VOLTAGE_RESISTOR_DOWNSTREAM is the 1kOhm resistor in the voltage divider that feeds the V2P pin in the HLW8012
_hlw8012->setResistors(HLW8012_CURRENT_R, HLW8012_VOLTAGE_R_UP, HLW8012_VOLTAGE_R_DOWN);
// Handle interrupts
#if HLW8012_USE_INTERRUPTS
_enable(true);
#else
_onconnect_handler = WiFi.onStationModeGotIP([this](WiFiEventStationModeGotIP ipInfo) {
_enable(true);
});
_ondisconnect_handler = WiFi.onStationModeDisconnected([this](WiFiEventStationModeDisconnected ipInfo) {
_enable(false);
});
#endif
}
// Descriptive name of the sensor
String description() {
char buffer[25];
snprintf(buffer, sizeof(buffer), "HLW8012 @ GPIO(%i,%i,%i)", _sel, _cf, _cf1);
return String(buffer);
}
// 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_VOLTAGE;
if (index == 2) return MAGNITUDE_POWER_ACTIVE;
if (index == 3) return MAGNITUDE_POWER_REACTIVE;
if (index == 4) return MAGNITUDE_POWER_APPARENT;
if (index == 5) return MAGNITUDE_POWER_FACTOR;
if (index == 6) return MAGNITUDE_ENERGY;
_error = SENSOR_ERROR_OUT_OF_RANGE;
return MAGNITUDE_NONE;
}
// Current value for slot # index
double value(unsigned char index) {
_error = SENSOR_ERROR_OK;
if (index == 0) return _hlw8012->getCurrent();
if (index == 1) return _hlw8012->getVoltage();
if (index == 2) return _hlw8012->getActivePower();
if (index == 3) return _hlw8012->getReactivePower();
if (index == 4) return _hlw8012->getApparentPower();
if (index == 5) return _hlw8012->getPowerFactor();
if (index == 6) return _hlw8012->getEnergy();
_error = SENSOR_ERROR_OUT_OF_RANGE;
return 0;
}
// Post-read hook (usually to reset things)
void post() {
// Toggle between current and voltage monitoring
#if (HLW8012_USE_INTERRUPTS == 0)
_hlw8012->toggleMode();
#endif // (HLW8012_USE_INTERRUPTS == 0)
}
// Handle interrupt calls
void ICACHE_RAM_ATTR handleInterrupt(unsigned char gpio) {
if (gpio == _interrupt_cf) _hlw8012->cf_interrupt();
if (gpio == _interrupt_cf1) _hlw8012->cf1_interrupt();
}
// Interrupt attach callback
void attached(unsigned char gpio) {
BaseSensor::attached(gpio);
if (_cf == gpio) _interrupt_cf = gpio;
if (_cf1 == gpio) _interrupt_cf1 = gpio;
}
// Interrupt detach callback
void detached(unsigned char gpio) {
BaseSensor::detached(gpio);
if (_interrupt_cf == gpio) _interrupt_cf = GPIO_NONE;
if (_interrupt_cf1 == gpio) _interrupt_cf1 = GPIO_NONE;
}
protected:
// ---------------------------------------------------------------------
// Protected
// ---------------------------------------------------------------------
void _enable(bool value) {
if (value) {
if (_interrupt_cf != _cf) {
detach(_interrupt_cf);
attach(this, _cf, CHANGE);
}
if (_interrupt_cf1 != _cf1) {
detach(_interrupt_cf1);
attach(this, _cf1, CHANGE);
}
} else {
detach(_interrupt_cf);
detach(_interrupt_cf1);
}
}
// ---------------------------------------------------------------------
unsigned char _sel;
unsigned char _cf;
unsigned char _cf1;
bool _sel_current;
HLW8012 * _hlw8012 = NULL;
WiFiEventHandler _onconnect_handler;
WiFiEventHandler _ondisconnect_handler;
unsigned char _interrupt_cf = GPIO_NONE;
unsigned char _interrupt_cf1 = GPIO_NONE;
};

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


+ 0
- 44
code/espurna/ws.ino View File

@ -153,50 +153,6 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) {
key = String("adminPass"); key = String("adminPass");
} }
// -----------------------------------------------------------------
// POWER
// -----------------------------------------------------------------
#if POWER_PROVIDER != POWER_PROVIDER_NONE
/*
if (key == "pwrExpectedP") {
powerCalibrate(POWER_MAGNITUDE_ACTIVE, value.toFloat());
changed = true;
continue;
}
if (key == "pwrExpectedV") {
powerCalibrate(POWER_MAGNITUDE_VOLTAGE, value.toFloat());
changed = true;
continue;
}
if (key == "pwrExpectedC") {
powerCalibrate(POWER_MAGNITUDE_CURRENT, value.toFloat());
changed = true;
continue;
}
if (key == "pwrExpectedF") {
powerCalibrate(POWER_MAGNITUDE_POWER_FACTOR, value.toFloat());
changed = true;
continue;
}
if (key == "pwrResetCalibration") {
if (value.toInt() == 1) {
powerResetCalibration();
changed = true;
}
continue;
}
*/
#endif
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// DOMOTICZ // DOMOTICZ
// ----------------------------------------------------------------- // -----------------------------------------------------------------


+ 0
- 17
code/html/custom.js View File

@ -28,23 +28,6 @@ function initMessages() {
messages[10] = "Session expired, please reload page..."; messages[10] = "Session expired, please reload page...";
} }
#define SENSOR_DHTXX_ID 0x01
#define SENSOR_DALLAS_ID 0x02
#define SENSOR_EMON_ANALOG_ID 0x03
#define SENSOR_EMON_ADC121_ID 0x04
#define SENSOR_EMON_ADS1X15_ID 0x05
#define SENSOR_HLW8012_ID 0x06
#define SENSOR_V9261F_ID 0x07
#define SENSOR_ECH1560_ID 0x08
#define SENSOR_ANALOG_ID 0x09
#define SENSOR_DIGITAL_ID 0x10
#define SENSOR_EVENTS_ID 0x11
#define SENSOR_PMSX003_ID 0x12
#define SENSOR_BMX280_ID 0x13
#define SENSOR_MHZ19_ID 0x14
#define SENSOR_SI7021_ID 0x15
#define SENSOR_SHT3X_I2C_ID 0x16
function sensorName(id) { function sensorName(id) {
var names = [ var names = [
"DHT", "Dallas", "Emon Analog", "Emon ADC121", "Emon ADS1X15", "DHT", "Dallas", "Emon Analog", "Emon ADC121", "Emon ADS1X15",


+ 19
- 76
code/html/index.html View File

@ -171,43 +171,6 @@
<div id="magnitudes"> <div id="magnitudes">
</div> </div>
<!--
<div class="pure-g module module-emon module-hlw module-v9261f module-ech1560">
<label class="pure-u-1 pure-u-sm-1-4">Current</label>
<input class="pure-u-1 pure-u-sm-3-4" type="text" name="pwrCurrent" post=" A" readonly />
</div>
<div class="pure-g module module-emon module-hlw module-v9261f module-ech1560">
<label class="pure-u-1 pure-u-sm-1-4">Voltage</label>
<input class="pure-u-1 pure-u-sm-3-4" type="text" name="pwrVoltage" post=" V" readonly />
</div>
<div class="pure-g module module-hlw module-v9261f">
<label class="pure-u-1 pure-u-sm-1-4">Active Power</label>
<input class="pure-u-1 pure-u-sm-3-4" type="text" name="pwrActive" post=" W" readonly />
</div>
<div class="pure-g module module-emon module-hlw module-v9261f module-ech1560">
<label class="pure-u-1 pure-u-sm-1-4">Apparent Power</label>
<input class="pure-u-1 pure-u-sm-3-4" type="text" name="pwrApparent" post=" VA" readonly />
</div>
<div class="pure-g module module-hlw module-v9261f">
<label class="pure-u-1 pure-u-sm-1-4">Reactive Power</label>
<input class="pure-u-1 pure-u-sm-3-4" type="text" name="pwrReactive" post=" VAR" readonly />
</div>
<div class="pure-g module module-hlw module-v9261f">
<label class="pure-u-1 pure-u-sm-1-4">Power Factor</label>
<input class="pure-u-1 pure-u-sm-3-4" type="text" name="pwrFactor" post="%" readonly />
</div>
<div class="pure-g module module-emon module-hlw module-v9261f module-ech1560">
<label class="pure-u-1 pure-u-sm-1-4">Energy</label>
<input class="pure-u-1 pure-u-sm-3-4" type="text" name="pwrEnergy" post=" J (aggregated)" readonly />
</div>
-->
<div class="pure-u-1 state"> <div class="pure-u-1 state">
<div class="pure-u-1 pure-u-sm-1-4">Manufacturer</div> <div class="pure-u-1 pure-u-sm-1-4">Manufacturer</div>
@ -925,64 +888,44 @@
--> -->
<legend>Energy monitor</legend>
<!--
<div class="pure-g module module-emon">
<label class="pure-u-1 pure-u-md-1-4">Current Ratio</label>
<input class="pure-u-1 pure-u-md-3-4" name="pwrRatioC" type="text" size="8" tabindex="51" />
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">In A/V. This number is usually written in the CT if it has a built-in burden resistor, otherwise you will have to calculate it according to the resistor you are using.</div>
</div>
-->
<legend class="module module-hlw module-emon">Energy monitor</legend>
<div class="pure-g module module-emon"> <div class="pure-g module module-emon">
<label class="pure-u-1 pure-u-md-1-4">Voltage</label> <label class="pure-u-1 pure-u-md-1-4">Voltage</label>
<input class="pure-u-1 pure-u-md-3-4" name="pwrVoltage" type="text" size="8" tabindex="52" />
<input class="pure-u-1 pure-u-md-3-4" name="pwrVoltage" type="text" size="8" tabindex="51" />
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div> <div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">Mains voltage in your system (in V).</div> <div class="pure-u-1 pure-u-md-3-4 hint">Mains voltage in your system (in V).</div>
</div> </div>
<div class="pure-g module module-hlw module-emon module-v9261f">
<label class="pure-u-1 pure-u-md-1-4">Expected Power</label>
<input class="pure-u-1 pure-u-md-3-4 pwrExpected" name="pwrExpectedP" type="text" size="8" tabindex="53" placeholder="0" />
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">Calibrate your sensor connecting a pure resistive load (like a bulb) and enter here the its nominal power or use a multimeter. In Watts.</div>
</div>
<div class="pure-g module module-hlw module-emon module-v9261f">
<div class="pure-u-1 pure-u-sm-1-4"><label>Reset calibration</label></div>
<div class="pure-u-1 pure-u-sm-1-4"><input type="checkbox" name="pwrResetCalibration" tabindex="59" /></div>
<div class="pure-u-0 pure-u-md-1-2">&nbsp;</div>
<div class="pure-g module module-hlw">
<label class="pure-u-1 pure-u-md-1-4">Expected Current</label>
<input class="pure-u-1 pure-u-md-3-4 pwrExpected" name="pwrExpectedC" type="text" size="8" tabindex="52" placeholder="0" />
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div> <div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">Move this switch to ON and press "Save" to revert to factory calibration values.</div>
<div class="pure-u-1 pure-u-md-3-4 hint">In Ampers (A). If you are using a pure resistive load like a bulb this will the ratio between the two previous values, i.e. power / voltage. You can also use a current clamp around one fo the power wires to get this value.</div>
</div> </div>
<!--
<div class="pure-g module module-v9261f">
<label class="pure-u-1 pure-u-md-1-4">AC Power Factor</label>
<input class="pure-u-1 pure-u-md-3-4 pwrExpected" name="pwrExpectedF" type="text" size="8" tabindex="51" placeholder="0" />
<div class="pure-g module module-hlw">
<label class="pure-u-1 pure-u-md-1-4">Expected Voltage</label>
<input class="pure-u-1 pure-u-md-3-4 pwrExpected" name="pwrExpectedV" type="text" size="8" tabindex="53" placeholder="0" />
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div> <div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">In percentage (%). You will need to use a calibrated multimeter to get this value and a mixed resistive and reactive load.</div>
<div class="pure-u-1 pure-u-md-3-4 hint">In Volts (V). Enter your the nominal AC voltage for your household or facility, or use multimeter to get this value.</div>
</div> </div>
<div class="pure-g module module-emon module-hlw module-v9261f">
<label class="pure-u-1 pure-u-md-1-4">AC RMS Voltage</label>
<input class="pure-u-1 pure-u-md-3-4 pwrExpected" name="pwrExpectedV" type="text" size="8" tabindex="52" placeholder="0" />
<div class="pure-g module module-hlw module-emon">
<label class="pure-u-1 pure-u-md-1-4">Expected Power</label>
<input class="pure-u-1 pure-u-md-3-4 pwrExpected" name="pwrExpectedP" type="text" size="8" tabindex="54" placeholder="0" />
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div> <div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">In Volts (V). Enter your the nominal AC voltage for your household or facility, or use multimeter to get this value.</div>
<div class="pure-u-1 pure-u-md-3-4 hint">In Watts (W). Calibrate your sensor connecting a pure resistive load (like a bulb) and enter here the its nominal power or use a multimeter.</div>
</div> </div>
<div class="pure-g module module-hlw module-v9261f">
<label class="pure-u-1 pure-u-md-1-4">AC RMS Current</label>
<input class="pure-u-1 pure-u-md-3-4 pwrExpected" name="pwrExpectedC" type="text" size="8" tabindex="55" placeholder="0" />
<div class="pure-g module module-hlw module-emon">
<div class="pure-u-1 pure-u-sm-1-4"><label>Reset calibration</label></div>
<div class="pure-u-1 pure-u-sm-1-4"><input type="checkbox" name="pwrResetCalibration" tabindex="55" /></div>
<div class="pure-u-0 pure-u-md-1-2">&nbsp;</div>
<div class="pure-u-0 pure-u-md-1-4">&nbsp;</div> <div class="pure-u-0 pure-u-md-1-4">&nbsp;</div>
<div class="pure-u-1 pure-u-md-3-4 hint">In Ampers (A). If you are using a pure resistive load like a bulb this will the ratio between the two previous values, i.e. power / voltage. You can also use a current clamp around one fo the power wires to get this value.</div>
<div class="pure-u-1 pure-u-md-3-4 hint">Move this switch to ON and press "Save" to revert to factory calibration values.</div>
</div> </div>
-->
</fieldset> </fieldset>
</div> </div>


Loading…
Cancel
Save