Browse Source

Untested support for ECH1560-based powermeters

fastled
Xose Pérez 6 years ago
parent
commit
5c294876ba
11 changed files with 3844 additions and 3561 deletions
  1. +32
    -0
      code/espurna/config/general.h
  2. +15
    -1
      code/espurna/config/hardware.h
  3. BIN
      code/espurna/data/index.html.gz
  4. +4
    -0
      code/espurna/hardware.ino
  5. +13
    -7
      code/espurna/power.ino
  6. +201
    -0
      code/espurna/power_ech1560.ino
  7. +2
    -2
      code/espurna/power_emon.ino
  8. +3548
    -3548
      code/espurna/static/index.html.gz.h
  9. +3
    -0
      code/espurna/web.ino
  10. +3
    -3
      code/html/index.html
  11. +23
    -0
      code/platformio.ini

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

@ -504,6 +504,7 @@ PROGMEM const char* const custom_reset_string[] = {
#define POWER_PROVIDER_EMON_ADC121 0x11
#define POWER_PROVIDER_HLW8012 0x20
#define POWER_PROVIDER_V9261F 0x30
#define POWER_PROVIDER_ECH1560 0x40
// Available magnitudes
#define POWER_MAGNITUDE_CURRENT 1
@ -566,14 +567,45 @@ PROGMEM const char* const custom_reset_string[] = {
#endif
#if POWER_PROVIDER == POWER_PROVIDER_V9261F
#undef POWER_REPORT_BUFFER
#define POWER_REPORT_BUFFER 60
#ifndef V9261F_PIN
#define V9261F_PIN 2
#endif
#ifndef V9261F_PIN_INVERSE
#define V9261F_PIN_INVERSE 1
#endif
#define V9261F_SYNC_INTERVAL 600
#define V9261F_BAUDRATE 4800
#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
#undef POWER_REPORT_BUFFER
#define POWER_REPORT_BUFFER 60
#ifndef ECH1560_CLK_PIN
#define ECH1560_CLK_PIN 4
#endif
#ifndef ECH1560_MISO_PIN
#define ECH1560_MISO_PIN 5
#endif
#define ECH1560_SYNC_INTERVAL 600
#define ECH1560_BAUDRATE 4800
#define ECH1560_CURRENT_FACTOR 79371434.0
#define ECH1560_VOLTAGE_FACTOR 4160651.0
#define ECH1560_POWER_FACTOR 153699.0
#define ECH1560_RPOWER_FACTOR ECH1560_CURRENT_FACTOR
#endif
// -----------------------------------------------------------------------------


+ 15
- 1
code/espurna/config/hardware.h View File

@ -862,10 +862,24 @@
// V9261F
#define POWER_PROVIDER POWER_PROVIDER_V9261F
#define V9261F_SUPPORT 1
#define V9261F_PIN 2
#define V9261F_PIN_INVERSE 1
// -----------------------------------------------------------------------------
// ECH1560
// -----------------------------------------------------------------------------
#elif defined(GENERIC_ECH1560)
// Info
#define MANUFACTURER "GENERIC"
#define DEVICE "ECH1560"
// V9261F
#define POWER_PROVIDER POWER_PROVIDER_ECH1560
#define ECH1560_CLK_PIN 4
#define ECH1560_MISO_PIN 5
// -----------------------------------------------------------------------------
// Unknown hardware
// -----------------------------------------------------------------------------


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


+ 4
- 0
code/espurna/hardware.ino View File

@ -438,6 +438,10 @@ void hwUpwardsCompatibility() {
setSetting("board", 37);
#elif defined(GENERIC_ECH1560)
setSetting("board", 38);
#else
#error "UNSUPPORTED HARDWARE!"


+ 13
- 7
code/espurna/power.ino View File

@ -146,6 +146,9 @@ void _powerRead() {
#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());
@ -163,19 +166,20 @@ void _powerReport() {
_power_voltage = _filter_voltage.average(true);
_power_active = _filter_active.average(true);
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
_power_apparent = _power_current * _power_voltage;
_power_active = _power_apparent;
double power = _power_apparent;
#endif
_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 energy_delta = power * POWER_ENERGY_FACTOR;
_power_ready = true;
char buf_current[10];
dtostrf(_power_current, -9, POWER_CURRENT_PRECISION, buf_current);
double energy_delta = _power_active * POWER_ENERGY_FACTOR;
char buf_energy[10];
dtostrf(_power_current, -9, POWER_CURRENT_PRECISION, buf_current);
dtostrf(energy_delta, -9, POWER_CURRENT_PRECISION, buf_energy);
{
@ -193,7 +197,7 @@ void _powerReport() {
#if DOMOTICZ_SUPPORT
if (domoticzEnabled()) {
char buffer[20];
snprintf_P(buffer, sizeof(buffer), PSTR("%d;%s"), _power_active, buf_energy);
snprintf_P(buffer, sizeof(buffer), PSTR("%d;%s"), power, buf_energy);
domoticzSend("dczPowIdx", 0, buffer);
domoticzSend("dczCurrentIdx", 0, buf_current);
domoticzSend("dczEnergyIdx", 0, buf_energy);
@ -241,6 +245,7 @@ double getApparentPower() {
return roundTo(_power_apparent, POWER_POWER_DECIMALS);
}
#if POWER_HAS_ACTIVE
double getActivePower() {
return roundTo(_power_active, POWER_POWER_DECIMALS);
}
@ -252,6 +257,7 @@ double getReactivePower() {
double getPowerFactor() {
return roundTo(_power_factor, 2);
}
#endif
// -----------------------------------------------------------------------------
// PUBLIC API


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

@ -0,0 +1,201 @@
/*
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;
}
}
}
// 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_EMON

+ 2
- 2
code/espurna/power_emon.ino View File

@ -81,7 +81,7 @@ double _powerVoltage() {
}
double _powerActivePower() {
return _powerApparentPower();
return 0;
}
double _powerApparentPower() {
@ -103,7 +103,7 @@ void _powerEnabledProvider() {
void _powerCalibrateProvider(unsigned char magnitude, double value) {
if (value <= 0) return;
if (magnitude == POWER_MAGNITUDE_ACTIVE) {
double power = _powerActivePower();
double power = _powerApparentPower();
double ratio = getSetting("pwrRatioC", EMON_CURRENT_RATIO).toFloat();
ratio = ratio * (value / power);
_emon.setCurrentRatio(ratio);


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


+ 3
- 0
code/espurna/web.ino View File

@ -617,6 +617,9 @@ void _wsStart(uint32_t client_id) {
#if POWER_PROVIDER == POWER_PROVIDER_V9261F
root["v9261fVisible"] = 1;
#endif
#if POWER_PROVIDER == POWER_PROVIDER_ECH1560
root["ech1560fVisible"] = 1;
#endif
#endif
#if NOFUSS_SUPPORT


+ 3
- 3
code/html/index.html View File

@ -190,12 +190,12 @@
<input class="pure-u-1 pure-u-sm-3-4" type="text" name="dhtHum" readonly />
</div>
<div class="pure-g module module-emon module-hlw module-v9261f">
<div class="pure-g module module-emon module-hlw module-v9261f module-ech1560">
<label class="pure-u-1 pure-u-sm-1-4" for="pwrCurrent">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">
<div class="pure-g module module-emon module-hlw module-v9261f module-ech1560">
<label class="pure-u-1 pure-u-sm-1-4" for="pwrVoltage">Voltage</label>
<input class="pure-u-1 pure-u-sm-3-4" type="text" name="pwrVoltage" post=" V" readonly />
</div>
@ -205,7 +205,7 @@
<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">
<div class="pure-g module module-emon module-hlw module-v9261f module-ech1560">
<label class="pure-u-1 pure-u-sm-1-4" for="pwrApparent">Apparent Power</label>
<input class="pure-u-1 pure-u-sm-3-4" type="text" name="pwrApparent" post=" VA" readonly />
</div>


+ 23
- 0
code/platformio.ini View File

@ -863,6 +863,29 @@ upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
[env:esp01-ech1560]
platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DGENERIC_ECH1560
monitor_baud = 115200
[env:esp01-ech1560-ota]
platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DGENERIC_ECH1560
upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
# ------------------------------------------------------------------------------
# GENERIC OTA ENVIRONMENTS
# ------------------------------------------------------------------------------


Loading…
Cancel
Save