diff --git a/README.md b/README.md index 426ec8a34..13dc9afc2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Sonoff-Tasmota Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE. -Current version is **5.0.3** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. +Current version is **5.0.4** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. ### **** ATTENTION Version 5.0.x specific information **** diff --git a/api/arduino/sonoff.ino.bin b/api/arduino/sonoff.ino.bin index 9360ad175..48b5253e2 100644 Binary files a/api/arduino/sonoff.ino.bin and b/api/arduino/sonoff.ino.bin differ diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index ab895a282..cd22875ff 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,10 @@ -/* 5.0.3 20170504 +/* 5.0.4 20170505 + * Add Sonoff Pow Energy Total up to 40 MWh + * Add command EnergyReset 1|2|3 to reset Energy counters (#406) + * Fix Domoticz Energy logging (#411) + * Add command PowerOnState 4 to keep relay always on and disabling all power control (#418) + * + * 5.0.3 20170504 * Add command SensorRetain on|off to enable retaining of mqtt message tele/sonoff/SENSOR (#74) * Change WifiConfig timeout from 60 seconds to 180 seconds (#212) * Change Sonoff Touch command Ledstate functionality by turning led on if power is off (#214) diff --git a/sonoff/settings.h b/sonoff/settings.h index 62c5dce2e..25ed2b426 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -172,6 +172,9 @@ struct SYSCFG { // 4.0.9 uint32_t ip_address[4]; + // 5.0.4 + unsigned long hlw_kWhtotal; + } sysCfg; struct RTCMEM { @@ -179,6 +182,7 @@ struct RTCMEM { byte osw_flag; byte nu1; unsigned long hlw_kWhtoday; + unsigned long hlw_kWhtotal; } rtcMem; // See issue https://github.com/esp8266/Arduino/issues/2913 diff --git a/sonoff/settings.ino b/sonoff/settings.ino index d655586ef..1fd329a95 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -448,6 +448,10 @@ void CFG_DefaultSet2() // 5.0.2 CFG_DefaultSet_5_0_2(); + + // 5.0.4 +// sysCfg.hlw_kWhtotal = 0; + rtcMem.hlw_kWhtotal = 0; } /********************************************************************************************/ @@ -622,7 +626,10 @@ void CFG_Delta() sysCfg.savedata = SAVE_DATA; } - + if (sysCfg.version < 0x05000400) { + sysCfg.hlw_kWhtotal = 0; + rtcMem.hlw_kWhtotal = 0; + } sysCfg.version = VERSION; } } diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 5969a5265..38f2e3ccc 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -10,7 +10,7 @@ * ==================================================== */ -#define VERSION 0x05000300 // 5.0.3 +#define VERSION 0x05000400 // 5.0.4 enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; enum week_t {Last, First, Second, Third, Fourth}; @@ -319,31 +319,35 @@ void setLatchingRelay(uint8_t power, uint8_t state) } } -void setRelay(uint8_t power) +void setRelay(uint8_t rpower) { uint8_t state; - + + if (4 == sysCfg.poweronstate) { // All on and stay on + power = (1 << Maxdevice) -1; + rpower = power; + } if ((SONOFF_DUAL == sysCfg.module) || (CH4 == sysCfg.module)) { Serial.write(0xA0); Serial.write(0x04); - Serial.write(power); + Serial.write(rpower); Serial.write(0xA1); Serial.write('\n'); Serial.flush(); } else if (SONOFF_LED == sysCfg.module) { - sl_setPower(power &1); + sl_setPower(rpower &1); } else if (EXS_RELAY == sysCfg.module) { - setLatchingRelay(power, 1); + setLatchingRelay(rpower, 1); } else { for (byte i = 0; i < Maxdevice; i++) { - state = power &1; + state = rpower &1; if (pin[GPIO_REL1 +i] < 99) { digitalWrite(pin[GPIO_REL1 +i], rel_inverted[i] ? !state : state); } - power >>= 1; + rpower >>= 1; } } hlw_setPowerSteadyCounter(2); @@ -949,8 +953,13 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) return; } else if ((sysCfg.module != MOTOR) && !strcmp_P(type,PSTR("POWERONSTATE"))) { - if ((data_len > 0) && (payload >= 0) && (payload <= 3)) { + if ((data_len > 0) && (payload >= 0) && (payload <= 4)) { sysCfg.poweronstate = payload; + if (4 == sysCfg.poweronstate) { + for(byte i = 1; i <= Maxdevice; i++) { + do_cmnd_power(i, 1); + } + } } snprintf_P(svalue, sizeof(svalue), PSTR("{\"PowerOnState\":%d}"), sysCfg.poweronstate); } @@ -2490,32 +2499,38 @@ void setup() if (MOTOR == sysCfg.module) { sysCfg.poweronstate = 1; // Needs always on else in limbo! } - if ((resetInfo.reason == REASON_DEFAULT_RST) || (resetInfo.reason == REASON_EXT_SYS_RST)) { - if (0 == sysCfg.poweronstate) { // All off - power = 0; - setRelay(power); - } - else if (1 == sysCfg.poweronstate) { // All on - power = (1 << Maxdevice) -1; - setRelay(power); - } - else if (2 == sysCfg.poweronstate) { // All saved state toggle - power = sysCfg.power & ((1 << Maxdevice) -1) ^ 0xFF; - if (sysCfg.flag.savestate) { + if (4 == sysCfg.poweronstate) { // Allways on + setRelay(power); + } else { + if ((resetInfo.reason == REASON_DEFAULT_RST) || (resetInfo.reason == REASON_EXT_SYS_RST)) { + switch (sysCfg.poweronstate) { + case 0: // All off + power = 0; setRelay(power); + break; + case 1: // All on + power = (1 << Maxdevice) -1; + setRelay(power); + break; + case 2: // All saved state toggle + power = sysCfg.power & ((1 << Maxdevice) -1) ^ 0xFF; + if (sysCfg.flag.savestate) { + setRelay(power); + } + break; + case 3: // All saved state + power = sysCfg.power & ((1 << Maxdevice) -1); + if (sysCfg.flag.savestate) { + setRelay(power); + } + break; } - } - else if (3 == sysCfg.poweronstate) { // All saved state + } else { power = sysCfg.power & ((1 << Maxdevice) -1); if (sysCfg.flag.savestate) { setRelay(power); } } - } else { - power = sysCfg.power & ((1 << Maxdevice) -1); - if (sysCfg.flag.savestate) { - setRelay(power); - } } blink_powersave = power; diff --git a/sonoff/xsns_hlw8012.ino b/sonoff/xsns_hlw8012.ino index 4f18f0fb0..47d20d796 100644 --- a/sonoff/xsns_hlw8012.ino +++ b/sonoff/xsns_hlw8012.ino @@ -116,15 +116,17 @@ void hlw_200mS() hlw_fifth_second = 0; if (hlw_EDcntr) { - hlw_len = 1000000 / hlw_EDcntr; + hlw_len = 10000 / hlw_EDcntr; hlw_EDcntr = 0; - hlw_temp = (HLW_PREF * sysCfg.hlw_pcal) / hlw_len; - hlw_kWhtoday += (hlw_temp * 100) / 36; + hlw_temp = ((HLW_PREF * sysCfg.hlw_pcal) / hlw_len) / 36; + hlw_kWhtoday += hlw_temp; rtcMem.hlw_kWhtoday = hlw_kWhtoday; } if (rtcTime.Valid) { if (rtc_loctime() == rtc_midnight()) { sysCfg.hlw_kWhyesterday = hlw_kWhtoday; + sysCfg.hlw_kWhtotal += (hlw_kWhtoday / 1000); + rtcMem.hlw_kWhtotal = sysCfg.hlw_kWhtotal; hlw_kWhtoday = 0; rtcMem.hlw_kWhtoday = hlw_kWhtoday; hlw_mkwh_state = 3; @@ -174,10 +176,12 @@ void hlw_savestate() { sysCfg.hlw_kWhdoy = (rtcTime.Valid) ? rtcTime.DayOfYear : 0; sysCfg.hlw_kWhtoday = hlw_kWhtoday; + sysCfg.hlw_kWhtotal = rtcMem.hlw_kWhtotal; } -boolean hlw_readEnergy(byte option, float &ed, uint16_t &e, uint16_t &w, uint16_t &u, float &i, float &c) +boolean hlw_readEnergy(byte option, float &et, float &ed, uint16_t &e, uint16_t &w, uint16_t &u, float &i, float &c) { + unsigned long cur_kWhtoday = hlw_kWhtoday; unsigned long hlw_len; unsigned long hlw_temp; unsigned long hlw_w; @@ -190,8 +194,10 @@ boolean hlw_readEnergy(byte option, float &ed, uint16_t &e, uint16_t &w, uint16_ //snprintf_P(log, sizeof(log), PSTR("HLW: CF %d, CF1U %d (%d), CF1I %d (%d)"), hlw_cf_plen, hlw_cf1u_plen, hlw_cf1u_pcntmax, hlw_cf1i_plen, hlw_cf1i_pcntmax); //addLog(LOG_LEVEL_DEBUG, log); - if (hlw_kWhtoday) { - ed = (float)hlw_kWhtoday / 100000000; + et = (float)(rtcMem.hlw_kWhtotal + (cur_kWhtoday / 1000)) / 100000; + + if (cur_kWhtoday) { + ed = (float)cur_kWhtoday / 100000000; } else { ed = 0; } @@ -265,6 +271,9 @@ void hlw_init() hlw_Ecntr = 0; hlw_EDcntr = 0; hlw_kWhtoday = (RTC_Valid()) ? rtcMem.hlw_kWhtoday : 0; + if (sysCfg.hlw_kWhtotal > rtcMem.hlw_kWhtotal) { + rtcMem.hlw_kWhtotal = sysCfg.hlw_kWhtotal; + } hlw_SELflag = 0; // Voltage; @@ -311,6 +320,7 @@ void hlw_margin_chk() { char log[LOGSZ]; char svalue[200]; // was MESSZ + float pet; float ped; float pi; float pc; @@ -327,7 +337,7 @@ void hlw_margin_chk() return; } - hlw_readEnergy(0, ped, pe, pw, pu, pi, pc); + hlw_readEnergy(0, pet, ped, pe, pw, pu, pi, pc); if (power && (sysCfg.hlw_pmin || sysCfg.hlw_pmax || sysCfg.hlw_umin || sysCfg.hlw_umax || sysCfg.hlw_imin || sysCfg.hlw_imax)) { piv = (uint16_t)(pi * 1000); @@ -473,6 +483,31 @@ boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len } snprintf_P(svalue, ssvalue, PSTR("{\"CurrentHigh\":\"%d%s\"}"), sysCfg.hlw_imax, (sysCfg.flag.value_units) ? " mA" : ""); } + else if (!strcmp_P(type,PSTR("ENERGYRESET"))) { + if ((data_len > 0) && (payload >= 1) && (payload <= 3)) { + switch (payload) { + case 1: + hlw_kWhtoday = 0; + rtcMem.hlw_kWhtoday = 0; + sysCfg.hlw_kWhtoday = 0; + break; + case 2: + sysCfg.hlw_kWhyesterday = 0; + break; + case 3: + rtcMem.hlw_kWhtotal = 0; + sysCfg.hlw_kWhtotal = rtcMem.hlw_kWhtotal; + break; + } + } + char stemp0[10]; + char stemp1[10]; + char stemp2[10]; + dtostrf((float)sysCfg.hlw_kWhyesterday / 100000000, 1, sysCfg.flag.energy_resolution, stemp0); + dtostrf((float)rtcMem.hlw_kWhtoday / 100000000, 1, sysCfg.flag.energy_resolution, stemp1); + dtostrf((float)(rtcMem.hlw_kWhtotal + (hlw_kWhtoday / 1000)) / 100000, 1, sysCfg.flag.energy_resolution, stemp2); + snprintf_P(svalue, ssvalue, PSTR("{\"EnergyReset\":{\"Total\":%s, \"Yesterday\":%s, \"Today\":%s}}"), stemp2, stemp0, stemp1); + } else if (!strcmp_P(type,PSTR("HLWPCAL"))) { if ((data_len > 0) && (payload > 0) && (payload < 32001)) { sysCfg.hlw_pcal = (payload > 9999) ? payload : HLW_PREF_PULSE; // 12530 @@ -558,7 +593,9 @@ void hlw_mqttStat(byte option, char* svalue, uint16_t ssvalue) char stemp1[10]; char stemp2[10]; char stemp3[10]; + char stemp4[10]; char speriod[20]; + float pet; float ped; float pi; float pc; @@ -566,23 +603,24 @@ void hlw_mqttStat(byte option, char* svalue, uint16_t ssvalue) uint16_t pw; uint16_t pu; - hlw_readEnergy(option, ped, pe, pw, pu, pi, pc); + hlw_readEnergy(option, pet, ped, pe, pw, pu, pi, pc); dtostrf((float)sysCfg.hlw_kWhyesterday / 100000000, 1, sysCfg.flag.energy_resolution, stemp0); dtostrf(ped, 1, sysCfg.flag.energy_resolution, stemp1); dtostrf(pc, 1, 2, stemp2); dtostrf(pi, 1, 3, stemp3); + dtostrf(pet, 1, sysCfg.flag.energy_resolution, stemp4); snprintf_P(speriod, sizeof(speriod), PSTR(", \"Period\":%d"), pe); - snprintf_P(svalue, ssvalue, PSTR("%s\"Yesterday\":%s, \"Today\":%s%s, \"Power\":%d, \"Factor\":%s, \"Voltage\":%d, \"Current\":%s}"), - svalue, stemp0, stemp1, (option) ? speriod : "", pw, stemp2, pu, stemp3); + snprintf_P(svalue, ssvalue, PSTR("%s\"Total\":%s, \"Yesterday\":%s, \"Today\":%s%s, \"Power\":%d, \"Factor\":%s, \"Voltage\":%d, \"Current\":%s}"), + svalue, stemp4, stemp0, stemp1, (option) ? speriod : "", pw, stemp2, pu, stemp3); #ifdef USE_DOMOTICZ - dtostrf(ped * 1000, 1, 1, stemp1); + dtostrf(pet * 1000, 1, 1, stemp1); domoticz_sensor4(pw, stemp1); #endif // USE_DOMOTICZ } void hlw_mqttPresent() { -// {"Time":"2017-03-04T13:37:24", "Yesterday":0.013, "Today":0.000, "Period":0, "Power":0, "Factor":0.00, "Voltage":0, "Current":0.000} +// {"Time":"2017-03-04T13:37:24", "Total":0.013, "Yesterday":0.013, "Today":0.000, "Period":0, "Power":0, "Factor":0.00, "Voltage":0, "Current":0.000} char svalue[200]; // was MESSZ snprintf_P(svalue, sizeof(svalue), PSTR("{\"Time\":\"%s\", "), getDateTime().c_str()); @@ -604,7 +642,8 @@ const char HTTP_ENERGY_SNS[] PROGMEM = "Power%d W" "Power Factor%s" "Energy Today%s kWh" - "Energy Yesterday%s kWh"; + "Energy Yesterday%s kWh" + "Energy Total%s kWh"; String hlw_webPresent() { @@ -613,7 +652,9 @@ String hlw_webPresent() char stemp2[10]; char stemp3[10]; char stemp4[10]; - char sensor[300]; + char stemp5[10]; + char sensor[320]; + float pet; float ped; float pi; float pc; @@ -621,13 +662,14 @@ String hlw_webPresent() uint16_t pw; uint16_t pu; - hlw_readEnergy(0, ped, pe, pw, pu, pi, pc); + hlw_readEnergy(0, pet, ped, pe, pw, pu, pi, pc); dtostrf(pi, 1, 3, stemp); dtostrf(pc, 1, 2, stemp2); dtostrf(ped, 1, sysCfg.flag.energy_resolution, stemp3); dtostrf((float)sysCfg.hlw_kWhyesterday / 100000000, 1, sysCfg.flag.energy_resolution, stemp4); - snprintf_P(sensor, sizeof(sensor), HTTP_ENERGY_SNS, pu, stemp, pw, stemp2, stemp3, stemp4); + dtostrf(pet, 1, sysCfg.flag.energy_resolution, stemp5); + snprintf_P(sensor, sizeof(sensor), HTTP_ENERGY_SNS, pu, stemp, pw, stemp2, stemp3, stemp4, stemp5); page += sensor; return page; }