diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index 4d0e3b5a..5e0acb74 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -7,6 +7,13 @@ #define BUFFER_SIZE 1024 #define HEARTBEAT_INTERVAL 300000 +//-------------------------------------------------------------------------------- +// EEPROM +//-------------------------------------------------------------------------------- + +#define EEPROM_RELAY_STATUS 0 +#define EEPROM_POWER_COUNT 1 + //-------------------------------------------------------------------------------- // RELAY //-------------------------------------------------------------------------------- diff --git a/code/espurna/config/prototypes.h b/code/espurna/config/prototypes.h index 2c4fe604..c3a56929 100644 --- a/code/espurna/config/prototypes.h +++ b/code/espurna/config/prototypes.h @@ -12,3 +12,4 @@ void mqttRegister(void (*callback)(unsigned int, const char *, const char *)); template bool setSetting(const String& key, T value); template String getSetting(const String& key, T defaultValue); template void domoticzSend(const char * key, T value); +template void domoticzSend(const char * key, T nvalue, const char * svalue); diff --git a/code/espurna/config/sensors.h b/code/espurna/config/sensors.h index fa69ee5a..a39793e5 100644 --- a/code/espurna/config/sensors.h +++ b/code/espurna/config/sensors.h @@ -20,6 +20,11 @@ #define DHT_TEMPERATURE_TOPIC "/temperature" #define DHT_HUMIDITY_TOPIC "/humidity" +#define HUMIDITY_NORMAL 0 +#define HUMIDITY_COMFORTABLE 1 +#define HUMIDITY_DRY 2 +#define HUMIDITY_WET 3 + //-------------------------------------------------------------------------------- // DS18B20 temperature sensor // Enable support by passing ENABLE_DS18B20=1 build flag @@ -46,6 +51,7 @@ #define EMON_MAINS_VOLTAGE 230 #define EMON_CURRENT_RATIO 180 #define EMON_POWER_TOPIC "/power" +#define EMON_ENERGY_TOPIC "/energy" //-------------------------------------------------------------------------------- // HLW8012 power sensor (Sonoff POW) diff --git a/code/espurna/dht.ino b/code/espurna/dht.ino index 61ba98f5..c1aeb45e 100644 --- a/code/espurna/dht.ino +++ b/code/espurna/dht.ino @@ -73,8 +73,22 @@ void dhtLoop() { // Send to Domoticz #if ENABLE_DOMOTICZ - domoticzSend("dczTmpIdx", temperature); - domoticzSend("dczHumIdx", humidity); + { + domoticzSend("dczTmpIdx", 0, temperature); + int status; + if (h > 70) { + status = HUMIDITY_WET; + } else if (h > 45) { + status = HUMIDITY_COMFORTABLE; + } else if (h > 30) { + status = HUMIDITY_NORMAL; + } else { + status = HUMIDITY_DRY; + } + char buffer[2]; + sprintf(buffer, "%d", status); + domoticzSend("dczHumIdx", humidity, buffer); + } #endif // Update websocket clients diff --git a/code/espurna/domoticz.ino b/code/espurna/domoticz.ino index 607acb8c..6534b91f 100644 --- a/code/espurna/domoticz.ino +++ b/code/espurna/domoticz.ino @@ -8,13 +8,17 @@ Copyright (C) 2016-2017 by Xose Pérez #if ENABLE_DOMOTICZ -template void domoticzSend(const char * key, T value) { +template void domoticzSend(const char * key, T nvalue, const char * svalue) { unsigned int idx = getSetting(key).toInt(); if (idx > 0) { - char payload[45]; - sprintf(payload, "{\"idx\": %d, \"nvalue\": %s, \"svalue\": \"\"}", idx, String(value).c_str()); + char payload[128]; + snprintf(payload, 128, "{\"idx\": %d, \"nvalue\": %s, \"svalue\": \"%s\"}", idx, String(nvalue).c_str(), svalue); mqttSendRaw(getSetting("dczTopicIn", DOMOTICZ_IN_TOPIC).c_str(), payload); } } +template void domoticzSend(const char * key, T nvalue) { + domoticzSend(key, nvalue, ""); +} + #endif diff --git a/code/espurna/ds18b20.ino b/code/espurna/ds18b20.ino index 2011530f..7424241b 100644 --- a/code/espurna/ds18b20.ino +++ b/code/espurna/ds18b20.ino @@ -62,7 +62,7 @@ void dsLoop() { // Send to Domoticz #if ENABLE_DOMOTICZ - domoticzSend("dczTmpIdx", temperature); + domoticzSend("dczTmpIdx", 0, temperature); #endif // Update websocket clients diff --git a/code/espurna/emon.ino b/code/espurna/emon.ino index f216a866..892fc2bf 100644 --- a/code/espurna/emon.ino +++ b/code/espurna/emon.ino @@ -9,10 +9,12 @@ Copyright (C) 2016-2017 by Xose Pérez #if ENABLE_EMON #include +#include EmonLiteESP emon; double _current = 0; unsigned int _power = 0; +double _energy = 0; // ----------------------------------------------------------------------------- // EMON @@ -26,6 +28,10 @@ unsigned int getPower() { return _power; } +double getEnergy() { + return _energy; +} + double getCurrent() { return _current; } @@ -34,6 +40,20 @@ unsigned int currentCallback() { return analogRead(EMON_CURRENT_PIN); } +void retrieveEnergy() { + unsigned long energy = EEPROM.read(EEPROM_POWER_COUNT + 1); + energy = (energy << 8) + EEPROM.read(EEPROM_POWER_COUNT); + if (energy == 0xFFFF) energy = 0; + _energy = energy; +} + +void saveEnergy() { + unsigned int energy = (int) _energy; + EEPROM.write(EEPROM_POWER_COUNT, energy & 0xFF); + EEPROM.write(EEPROM_POWER_COUNT + 1, (energy >> 8) & 0xFF); + EEPROM.commit(); +} + void powerMonitorSetup() { // backwards compatibility @@ -56,6 +76,11 @@ void powerMonitorSetup() { apiRegister("/api/power", "power", [](char * buffer, size_t len) { snprintf(buffer, len, "%d", _power); }); + apiRegister("/api/energy", "energy", [](char * buffer, size_t len) { + snprintf(buffer, len, "%ld", (unsigned long) _energy); + }); + + retrieveEnergy(); } @@ -108,14 +133,24 @@ void powerMonitorLoop() { if (measurements == EMON_MEASUREMENTS) { _power = (int) ((sum - max - min) * mainsVoltage / (measurements - 2)); + double window = (double) EMON_INTERVAL * EMON_MEASUREMENTS / 1000.0 / 3600.0; + _energy += _power * window; + saveEnergy(); sum = 0; measurements = 0; char power[6]; snprintf(power, 6, "%d", _power); + char energy[8]; + snprintf(energy, 6, "%ld", (unsigned long) _energy); mqttSend(getSetting("emonPowerTopic", EMON_POWER_TOPIC).c_str(), power); + mqttSend(getSetting("emonEnergyTopic", EMON_ENERGY_TOPIC).c_str(), energy); #if ENABLE_DOMOTICZ - domoticzSend("dczPowIdx", power); + { + char buffer[20]; + snprintf(buffer, 20, "%s;%s", power, energy); + domoticzSend("dczPowIdx", 0, buffer); + } #endif diff --git a/code/espurna/pow.ino b/code/espurna/pow.ino index ac2e43b9..a575baf7 100644 --- a/code/espurna/pow.ino +++ b/code/espurna/pow.ino @@ -12,9 +12,11 @@ Copyright (C) 2016-2017 by Xose Pérez #include #include #include +#include HLW8012 hlw8012; bool _powEnabled = false; +double _energy = 0; // ----------------------------------------------------------------------------- // POW @@ -117,8 +119,26 @@ unsigned int getPowerFactor() { return (int) (100 * hlw8012.getPowerFactor()); } +double getEnergy() { + return _energy; +} + // ----------------------------------------------------------------------------- +void retrieveEnergy() { + unsigned long energy = EEPROM.read(EEPROM_POWER_COUNT + 1); + energy = (energy << 8) + EEPROM.read(EEPROM_POWER_COUNT); + if (energy == 0xFFFF) energy = 0; + _energy = energy; +} + +void saveEnergy() { + unsigned int energy = (int) _energy; + EEPROM.write(EEPROM_POWER_COUNT, energy & 0xFF); + EEPROM.write(EEPROM_POWER_COUNT + 1, (energy >> 8) & 0xFF); + EEPROM.commit(); +} + void powSetup() { // Initialize HLW8012 @@ -143,10 +163,16 @@ void powSetup() { // Retrieve calibration values powRetrieveCalibration(); + // Recover energy reading + retrieveEnergy(); + // API definitions apiRegister("/api/power", "power", [](char * buffer, size_t len) { snprintf(buffer, len, "%d", getActivePower()); }); + apiRegister("/api/energy", "energy", [](char * buffer, size_t len) { + snprintf(buffer, len, "%ld", (unsigned long) _energy); + }); apiRegister("/api/current", "current", [](char * buffer, size_t len) { dtostrf(getCurrent(), len-1, 2, buffer); }); @@ -216,8 +242,12 @@ void powLoop() { reactive = (apparent > power) ? sqrt(apparent * apparent - power * power) : 0; factor = (apparent > 0) ? 100 * power / apparent : 100; if (factor > 100) factor = 100; + unsigned long window = (double) POW_REPORT_EVERY * POW_UPDATE_INTERVAL / 1000.0 / 3600.0; + _energy += power * window; + saveEnergy(); mqttSend(getSetting("powPowerTopic", POW_POWER_TOPIC).c_str(), String(power).c_str()); + mqttSend(getSetting("powEnergyTopic", POW_ENERGY_TOPIC).c_str(), String(_energy).c_str()); mqttSend(getSetting("powCurrentTopic", POW_CURRENT_TOPIC).c_str(), String(current).c_str()); mqttSend(getSetting("powVoltageTopic", POW_VOLTAGE_TOPIC).c_str(), String(voltage).c_str()); mqttSend(getSetting("powAPowerTopic", POW_APOWER_TOPIC).c_str(), String(apparent).c_str()); @@ -225,7 +255,11 @@ void powLoop() { mqttSend(getSetting("powPFactorTopic", POW_PFACTOR_TOPIC).c_str(), String(factor).c_str()); #if ENABLE_DOMOTICZ - domoticzSend("dczPowIdx", power); + { + char buffer[20]; + snprintf(buffer, 20, "%d;%ld", power, (unsigned long) _energy); + domoticzSend("dczPowIdx", 0, buffer); + } #endif power_sum = current_sum = voltage_sum = 0; diff --git a/code/espurna/relay.ino b/code/espurna/relay.ino index 65fe03d9..0b66e870 100644 --- a/code/espurna/relay.ino +++ b/code/espurna/relay.ino @@ -208,20 +208,20 @@ void relaySave() { if (relayStatus(i)) mask += bit; bit += bit; } - EEPROM.write(0, mask); + EEPROM.write(EEPROM_RELAY_STATUS, mask); EEPROM.commit(); } void relayRetrieve(bool invert) { recursive = true; unsigned char bit = 1; - unsigned char mask = invert ? ~EEPROM.read(0) : EEPROM.read(0); + unsigned char mask = invert ? ~EEPROM.read(EEPROM_RELAY_STATUS) : EEPROM.read(EEPROM_RELAY_STATUS); for (unsigned int i=0; i < _relays.size(); i++) { relayStatus(i, ((mask & bit) == bit)); bit += bit; } if (invert) { - EEPROM.write(0, mask); + EEPROM.write(EEPROM_RELAY_STATUS, mask); EEPROM.commit(); } recursive = false;