diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ab62c092f..07406b54f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -52,10 +52,13 @@ The following binary downloads have been compiled with ESP8266/Arduino library c ## Changelog -### Version 8.3.1.1 +### Version 8.3.1.2 - Change IRremoteESP8266 library updated to v2.7.7 +- Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]`` +- Change Energy JSON ExportActive field from ``"ExportActive":[33.736,11.717,16.978]`` to ``"ExportActive":33.736,"ExportTariff":[11.717,16.978]`` - Add command ``Rule0`` to change global rule parameters - Add more functionality to ``Switchmode`` 11 and 12 (#8450) - Add support for VEML6075 UVA/UVB/UVINDEX Sensor by device111 (#8432) - Add support for VEML7700 Ambient light intensity Sensor by device111 (#8432) +- Add Three Phase Export Active Energy to SDM630 driver diff --git a/lib/Unishox-1.0-shadinger/src/unishox.cpp b/lib/Unishox-1.0-shadinger/src/unishox.cpp index 743eed38c..286a16280 100644 --- a/lib/Unishox-1.0-shadinger/src/unishox.cpp +++ b/lib/Unishox-1.0-shadinger/src/unishox.cpp @@ -388,9 +388,9 @@ uint32_t Unishox::getNextBit(void) { in_eof = true; return 1; // return only 1s, which appends 'r' in worst case } - byte_in = in[byte_no++]; + byte_in = pgm_read_byte(&in[byte_no++]); if (ESCAPE_MARKER == byte_in) { - byte_in = in[byte_no++] - 1; // we shouldn't need to test if byte_no >= len, because it should not be possible to end with ESCAPE_MARKER + byte_in = pgm_read_byte(&in[byte_no++]) - 1; // we shouldn't need to test if byte_no >= len, because it should not be possible to end with ESCAPE_MARKER } bit_no = 0; } @@ -479,6 +479,9 @@ int32_t Unishox::unishox_decompress(const char *p_in, size_t p_len, char *p_out, out[ol] = 0; // while ((byte_no << 3) + bit_no - 8 < len) { while (!in_eof) { + if (ol >= len_out) { + break; + } int32_t h, v; char c = 0; byte is_upper = is_all_upper; @@ -564,11 +567,11 @@ int32_t Unishox::unishox_decompress(const char *p_in, size_t p_len, char *p_out, } } out[ol++] = c; - - if (ol >= len_out) { - return -1; // overflow - } } - return ol; + if (ol > len_out) { + return -1; // overflow + } else { + return ol; + } } diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 056a0edd6..b4c77c4ab 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -1,5 +1,11 @@ ## Unreleased (development) +### 8.3.1.2 20200522 + +- Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]`` +- Change Energy JSON ExportActive field from ``"ExportActive":[33.736,11.717,16.978]`` to ``"ExportActive":33.736,"ExportTariff":[11.717,16.978]`` +- Add Three Phase Export Active Energy to SDM630 driver + ### 8.3.1.1 20200518 - Change IRremoteESP8266 library updated to v2.7.7 diff --git a/tasmota/i18n.h b/tasmota/i18n.h index 698192e99..98e20d9ac 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -65,6 +65,7 @@ #define D_JSON_ERROR "Error" #define D_JSON_EVENT "Event" #define D_JSON_EVERY "Every" +#define D_JSON_EXPORT "Export" #define D_JSON_EXPORT_ACTIVE "ExportActive" #define D_JSON_EXPORT_REACTIVE "ExportReactive" #define D_JSON_FAILED "Failed" @@ -294,6 +295,9 @@ #define D_CMND_LEDPOWER "LedPower" #define D_CMND_LEDSTATE "LedState" #define D_CMND_LEDMASK "LedMask" +#define D_CMND_LEDPWMOFF "LedPwmOff" +#define D_CMND_LEDPWMON "LedPwmOn" +#define D_CMND_LEDPWMMODE "LedPwmMode" #define D_CMND_WIFIPOWER "WifiPower" #define D_CMND_SPEEDUNIT "SpeedUnit" #define D_CMND_I2CSCAN "I2CScan" diff --git a/tasmota/settings.h b/tasmota/settings.h index edd3de523..6ff0c4213 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -515,9 +515,7 @@ struct { uint8_t ot_hot_water_setpoint; // E8C uint8_t ot_boiler_setpoint; // E8D uint8_t ot_flags; // E8E - - uint8_t free_e8f[1]; // E8F - + uint8_t ledpwm_mask; // F8F uint16_t dimmer_hw_min; // E90 uint16_t dimmer_hw_max; // E92 uint32_t deepsleep; // E94 @@ -569,8 +567,10 @@ struct { uint16_t windmeter_pulse_debounce; // F3A int16_t windmeter_speed_factor; // F3C uint8_t windmeter_tele_pchange; // F3E + uint8_t ledpwm_on; // F3F + uint8_t ledpwm_off; // F40 - uint8_t free_f3f[121]; // F3F - Decrement if adding new Setting variables just above and below + uint8_t free_f42[119]; // F41 - Decrement if adding new Setting variables just above and below // Only 32 bit boundary variables below uint16_t pulse_counter_debounce_low; // FB8 diff --git a/tasmota/settings.ino b/tasmota/settings.ino index 5214add7a..549799447 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -765,6 +765,9 @@ void SettingsDefaultSet2(void) Settings.blinkcount = APP_BLINKCOUNT; Settings.ledstate = APP_LEDSTATE; Settings.ledmask = APP_LEDMASK; +// Settings.ledpwm_off = 0; + Settings.ledpwm_on = 255; +// Settings.ledpwm_mask = 0; Settings.pulse_timer[0] = APP_PULSETIME; // for (uint32_t i = 1; i < MAX_PULSETIMERS; i++) { Settings.pulse_timer[i] = 0; } @@ -1400,7 +1403,6 @@ void SettingsDelta(void) Settings.config_version = 1; // ESP32 #endif // ESP32 } - if (Settings.version < 0x08020006) { #ifdef ESP32 Settings.module = WEMOS; @@ -1411,12 +1413,15 @@ void SettingsDelta(void) if (Settings.rules[1][0] == 0) { Settings.rules[1][1] = 0; } if (Settings.rules[2][0] == 0) { Settings.rules[2][1] = 0; } } - if (Settings.version < 0x08030002) { SettingsUpdateText(SET_DEVICENAME, SettingsText(SET_FRIENDLYNAME1)); + Settings.ledpwm_off = 0; + Settings.ledpwm_on = 255; + Settings.ledpwm_mask = 0; } Settings.version = VERSION; SettingsSave(1); } + } diff --git a/tasmota/support.ino b/tasmota/support.ino index 271ad81fe..cecb5ffb2 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -1931,4 +1931,36 @@ String escapeJSONString(const char *str) { } return r; -} \ No newline at end of file +} + +/*********************************************************************************************\ + * Uncompress static PROGMEM strings +\*********************************************************************************************/ + +#if defined(USE_RULES_COMPRESSION) || defined(USE_SCRIPT_COMPRESSION) + +#include + +Unishox compressor; + +String Decompress(const char * compressed, size_t uncompressed_size) { + String content(""); + + uncompressed_size += 2; // take a security margin + + // We use a nasty trick here. To avoid allocating twice the buffer, + // we first extend the buffer of the String object to the target size (maybe overshooting by 7 bytes) + // then we decompress in this buffer, + // and finally assign the raw string to the String, which happens to work: String uses memmove(), so overlapping works + content.reserve(uncompressed_size); + char * buffer = content.begin(); + + int32_t len = compressor.unishox_decompress(compressed, strlen_P(compressed), buffer, uncompressed_size); + if (len > 0) { + buffer[len] = 0; // terminate string with NULL + content = buffer; // copy in place + } + return content; +} + +#endif // defined(USE_RULES_COMPRESSION) || defined(USE_SCRIPT_COMPRESSION) \ No newline at end of file diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index f262b5fcb..2ee5c17c4 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -27,7 +27,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix D_CMND_SERIALDELIMITER "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" D_CMND_WIFICONFIG "|" D_CMND_DEVICENAME "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_INTERLOCK "|" D_CMND_TELEPERIOD "|" D_CMND_RESET "|" D_CMND_TIME "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|" D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" D_CMND_LEDMASK "|" D_CMND_WIFIPOWER "|" D_CMND_TEMPOFFSET "|" D_CMND_HUMOFFSET "|" - D_CMND_SPEEDUNIT "|" D_CMND_GLOBAL_TEMP "|" D_CMND_GLOBAL_HUM "|" + D_CMND_SPEEDUNIT "|" D_CMND_GLOBAL_TEMP "|" D_CMND_GLOBAL_HUM "|" D_CMND_LEDPWMON "|" D_CMND_LEDPWMOFF "|" D_CMND_LEDPWMMODE "|" #ifdef USE_I2C D_CMND_I2CSCAN "|" D_CMND_I2CDRIVER "|" #endif @@ -50,7 +50,7 @@ void (* const TasmotaCommand[])(void) PROGMEM = { &CmndSerialDelimiter, &CmndIpAddress, &CmndNtpServer, &CmndAp, &CmndSsid, &CmndPassword, &CmndHostname, &CmndWifiConfig, &CmndDevicename, &CmndFriendlyname, &CmndSwitchMode, &CmndInterlock, &CmndTeleperiod, &CmndReset, &CmndTime, &CmndTimezone, &CmndTimeStd, &CmndTimeDst, &CmndAltitude, &CmndLedPower, &CmndLedState, &CmndLedMask, &CmndWifiPower, &CmndTempOffset, &CmndHumOffset, - &CmndSpeedUnit, &CmndGlobalTemp, &CmndGlobalHum, + &CmndSpeedUnit, &CmndGlobalTemp, &CmndGlobalHum, &CmndLedPwmOn, &CmndLedPwmOff, &CmndLedPwmMode, #ifdef USE_I2C &CmndI2cScan, CmndI2cDriver, #endif @@ -1890,3 +1890,59 @@ void CmndDriver(void) { XdrvCall(FUNC_COMMAND_DRIVER); } + +void CmndLedPwmOff(void) +{ + if (XdrvMailbox.data_len > 0) { + if (XdrvMailbox.payload < 0) { + Settings.ledpwm_off = 0; + } + else if (XdrvMailbox.payload > 255) { + Settings.ledpwm_off = 255; + } else { + Settings.ledpwm_off = XdrvMailbox.payload; + } + UpdateLedPowerAll(); + } + ResponseCmndNumber(Settings.ledpwm_off); +} + +void CmndLedPwmOn(void) +{ + if (XdrvMailbox.data_len > 0) { + if (XdrvMailbox.payload < 0) { + Settings.ledpwm_on = 0; + } + else if (XdrvMailbox.payload > 255) { + Settings.ledpwm_on = 255; + } else { + Settings.ledpwm_on = XdrvMailbox.payload; + } + UpdateLedPowerAll(); + } + ResponseCmndNumber(Settings.ledpwm_on); +} + +void CmndLedPwmMode(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_LEDS)) { + if (!PinUsed(GPIO_LEDLNK)) { XdrvMailbox.index = 1; } + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) { + uint32_t mask = 1 << (XdrvMailbox.index -1); // Led to configure + switch (XdrvMailbox.payload) { + case 0: // digital + Settings.ledpwm_mask &= (0xFF ^ mask); + break; + case 1: // pwm + Settings.ledpwm_mask |= mask; + break; + case 2: // toggle + Settings.ledpwm_mask ^= mask; + break; + } + UpdateLedPowerAll(); + } + bool state = bitRead(Settings.ledpwm_mask, XdrvMailbox.index -1); + ResponseCmndIdxChar(GetStateText(state)); + } +} diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 90df92a37..08a2ac6ca 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -336,6 +336,13 @@ void SetPowerOnState(void) blink_powersave = power; } +void UpdateLedPowerAll() +{ + for (uint32_t i = 0; i < leds_present; i++) { + SetLedPowerIdx(i, bitRead(led_power, i)); + } +} + void SetLedPowerIdx(uint32_t led, uint32_t state) { if (!PinUsed(GPIO_LEDLNK) && (0 == led)) { // Legacy - LED1 is link led only if LED2 is present @@ -351,7 +358,17 @@ void SetLedPowerIdx(uint32_t led, uint32_t state) } else { led_power &= (0xFF ^ mask); } - DigitalWrite(GPIO_LED1, led, bitRead(led_inverted, led) ? !state : state); + uint16_t pwm = 0; + if (bitRead(Settings.ledpwm_mask, led)) { +#ifdef USE_LIGHT + pwm = changeUIntScale(ledGamma10(state ? Settings.ledpwm_on : Settings.ledpwm_off), 0, 1023, 0, Settings.pwm_range); // gamma corrected +#else //USE_LIGHT + pwm = changeUIntScale((uint16_t)(state ? Settings.ledpwm_on : Settings.ledpwm_off), 0, 255, 0, Settings.pwm_range); // linear +#endif //USE_LIGHT + analogWrite(Pin(GPIO_LED1, led), bitRead(led_inverted, led) ? Settings.pwm_range - pwm : pwm); + } else { + DigitalWrite(GPIO_LED1, led, bitRead(led_inverted, led) ? !state : state); + } } #ifdef USE_BUZZER if (led == 0) { @@ -386,10 +403,9 @@ void SetLedLink(uint32_t state) uint32_t led_pin = Pin(GPIO_LEDLNK); uint32_t led_inv = ledlnk_inverted; if (99 == led_pin) { // Legacy - LED1 is status - led_pin = Pin(GPIO_LED1); - led_inv = bitRead(led_inverted, 0); + SetLedPowerIdx(0, state); } - if (led_pin < 99) { + else if (led_pin < 99) { if (state) { state = 1; } digitalWrite(led_pin, (led_inv) ? !state : state); } diff --git a/tasmota/tasmota_version.h b/tasmota/tasmota_version.h index af18e431f..1b21293b2 100644 --- a/tasmota/tasmota_version.h +++ b/tasmota/tasmota_version.h @@ -20,7 +20,7 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x08030101; +const uint32_t VERSION = 0x08030102; // Lowest compatible version const uint32_t VERSION_COMPATIBLE = 0x07010006; diff --git a/tasmota/xdrv_03_energy.ino b/tasmota/xdrv_03_energy.ino index 4210cea1c..f5e4a729d 100644 --- a/tasmota/xdrv_03_energy.ino +++ b/tasmota/xdrv_03_energy.ino @@ -80,10 +80,12 @@ struct ENERGY { float power_factor[3] = { NAN, NAN, NAN }; // 0.12 float frequency[3] = { NAN, NAN, NAN }; // 123.1 Hz +// float import_active[3] = { NAN, NAN, NAN }; // 123.123 kWh + float export_active[3] = { NAN, NAN, NAN }; // 123.123 kWh + float start_energy = 0; // 12345.12345 kWh total previous float daily = 0; // 123.123 kWh float total = 0; // 12345.12345 kWh total energy - float export_active = NAN; // 123.123 KWh unsigned long kWhtoday_delta = 0; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to Energy.kWhtoday (HLW and CSE only) unsigned long kWhtoday_offset = 0; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily @@ -95,7 +97,8 @@ struct ENERGY { uint8_t data_valid[3] = { 0, 0, 0 }; uint8_t phase_count = 1; // Number of phases active - bool voltage_common = false; // Use single voltage and frequency + bool voltage_common = false; // Use single voltage + bool frequency_common = false; // Use single frequency bool kWhtoday_offset_init = false; bool voltage_available = true; // Enable if voltage is measured @@ -170,9 +173,18 @@ void EnergyUpdateToday(void) RtcSettings.energy_usage.last_usage_kWhtotal = (uint32_t)(Energy.total * 100000); uint32_t return_diff = 0; - if (!isnan(Energy.export_active)) { - return_diff = (uint32_t)(Energy.export_active * 100000) - RtcSettings.energy_usage.last_return_kWhtotal; - RtcSettings.energy_usage.last_return_kWhtotal = (uint32_t)(Energy.export_active * 100000); + if (!isnan(Energy.export_active[0])) { +// return_diff = (uint32_t)(Energy.export_active * 100000) - RtcSettings.energy_usage.last_return_kWhtotal; +// RtcSettings.energy_usage.last_return_kWhtotal = (uint32_t)(Energy.export_active * 100000); + + float export_active = 0.0; + for (uint32_t i = 0; i < Energy.phase_count; i++) { + if (!isnan(Energy.export_active[i])) { + export_active += Energy.export_active[i]; + } + } + return_diff = (uint32_t)(export_active * 100000) - RtcSettings.energy_usage.last_return_kWhtotal; + RtcSettings.energy_usage.last_return_kWhtotal = (uint32_t)(export_active * 100000); } if (EnergyTariff1Active()) { // Tarrif1 = Off-Peak @@ -466,13 +478,13 @@ void EnergyEverySecond(void) if (!isnan(Energy.reactive_power[i])) { Energy.reactive_power[i] = 0; } if (!isnan(Energy.frequency[i])) { Energy.frequency[i] = 0; } if (!isnan(Energy.power_factor[i])) { Energy.power_factor[i] = 0; } + if (!isnan(Energy.export_active[i])) { Energy.export_active[i] = 0; } data_valid--; } } } if (!data_valid) { - if (!isnan(Energy.export_active)) { Energy.export_active = 0; } Energy.start_energy = 0; XnrgCall(FUNC_ENERGY_RESET); @@ -948,29 +960,31 @@ void EnergyShow(bool json) char voltage_chr[Energy.phase_count][FLOATSZ]; char current_chr[Energy.phase_count][FLOATSZ]; char active_power_chr[Energy.phase_count][FLOATSZ]; + char export_active_chr[Energy.phase_count][FLOATSZ]; for (uint32_t i = 0; i < Energy.phase_count; i++) { dtostrfd(Energy.voltage[i], Settings.flag2.voltage_resolution, voltage_chr[i]); dtostrfd(Energy.current[i], Settings.flag2.current_resolution, current_chr[i]); dtostrfd(Energy.active_power[i], Settings.flag2.wattage_resolution, active_power_chr[i]); + dtostrfd(Energy.export_active[i], Settings.flag2.energy_resolution, export_active_chr[i]); } + char energy_total_chr[FLOATSZ]; + dtostrfd(Energy.total, Settings.flag2.energy_resolution, energy_total_chr); char energy_daily_chr[FLOATSZ]; dtostrfd(Energy.daily, Settings.flag2.energy_resolution, energy_daily_chr); char energy_yesterday_chr[FLOATSZ]; dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr); - char energy_total_chr[3][FLOATSZ]; - dtostrfd(Energy.total, Settings.flag2.energy_resolution, energy_total_chr[0]); - char export_active_chr[3][FLOATSZ]; - dtostrfd(Energy.export_active, Settings.flag2.energy_resolution, export_active_chr[0]); - uint8_t energy_total_fields = 1; + bool energy_tariff = false; + char energy_usage_chr[2][FLOATSZ]; + char energy_return_chr[2][FLOATSZ]; if (Settings.tariff[0][0] != Settings.tariff[1][0]) { - dtostrfd((float)RtcSettings.energy_usage.usage1_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_total_chr[1]); // Tariff1 - dtostrfd((float)RtcSettings.energy_usage.usage2_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_total_chr[2]); // Tariff2 - dtostrfd((float)RtcSettings.energy_usage.return1_kWhtotal / 100000, Settings.flag2.energy_resolution, export_active_chr[1]); // Tariff1 - dtostrfd((float)RtcSettings.energy_usage.return2_kWhtotal / 100000, Settings.flag2.energy_resolution, export_active_chr[2]); // Tariff2 - energy_total_fields = 3; + dtostrfd((float)RtcSettings.energy_usage.usage1_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_usage_chr[0]); // Tariff1 + dtostrfd((float)RtcSettings.energy_usage.usage2_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_usage_chr[1]); // Tariff2 + dtostrfd((float)RtcSettings.energy_usage.return1_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_return_chr[0]); // Tariff1 + dtostrfd((float)RtcSettings.energy_usage.return2_kWhtotal / 100000, Settings.flag2.energy_resolution, energy_return_chr[1]); // Tariff2 + energy_tariff = true; } char value_chr[FLOATSZ *3]; // Used by EnergyFormatIndex @@ -980,15 +994,26 @@ void EnergyShow(bool json) if (json) { bool show_energy_period = (0 == tele_period); - ResponseAppend_P(PSTR(",\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL_START_TIME "\":\"%s\",\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), + ResponseAppend_P(PSTR(",\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL_START_TIME "\":\"%s\",\"" D_JSON_TOTAL "\":%s"), GetDateAndTime(DT_ENERGY).c_str(), - EnergyFormatIndex(value_chr, energy_total_chr[0], json, energy_total_fields), + energy_total_chr); + + if (energy_tariff) { + ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL D_CMND_TARIFF "\":%s"), + EnergyFormatIndex(value_chr, energy_usage_chr[0], json, 2)); + } + + ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), energy_yesterday_chr, energy_daily_chr); - if (!isnan(Energy.export_active)) { + if (!isnan(Energy.export_active[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"), - EnergyFormatIndex(value_chr, export_active_chr[0], json, energy_total_fields)); + EnergyFormat(value_chr, export_active_chr[0], json)); + if (energy_tariff) { + ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT D_CMND_TARIFF "\":%s"), + EnergyFormatIndex(value_chr, energy_return_chr[0], json, 2)); + } } if (show_energy_period) { @@ -1012,7 +1037,7 @@ void EnergyShow(bool json) } if (!isnan(Energy.frequency[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_FREQUENCY "\":%s"), - EnergyFormat(value_chr, frequency_chr[0], json, Energy.voltage_common)); + EnergyFormat(value_chr, frequency_chr[0], json, Energy.frequency_common)); } } if (Energy.voltage_available) { @@ -1028,14 +1053,14 @@ void EnergyShow(bool json) #ifdef USE_DOMOTICZ if (show_energy_period) { // Only send if telemetry - dtostrfd(Energy.total * 1000, 1, energy_total_chr[0]); - DomoticzSensorPowerEnergy((int)Energy.active_power[0], energy_total_chr[0]); // PowerUsage, EnergyToday + dtostrfd(Energy.total * 1000, 1, energy_total_chr); + DomoticzSensorPowerEnergy((int)Energy.active_power[0], energy_total_chr); // PowerUsage, EnergyToday - dtostrfd((float)RtcSettings.energy_usage.usage1_kWhtotal / 100, 1, energy_total_chr[1]); // Tariff1 - dtostrfd((float)RtcSettings.energy_usage.usage2_kWhtotal / 100, 1, energy_total_chr[2]); // Tariff2 - dtostrfd((float)RtcSettings.energy_usage.return1_kWhtotal / 100, 1, export_active_chr[1]); - dtostrfd((float)RtcSettings.energy_usage.return2_kWhtotal / 100, 1, export_active_chr[2]); - DomoticzSensorP1SmartMeter(energy_total_chr[1], energy_total_chr[2], export_active_chr[1], export_active_chr[2], (int)Energy.active_power[0]); + dtostrfd((float)RtcSettings.energy_usage.usage1_kWhtotal / 100, 1, energy_usage_chr[0]); // Tariff1 + dtostrfd((float)RtcSettings.energy_usage.usage2_kWhtotal / 100, 1, energy_usage_chr[1]); // Tariff2 + dtostrfd((float)RtcSettings.energy_usage.return1_kWhtotal / 100, 1, energy_return_chr[0]); + dtostrfd((float)RtcSettings.energy_usage.return2_kWhtotal / 100, 1, energy_return_chr[1]); + DomoticzSensorP1SmartMeter(energy_usage_chr[0], energy_usage_chr[1], energy_return_chr[0], energy_return_chr[1], (int)Energy.active_power[0]); if (Energy.voltage_available) { DomoticzSensor(DZ_VOLTAGE, voltage_chr[0]); // Voltage @@ -1079,12 +1104,12 @@ void EnergyShow(bool json) } if (!isnan(Energy.frequency[0])) { WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), - EnergyFormat(value_chr, frequency_chr[0], json, Energy.voltage_common)); + EnergyFormat(value_chr, frequency_chr[0], json, Energy.frequency_common)); } } - WSContentSend_PD(HTTP_ENERGY_SNS2, energy_daily_chr, energy_yesterday_chr, energy_total_chr[0]); - if (!isnan(Energy.export_active)) { - WSContentSend_PD(HTTP_ENERGY_SNS3, export_active_chr[0]); + WSContentSend_PD(HTTP_ENERGY_SNS2, energy_daily_chr, energy_yesterday_chr, energy_total_chr); + if (!isnan(Energy.export_active[0])) { + WSContentSend_PD(HTTP_ENERGY_SNS3, EnergyFormat(value_chr, export_active_chr[0], json)); } XnrgCall(FUNC_WEB_SENSOR); diff --git a/tasmota/xdrv_10_rules.ino b/tasmota/xdrv_10_rules.ino index 25a62d288..912a32ae5 100644 --- a/tasmota/xdrv_10_rules.ino +++ b/tasmota/xdrv_10_rules.ino @@ -213,7 +213,7 @@ char rules_vars[MAX_RULE_VARS][33] = {{ 0 }}; #ifdef USE_RULES_COMPRESSION // Statically allocate one String per rule String k_rules[MAX_RULE_SETS] = { String(), String(), String() }; // Strings are created empty -Unishox compressor; // singleton +// Unishox compressor; // singleton #endif // USE_RULES_COMPRESSION // Returns whether the rule is uncompressed, which means the first byte is not NULL @@ -263,18 +263,7 @@ void GetRule_decompress(String &rule, const char *rule_head) { size_t buf_len = 1 + *rule_head * 8; // the first byte contains size of buffer for uncompressed rule / 8, buf_len may overshoot by 7 rule_head++; // advance to the actual compressed buffer - // We use a nasty trick here. To avoid allocating twice the buffer, - // we first extend the buffer of the String object to the target size (maybe overshooting by 7 bytes) - // then we decompress in this buffer, - // and finally assign the raw string to the String, which happens to work: String uses memmove(), so overlapping works - rule.reserve(buf_len); - char* buf = rule.begin(); - - int32_t len_decompressed = compressor.unishox_decompress(rule_head, strlen(rule_head), buf, buf_len); - buf[len_decompressed] = 0; // add NULL terminator - - // AddLog_P2(LOG_LEVEL_INFO, PSTR("RUL: Rawdecompressed: %d"), len_decompressed); - rule = buf; // assign the raw string to the String object (in reality re-writing the same data in the same place) + rule = Decompress(rule_head, buf_len); } #endif // USE_RULES_COMPRESSION diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index eb0d00f29..cf148c97b 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -71,7 +71,7 @@ uint32_t DecodeLightId(uint32_t hue_id); #ifdef USE_SCRIPT_COMPRESSION #include -Unishox compressor; // singleton +//Unishox compressor; // singleton #define SCRIPT_COMPRESS compressor.unishox_compress #define SCRIPT_DECOMPRESS compressor.unishox_decompress #ifndef UNISHOXRSIZE @@ -1228,6 +1228,52 @@ chknext: fvar=UtcTime()-(uint32_t)EPOCH_OFFSET; goto exit; } +#ifdef USE_ENERGY_SENSOR + if (!strncmp(vname,"enrg[",5)) { + lp+=5; + lp=GetNumericResult(lp,OPER_EQU,&fvar,0); + while (*lp==' ') lp++; + switch ((uint32_t)fvar) { + case 0: + fvar=Energy.total; + break; + case 1: + fvar=Energy.voltage[0]; + break; + case 2: + fvar=Energy.voltage[1]; + break; + case 3: + fvar=Energy.voltage[2]; + break; + case 4: + fvar=Energy.current[0]; + break; + case 5: + fvar=Energy.current[1]; + break; + case 6: + fvar=Energy.current[2]; + break; + case 7: + fvar=Energy.active_power[0]; + break; + case 8: + fvar=Energy.active_power[1]; + break; + case 9: + fvar=Energy.active_power[2]; + break; + + default: + fvar=99999; + break; + } + len=0; + lp++; + goto exit; + } +#endif //USE_ENERGY_SENSOR break; case 'f': #ifdef USE_SCRIPT_FATFS @@ -1948,6 +1994,15 @@ chknext: } #endif #if defined(USE_SML_M) && defined (USE_SML_SCRIPT_CMD) + if (!strncmp(vname,"sml[",4)) { + lp+=4; + lp=GetNumericResult(lp,OPER_EQU,&fvar,0); + SCRIPT_SKIP_SPACES + fvar=SML_GetVal[fvar]; + lp++; + len=0; + goto exit; + } if (!strncmp(vname,"sml(",4)) { lp+=4; float fvar1; @@ -3948,6 +4003,12 @@ void ScriptSaveSettings(void) { strlcpy(glob_script_mem.script_ram,str.c_str(), glob_script_mem.script_size); + if (glob_script_mem.script_ram[0]!='>' && glob_script_mem.script_ram[1]!='D') { + AddLog_P2(LOG_LEVEL_INFO, PSTR("script error: must start with >D")); + bitWrite(Settings.rule_enabled, 0, 0); + } + + #if defined(USE_24C256) && !defined(USE_SCRIPT_FATFS) if (glob_script_mem.flags&1) { EEP_WRITE(0,EEP_SCRIPT_SIZE,glob_script_mem.script_ram); @@ -3983,9 +4044,9 @@ void ScriptSaveSettings(void) { #ifndef ESP32_SCRIPT_SIZE //AddLog_P2(LOG_LEVEL_INFO,PSTR("in string: %s len = %d"),glob_script_mem.script_ram,strlen(glob_script_mem.script_ram)); - uint32_t len_compressed = SCRIPT_COMPRESS(glob_script_mem.script_ram, strlen(glob_script_mem.script_ram)+1, Settings.rules[0], MAX_SCRIPT_SIZE-1); - Settings.rules[0][len_compressed] = 0; + uint32_t len_compressed = SCRIPT_COMPRESS(glob_script_mem.script_ram, strlen(glob_script_mem.script_ram), Settings.rules[0], MAX_SCRIPT_SIZE-1); if (len_compressed > 0) { + Settings.rules[0][len_compressed] = 0; AddLog_P2(LOG_LEVEL_INFO,PSTR("script compressed to %d %%"),len_compressed * 100 / strlen(glob_script_mem.script_ram)); } else { AddLog_P2(LOG_LEVEL_INFO, PSTR("script compress error: %d"), len_compressed); @@ -4899,12 +4960,20 @@ const char SCRIPT_MSG_TEXTINP[] PROGMEM = const char SCRIPT_MSG_NUMINP[] PROGMEM = "
"; + +#ifdef USE_GOOGLE_CHARTS const char SCRIPT_MSG_GTABLE[] PROGMEM = "" "" - "" - "" - ""; + "" + ""; + +const char SCRIPT_MSG_TABLE[] PROGMEM = + ""; +const char SCRIPT_MSG_GAUGE[] PROGMEM = + ""; +const char SCRIPT_MSG_TIMELINE[] PROGMEM = + ""; const char SCRIPT_MSG_GTABLEa[] PROGMEM = @@ -4913,9 +4982,15 @@ const char SCRIPT_MSG_GTABLEa[] PROGMEM = "var data=google.visualization.arrayToDataTable(["; +const char SCRIPT_MSG_GTABLEd[] PROGMEM = +"['Timeline','start','end'],"; + +//#define CHART_EXTRA_OPTIONS ",width:'640px',height:'480px'" +#define CHART_EXTRA_OPTIONS + const char SCRIPT_MSG_GTABLEb[] PROGMEM = "]);" - "var options={%s};" + "var options={%s" CHART_EXTRA_OPTIONS "};" "var chart=new google.visualization.%s(document.getElementById('chart%1d'));" "chart.draw(data,options);}" "google.charts.setOnLoadCallback(drawChart);"; @@ -4923,15 +4998,83 @@ const char SCRIPT_MSG_GTABLEb[] PROGMEM = const char SCRIPT_MSG_GOPT1[] PROGMEM = "title:'%s',isStacked:false"; -const char SCRIPT_MSG_GOPT3[] PROGMEM = -"title:'%s',vAxes:{0:{maxValue:%d},1:{maxValue:%d}},series:{0:{targetAxisIndex:0},1:{targetAxisIndex:1}}"; - - const char SCRIPT_MSG_GOPT2[] PROGMEM = "showRowNumber:true,sort:'disable',allowHtml:true,width:'100%%',height:'100%%',cssClassNames:cssc"; +const char SCRIPT_MSG_GOPT3[] PROGMEM = +"title:'%s',isStacked:false,vAxes:{0:{maxValue:%d},1:{maxValue:%d}},series:{0:{targetAxisIndex:0},1:{targetAxisIndex:1}}%s"; + +const char SCRIPT_MSG_GOPT4[] PROGMEM = +//"hAxis:{minValue:new Date(0,1,1,0,0),maxValue:new Date(0,1,2,0,0),format:'HH:mm'}"; +"hAxis:{minValue:new Date(0,1,1,0,0),maxValue:new Date(0,1,2,0,0),format:'HH:mm'},theme: 'maximized'"; + +const char SCRIPT_MSG_GOPT5[] PROGMEM = +"new Date(0,1,1,%d,%d)"; + const char SCRIPT_MSG_GTE1[] PROGMEM = "'%s'"; +#define GLIBS_MAIN 1<<0 +#define GLIBS_TABLE 1<<1 +#define GLIBS_GAUGE 1<<2 +#define GLIBS_TIMELINE 1<<3 + +#define MAX_GARRAY 4 + +char *gc_get_arrays(char *lp, float **arrays, uint8_t *ranum, uint8_t *rentries) { +struct T_INDEX ind; +uint8_t vtype; +uint8 entries=0; + + uint8_t anum=0; + while (anum> 2 %d\n",(uint32_t)*fa); + if (fa && len>=entries) { + if (!entries) {entries = len;} + // add array to list + arrays[anum]=fa; + anum++; + } + } + } else { + lp=lp1; + break; + } + } + } + *ranum=anum; + *rentries=entries; + return lp; +} + +char *gc_send_labels(char *lp,uint32_t anum) { + WSContentSend_PD("["); + for (uint32_t cnt=0; cnt> 2 %d\n",(uint32_t)*fa); - if (fa && len>=entries) { - if (!entries) {entries = len;} - // add array to list - arrays[anum]=fa; - anum++; - } - } - } else { - lp=lp1; - break; - } - } - } - //Serial.printf("arrays %d\n",anum); - //Serial.printf("entries %d\n",entries); - - if (!google_libs) { - WSContentSend_PD(SCRIPT_MSG_GTABLE); - google_libs=1; - } - - WSContentSend_PD(SCRIPT_MSG_GTABLEa); - - // we know how many arrays and the number of entries - // we need to fetch the labels now - WSContentSend_PD("["); - for (uint32_t cnt=0; cntnanum) { + goto nextwebline; + } + // we know how many arrays and the number of entries + //Serial.printf("arrays %d\n",anum); + //Serial.printf("entries %d\n",entries); + if (ctype=='T') { + if (anum && !(entries&1)) { + WSContentSend_PD(SCRIPT_MSG_GTABLEa); + WSContentSend_PD(SCRIPT_MSG_GTABLEd); + char label[SCRIPT_MAXSSIZE]; + lp=GetStringResult(lp,OPER_EQU,label,0); + SCRIPT_SKIP_SPACES + char *lblp=label; + for (uint32_t ind=0; ind0) glob_script_mem.script_ram[len_decompressed]=0; //AddLog_P2(LOG_LEVEL_INFO, PSTR("decompressed script len %d"),len_decompressed); #endif #endif @@ -5568,6 +5756,14 @@ bool Xdrv10(uint8_t function) glob_script_mem.flags=1; #endif + // a valid script MUST start with >D + if (glob_script_mem.script_ram[0]!='>' && glob_script_mem.script_ram[1]!='D') { + // clr all + memset(glob_script_mem.script_ram,0,glob_script_mem.script_size); + strcpy_P(glob_script_mem.script_ram, PSTR(">D\nscript error must start with >D")); + bitWrite(Settings.rule_enabled, 0, 0); + } + // assure permanent memory is 4 byte aligned { uint32_t ptr=(uint32_t)glob_script_mem.script_pram; ptr&=0xfffffffc; diff --git a/tasmota/xdrv_20_hue.ino b/tasmota/xdrv_20_hue.ino index 122166010..639f198bb 100644 --- a/tasmota/xdrv_20_hue.ino +++ b/tasmota/xdrv_20_hue.ino @@ -114,6 +114,29 @@ void HueRespondToMSearch(void) * Hue web server additions \*********************************************************************************************/ +//10http://{x1:80/urn:schemas-upnp-org:device:Basic:1Amazon-Echo-HA-Bridge ({x1)Royal Philips Electronicshttp://www.philips.comPhilips hue Personal Wireless LightingPhilips hue bridge 2012929000226503{x3uuid:{x2\r\n\r\n +//Successfully compressed from 625 to 391 bytes (-37.4%) +// const size_t HUE_DESCRIPTION_XML_size = 625; +// const char HUE_DESCRIPTION_XML[] PROGMEM = "\x3D\x0E\xD1\xB0\x68\x48\xCD\xFF\xDB\x9C\x7C\x3D\x87\x21\xD1\x9E\xC3\xB4\x7E\x1E" +// "\x85\xFC\xCA\x46\xC1\xA1\x77\x8F\x87\xB0\x5F\xF8\xF3\xF0\x62\x98\xDB\xF1\xD6\x2C" +// "\x67\x0C\x3A\xF3\xE3\xC7\x98\x8C\xCF\x43\x67\x59\xC8\x75\xB3\xD8\x7E\x1E\x85\xE1" +// "\x8C\x32\x33\x04\x1C\x78\xFC\x3D\x06\xD9\xAF\x3E\x7E\x1C\x87\xA1\xD8\x40\x83\x14" +// "\xF4\x1B\xBD\x9F\x3F\x0E\x33\xD0\xEC\x20\x41\x8A\x7A\x1D\x80\x91\x85\x10\xB2\xF9" +// "\x04\x43\xAF\xCC\xFC\x15\x54\x30\xF3\x3B\x0E\xC3\xDA\x6C\x39\x0F\x3F\xB3\xB0\xF4" +// "\x3B\x08\x10\xEA\x1E\x80\x83\xA2\x82\x1C\x42\xA3\x21\x8C\xFC\x05\x6D\xB4\xF3\x21" +// "\xD7\xED\x0C\xF3\x39\x0F\x43\xB0\x81\x1B\x0C\x3D\x0C\x7F\x5F\x08\x11\x91\x75\x8D" +// "\x67\xE1\x58\xDB\x36\xE7\x1D\x64\xC3\x15\x87\x59\x0A\x2B\x3A\xC8\x77\xF4\x41\xE6" +// "\x8E\xE9\xED\x36\x1C\x87\x78\xF4\x3B\x08\x12\x30\x63\xD0\x6D\xF0\xB3\x16\x1D\x0B" +// "\xFB\xF9\xF8\x5F\xC3\x2B\x09\x10\xC1\x5A\x16\x8C\xF2\x26\x13\x0E\xBF\x9D\xA1\xF8" +// "\xF4\x3B\x01\x23\x04\x04\x8C\x48\x85\x97\xC8\x20\x43\xE0\xDC\x7C\x7C\x7C\xE8\x30" +// "\x10\x71\xA3\xA0\x78\x34\x12\x71\x22\x16\x5F\x20\x8F\xC3\xD0\x6E\x08\xC2\x21\x1F" +// "\x83\xFE\x8C\xAD\xCE\x3F\x01\x0F\x49\x14\x2D\xA2\x18\xFF\xEC\xEB\x09\x10\xFE\xFD" +// "\x84\xFD\xE4\x41\x68\xF0\xAA\xDE\x1E\x3D\x0E\xC0\x4C\xC5\x41\x07\x27\x2E\xB1\xAC" +// "\x12\x32\x01\xC0\x83\xC2\x41\xCA\x72\x88\x10\xB1\x10\x42\xE1\x13\x04\x61\x17\x0B" +// "\x1A\x39\xFC\xFC\x38\xA9\x36\xEA\xBB\x5D\x90\x21\xE0\x20\x83\x58\xF4\xF3\xFE\xD8" +// "\x21\xCA\x3D\xA6\xC3\x96\x7A\x1D\x84\x09\x13\x8F\x42\x16\x42\x17\x1F\x82\xC5\xE8" +// "\x87\x99\xED\x36\x1C\xA3\xD0\xEC\x22\x16\x42\x17\x1F\x80\x87\xC7\x19\xF8\x7A\x1D" +// "\x9F\xCC\xA3\xF2\x70\xA4\x6E\x9C\x29\x1B\x8D"; const char HUE_DESCRIPTION_XML[] PROGMEM = "" "" @@ -137,22 +160,59 @@ const char HUE_DESCRIPTION_XML[] PROGMEM = "" "\r\n" "\r\n"; + +//%s"alert":"none","effect":"none","reachable":true} +//Successfully compressed from 50 to 34 bytes (-32%) +// const size_t HUE_LIGHTS_STATUS_JSON1_SUFFIX_size = 50; +// const char HUE_LIGHTS_STATUS_JSON1_SUFFIX[] PROGMEM = "\x3E\xBC\x7B\x2C\x27\xFA\x3D\x87\x99\xEC\xEC\xE6\x7B\x0E\xA3\xD8\xCC\x18\x61\x82" +// "\x34\xCF\xBB\x0C\x55\x8E\x09\x9E\xC3\xCE\xBE\x2D\x9E\xE3"; const char HUE_LIGHTS_STATUS_JSON1_SUFFIX[] PROGMEM = "%s\"alert\":\"none\"," "\"effect\":\"none\"," "\"reachable\":true}"; + +//,"type":"Extended color light","name":"%s","modelid":"%s","manufacturername":"%s","uniqueid":"%s"} +//Successfully compressed from 98 to 64 bytes (-34.7%) +// const size_t HUE_LIGHTS_STATUS_JSON2_size = 98; +// const char HUE_LIGHTS_STATUS_JSON2[] PROGMEM = "\x3A\x8F\x65\x19\x0C\x67\xB0\xF3\x3D\x84\xCD\x94\xF8\x46\x22\x0F\x02\xCF\xA0\xB4" +// "\x78\x55\x1E\xC3\xA8\xF6\x75\x8D\x67\xB0\xF3\x3D\x87\xD7\x8F\x61\xD4\x7B\x06\xE0" +// "\x8C\x2D\x10\x11\x25\xDF\x0B\x31\x61\xD0\xBF\xBF\x82\x3E\x06\x2F\xB4\xD4\x2D\x82" +// "\x1E\x08\x7B\x8D"; const char HUE_LIGHTS_STATUS_JSON2[] PROGMEM = ",\"type\":\"Extended color light\"," "\"name\":\"%s\"," "\"modelid\":\"%s\"," "\"manufacturername\":\"%s\"," "\"uniqueid\":\"%s\"}"; + +//{"name":"Group 0","lights":[{l1],"type":"LightGroup","action": +//Successfully compressed from 62 to 61 bytes (-1.6%) const char HUE_GROUP0_STATUS_JSON[] PROGMEM = "{\"name\":\"Group 0\"," "\"lights\":[{l1]," "\"type\":\"LightGroup\"," "\"action\":"; // "\"scene\":\"none\","; + +//{"name":"Philips hue","mac":"{ma","dhcp":true,"ipaddress":"{ip","netmask":"{ms","gateway":"{gw","proxyaddress":"none","proxyport":0,"bridgeid":"{br","UTC":"{dt","whitelist":{"{id":{"last use date":"{dt","create date":"{dt","name":"Remote"}},"swversion":"01041302","apiversion":"1.17.0","swupdate":{"updatestate":0,"url":"","text":"","notify": false},"linkbutton":false,"portalservices":false} +//Successfully compressed from 392 to 302 bytes (-23%) +// const size_t HueConfigResponse_JSON_size = 392; +// const char HueConfigResponse_JSON[] PROGMEM = "\x3D\xA7\xB3\xAC\x6B\x3D\x87\x99\xEC\x21\x82\xB4\x2D\x19\xE4\x28\x5B\x3D\x87\x51" +// "\xEC\x1B\x61\x9E\xC3\xCC\xF6\x1E\xD1\xB6\x7B\x0E\xA3\xD8\x20\xA0\xC6\x1E\xC3\xCE" +// "\xBE\x2D\x9D\x47\xB3\x46\x58\x82\x7D\xFB\xC7\xB0\xF3\x3D\x87\xB7\x46\x1E\xC3\xA8" +// "\xF6\x73\xA1\xB7\xE3\x43\xD8\x79\x9E\xC3\xDA\x37\xC7\xB0\xEA\x3D\x83\xD7\x4C\x7E" +// "\xCC\x8F\x61\xE6\x7B\x0F\x68\xF0\xF9\xEC\x3A\x8F\x60\xCF\xE1\xB0\xC8\x11\x71\x1E" +// "\xCE\x60\x87\x48\x66\x7E\x8F\x61\xE6\x71\x9D\x47\xB0\x87\x7F\x44\x1E\x7A\x21\xEC" +// "\x3C\xCF\x61\xED\x1D\xF3\xD8\x75\x1E\xC2\x16\x54\x41\x9E\xC3\xCC\xF6\x1E\xD1\x28" +// "\xF6\x1D\x47\xB0\x7C\x56\xD3\x0B\x7D\x47\xB0\xF3\x3D\xA7\xB0\xF6\xE8\x87\xB0\xF3" +// "\x3D\xA7\xB0\x2B\xF5\x21\x7E\x68\x4B\xA6\x08\x98\x30\x7F\x77\x40\x95\x40\x10\xB8" +// "\x3A\x2F\xB1\xB9\x4C\xF6\x1E\xE3\xDC\x75\x1E\xCF\x0F\x99\xBF\xFB\x73\x8F\x61\xE6" +// "\x7B\x0E\x38\xF2\x5B\xA3\xD8\x75\x1E\xC2\xB1\x9A\x08\xB5\x0E\x43\xA4\xF1\xD1\x9E" +// "\xC3\xA8\xF6\x17\x87\xC5\x8C\x04\x1C\xB0\xF6\x9E\xC0\x41\x8D\xEA\xBA\x67\xB0\xF3" +// "\x38\xCE\xA3\xD8\x42\xFE\x11\xEC\x3C\xCF\x61\xEC\x3A\x8F\x65\x33\x65\x02\x0C\x6E" +// "\xCA\xD3\x06\x47\xB0\xF3\x46\x2C\x2F\x33\xDC\x75\x1E\xC0\xB7\x8D\x07\x0B\xAA\xCE" +// "\x3D\x87\x99\x8B\x0B\xCC\xEA\x3D\x83\x33\xF5\x61\x79\xFC\xCF\x43\x7E\x04\x2A\x2B" +// "\x67\xB8"; const char HueConfigResponse_JSON[] PROGMEM = "{\"name\":\"Philips hue\"," "\"mac\":\"{ma\"," diff --git a/tasmota/xdrv_21_wemo.ino b/tasmota/xdrv_21_wemo.ino index fb123d4ab..86022b084 100644 --- a/tasmota/xdrv_21_wemo.ino +++ b/tasmota/xdrv_21_wemo.ino @@ -85,6 +85,79 @@ void WemoRespondToMSearch(int echo_type) * Wemo web server additions \*********************************************************************************************/ +#if defined(USE_RULES_COMPRESSION) || defined(USE_SCRIPT_COMPRESSION) + +//SetBinaryStateBinaryStateBinaryStateinGetBinaryStateBinaryStateBinaryStateoutBinaryStatebool0levelstring0\r\n\r\n +//Successfully compressed from 779 to 249 bytes (-68%) +const size_t WEMO_EVENTSERVICE_XML_SIZE = 779; +const char WEMO_EVENTSERVICE_XML[] PROGMEM = "\x3D\x3C\x18\xC1\x11\xB0\x68\x5D\xE3\xE1\xEC\x17\xFE\x3C\xC8\x73\x08\xD3\x78\xF3" + "\xF3\xF9\x9E\x86\xCE\xB3\x90\xEB\x67\xB0\xFC\x3D\x0A\xC3\xAD\xCE\x20\xB7\xD4\x08" + "\x72\x0F\xC3\xD3\xAC\x6B\x3F\x0B\xCE\x88\x76\xF5\xFC\xC8\xBD\x57\x4C\xF4\x3B\x3A" + "\xC6\xB3\xF0\xF4\xBF\x8F\x0B\x1A\xFA\x81\x0B\x0D\x04\x29\x47\xE1\xE9\xF7\x46\x76" + "\x11\xD8\x08\x58\xC0\x27\x62\xBF\x61\x5D\x31\x0B\xD5\x74\xC8\xCE\xFF\xB6\x38\x20" + "\x4A\xC1\x01\x42\xF1\xE8\x26\xFD\x82\x0E\xE7\xBC\x7A\x1D\x80\x8B\x28\xF4\x3B\x01" + "\x17\x59\x04\x48\xE0\x83\xB9\x1D\x80\x87\xC1\x20\x24\x70\x58\x43\xC0\xDA\xF8\x2C" + "\xC1\x74\x0C\x2F\x82\xD0\x42\x8A\x08\x34\x81\x0B\x92\x42\xF5\x5D\x32\xA0\x41\xCE" + "\x7C\x08\xFA\x42\xF3\xE1\x09\x99\xBE\xAF\x1F\x0F\x61\x93\xF1\xEC\x05\x5E\x0A\x44" + "\xBA\xB2\xA3\x21\x8C\xFC\x1D\x98\x11\xE8\x76\x02\x24\xB3\xD0\x46\x62\xC5\x85\x44" + "\x67\x61\x0B\x67\xE1\xC6\x7A\x1D\x84\x09\x13\x0F\x43\xB0\x12\x34\xC0\x60\x5A\xD8" + "\x4C\xCD\x84\x09\x9A\xAF\xAB\xFB\xC3\xC0\xC5\x75\x73\xB0\x13\xB8\x6A\x3B\x3C\x18" + "\xC1\x0F\xC9\xC2\x91\xBA\x70\xA4\x6E"; + +//10GetMetaInfoGetMetaInfoMetaInfoinMetaInfostring0\r\n\r\n +//Successfully compressed from 479 to 253 bytes (-47.2%) +const size_t WEMO_METASERVICE_XML_SIZE = 479; +const char WEMO_METASERVICE_XML[] PROGMEM = "\x3D\x3C\x18\xC1\x11\xB0\x68\x5D\xE3\xE1\xEC\x17\xFE\x3C\xC8\x73\x08\xD3\x78\xF3" + "\xF3\xF9\x9E\x86\xCE\xB3\x90\xEB\x67\xB0\xFC\x3D\x0B\xC3\x18\x64\x66\xFF\xED\xCE" + "\x3F\x0F\x41\xB6\x6B\xCF\x9F\x87\x21\xE8\x76\x10\x20\xC5\x3D\x06\xEF\x67\xCF\xC3" + "\x8C\xF4\x3B\x08\x10\x62\x9E\x87\x60\x24\x61\x56\x1D\x6E\x71\x05\xBE\xA0\x43\x90" + "\x7E\x1E\x9D\x63\x59\xF8\x43\xCE\x88\x6B\xAB\x2D\xE3\x18\x7A\x1D\x9D\x63\x59\xF8" + "\x7A\x5F\xC7\x85\x8D\x7D\x40\x83\x85\x7D\xD1\x9D\x84\x8E\xC0\x55\xC3\x3E\xC2\xBA" + "\x62\x17\xAA\xE9\x91\x9D\xFF\x6C\x70\x4C\xFC\x04\x5C\x04\x14\x2D\x9E\x82\x6F\xD8" + "\x20\xEC\x9B\xC7\xA1\xD8\x08\xB2\x8F\x43\xB0\x12\x75\xB3\xB0\x10\xF8\x0A\x04\x28" + "\xA0\x83\x48\x10\xB8\x74\x2F\x55\xD3\x2A\x2B\x04\x1C\xB7\xC0\x8F\x9E\x2F\x3E\x10" + "\x99\x9B\xEA\xF1\xF0\xF6\x19\x3F\x1E\xC0\x42\xE0\x68\x12\xF8\x17\x12\xEA\xCA\x8C" + "\x86\x33\xF3\xD5\xFD\xE1\xE3\xD0\xEC\x04\x49\xA7\xA0\x8C\xC5\x8B\x0A\x88\xCE\xC2" + "\x16\xCF\xC3\x8C\xF4\x3B\x08\x12\x26\x1E\x87\x60\x24\x69\x67\xE1\xE8\x76\x02\x76" + "\xDC\x76\x78\x31\x82\x1F\x93\x85\x23\x74\xE1\x48\xDC"; + +//%d\r\n +//Successfully compressed from 282 to 161 bytes (-42.9%) +const size_t WEMO_RESPONSE_STATE_SOAP_SIZE = 282; +const char WEMO_RESPONSE_STATE_SOAP[] PROGMEM = "\x3D\x3C\x79\x93\xE3\x36\x16\x0C\x68\xD8\x34\x2E\xF1\xE7\xE3\xE1\xEC\x15\x54\x30" + "\xF3\x3B\x0E\xCF\x06\x29\x8D\xBF\x1D\x0D\x83\x42\xF6\x58\xC3\xA6\x7C\x78\xEC\xF6" + "\x58\xC3\xB1\x82\x16\x1C\x76\x1E\xC5\xE3\xCD\xF0\x78\x26\xF0\xF1\x7A\x8C\x82\x60" + "\xBF\x8C\x02\x0E\x16\x76\x1E\xC3\xF0\xF4\xF1\xE6\x43\xB0\x43\x23\xF0\xF4\x16\x79" + "\x9F\x41\xBA\x21\xDB\xD7\xF3\x22\xF5\x5D\x32\xFB\xF0\xCC\xEF\x02\x1E\xDE\x2C\xF8" + "\x7B\x05\xFF\x8F\x32\x1C\xC2\x34\xDE\x3C\xFC\xFE\x67\xA1\xB3\xCC\x75\xFB\x43\x66" + "\x6F\xA8\xF3\x39\x0F\x61\xF8\x7A\x10\x23\x63\x67\xE1\xF4\x21\xE8\x76\x02\x3C\xC3" + "\xD0\xEC\x05\x4C\xFC\xFC\x3D\x0E\xC0\x43\xD8\xCE\xC0\x45\xE1\xA0\xFC\x9C\x29\x1B" + "\x8D"; + +//urn:Belkin:device:controllee:1{x1Belkin International Inc.Socket3.1415uuid:{x2{x30urn:Belkin:service:basicevent:1urn:Belkin:serviceId:basicevent1/upnp/control/basicevent1/upnp/event/basicevent1/eventservice.xmlurn:Belkin:service:metainfo:1urn:Belkin:serviceId:metainfo1/upnp/control/metainfo1/upnp/event/metainfo1/metainfoservice.xml\r\n +//Successfully compressed from 923 to 392 bytes (-57.5%) +const size_t WEMO_SETUP_XML_SIZE = 923; +const char WEMO_SETUP_XML[] PROGMEM = "\x3D\x0E\xD1\xB0\x68\x48\xCD\xFF\xDB\x9C\x7C\x3D\x87\x21\xD1\x9E\xC3\xB4\x7E\x1E" + "\x85\xFC\xCA\x46\xC1\xA1\x77\x8F\x87\xB0\x5F\xF8\xF3\x21\xCC\x23\x4D\xE3\xCC\x46" + "\x67\xA1\xB3\xAC\xE4\x3A\xD9\xEC\x3F\x0F\x42\x04\x19\x20\x87\x10\xA8\xC8\x63\x3F" + "\x01\x33\x07\x3C\xC3\xCE\xAF\xE0\x41\x36\x79\x9C\x87\xA1\xD8\x40\x8D\x83\x9E\x86" + "\x3F\xAF\x84\x08\xC8\xBA\xC6\xB3\xF0\xF6\x9B\x0E\x43\xD0\xEC\x20\x48\x9C\x7A\x0D" + "\xBE\x16\x62\xC3\xA1\x7F\x7F\x3F\x01\x07\x31\x45\xBD\x4F\xFD\x75\xB9\xD6\x12\x2D" + "\xE0\xCE\x87\xA1\xD8\x09\x18\x21\xE8\x37\x04\x61\x17\x58\xD6\x7E\x17\xB0\x33\x47" + "\x47\xA1\xD8\x08\xB3\x81\x0A\xC8\xB1\xA3\x9F\xCF\xC3\x96\x74\x99\x34\x81\x0E\xD8" + "\x20\xD0\x3D\x08\x59\x08\x5C\x7E\x0B\x17\xA2\x1E\x67\xB4\xD8\x72\x8F\x43\xB0\x88" + "\x59\x08\x5C\x7E\x1E\x9E\x7F\xDB\x04\x3B\xA7\xB4\xD8\x72\xCF\x43\xB0\x81\x22\x71" + "\xE8\x3B\x7A\xFE\x64\x5E\xAB\xA6\x7E\x1C\x67\xA1\xD8\x40\x8F\x2C\xF4\xF3\xF9\x9E" + "\x86\xC8\x2D\xF5\x02\x24\x90\x44\x8A\x09\x7C\x46\x82\x15\x33\xCC\x75\xFB\x43\x66" + "\x6F\xA8\xF3\x39\x0F\x43\xB0\x81\x1F\x09\x04\x3C\x58\xB4\x40\x4E\xC5\x0B\x44\x04" + "\x6C\x58\x11\x71\x52\xD1\x0F\xC3\xD0\x10\xB8\xE0\x21\x65\xF2\x08\xFC\x3B\x05\x8C" + "\xE1\x87\x60\x21\x4D\x3B\x01\x23\x0D\x04\x6C\x08\xF4\x66\x6F\xA8\xBC\x2C\x70\x22" + "\xE1\xEC\xCD\xF5\x02\x4E\x1A\x08\xF8\x09\xE8\x45\xE0\xC6\x08\x2F\xE1\x11\xF8\x08" + "\x34\x81\x0B\x59\x3A\x1B\x06\x84\x7A\x1D\x80\x87\x5C\x11\x37\x2A\x01\x60\xBC\x34" + "\x0D\x75\x7B\xC6\x30\x18\x5F\x0C\xC0\x87\x8A\x03\x02\xE1\x90\x11\xB0\xB0\x5F\xE1" + "\x88\x11\xB0\xB0\x51\xE1\x80\x10\xEE\x82\xDF\x0C\x60\x87\x18\x10\x79\x7D\x04\x2E" + "\x83\xD1\xF8\x7A\x1D\x9F\xCC\xA3\xF2\x70\xA4\x6E"; +#else const char WEMO_EVENTSERVICE_XML[] PROGMEM = "" "" @@ -190,6 +263,7 @@ const char WEMO_SETUP_XML[] PROGMEM = "" "" "\r\n"; +#endif /********************************************************************************************/ @@ -219,7 +293,11 @@ void HandleUpnpEvent(void) } } +#if defined(USE_RULES_COMPRESSION) || defined(USE_SCRIPT_COMPRESSION) + snprintf_P(event, sizeof(event), Decompress(WEMO_RESPONSE_STATE_SOAP, WEMO_RESPONSE_STATE_SOAP_SIZE).c_str(), state, bitRead(power, devices_present -1), state); +#else snprintf_P(event, sizeof(event), WEMO_RESPONSE_STATE_SOAP, state, bitRead(power, devices_present -1), state); +#endif WSSend(200, CT_XML, event); } @@ -227,21 +305,33 @@ void HandleUpnpService(void) { AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_EVENT_SERVICE)); +#if defined(USE_RULES_COMPRESSION) || defined(USE_SCRIPT_COMPRESSION) + WSSend(200, CT_PLAIN, Decompress(WEMO_EVENTSERVICE_XML, WEMO_EVENTSERVICE_XML_SIZE)); +#else WSSend(200, CT_PLAIN, FPSTR(WEMO_EVENTSERVICE_XML)); +#endif } void HandleUpnpMetaService(void) { AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_META_SERVICE)); +#if defined(USE_RULES_COMPRESSION) || defined(USE_SCRIPT_COMPRESSION) + WSSend(200, CT_PLAIN, Decompress(WEMO_METASERVICE_XML, WEMO_METASERVICE_XML_SIZE)); +#else WSSend(200, CT_PLAIN, FPSTR(WEMO_METASERVICE_XML)); +#endif } void HandleUpnpSetupWemo(void) { AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_SETUP)); +#if defined(USE_RULES_COMPRESSION) || defined(USE_SCRIPT_COMPRESSION) + String setup_xml = Decompress(WEMO_SETUP_XML, WEMO_SETUP_XML_SIZE); +#else String setup_xml = FPSTR(WEMO_SETUP_XML); +#endif setup_xml.replace("{x1", SettingsText(SET_FRIENDLYNAME1)); setup_xml.replace("{x2", WemoUuid()); setup_xml.replace("{x3", WemoSerialnumber()); diff --git a/tasmota/xnrg_07_ade7953.ino b/tasmota/xnrg_07_ade7953.ino index 44bec2e59..3d7b405d5 100644 --- a/tasmota/xnrg_07_ade7953.ino +++ b/tasmota/xnrg_07_ade7953.ino @@ -209,10 +209,9 @@ void Ade7953DrvInit(void) } I2cSetActiveFound(ADE7953_ADDR, "ADE7953"); Ade7953.init_step = 2; - Energy.phase_count = 2; // Handle two channels as two phases - Energy.voltage_common = true; // Use common voltage and frequency - + Energy.voltage_common = true; // Use common voltage + Energy.frequency_common = true; // Use common frequency energy_flg = XNRG_07; } } diff --git a/tasmota/xnrg_08_sdm120.ino b/tasmota/xnrg_08_sdm120.ino index 93af326f8..8f764ad52 100644 --- a/tasmota/xnrg_08_sdm120.ino +++ b/tasmota/xnrg_08_sdm120.ino @@ -134,7 +134,7 @@ void SDM120Every250ms(void) break; case 9: - Energy.export_active = value; // 6.216 kWh + Energy.export_active[0] = value; // 6.216 kWh break; case 10: diff --git a/tasmota/xnrg_09_dds2382.ino b/tasmota/xnrg_09_dds2382.ino index a516ea4a8..7acb36f05 100644 --- a/tasmota/xnrg_09_dds2382.ino +++ b/tasmota/xnrg_09_dds2382.ino @@ -74,7 +74,7 @@ void Dds2382EverySecond(void) if (Settings.flag3.dds2382_model) { // SetOption71 - Select different Modbus registers for Active Energy (#6531) offset = 19; } - Energy.export_active = (float)((buffer[offset] << 24) + (buffer[offset +1] << 16) + (buffer[offset +2] << 8) + buffer[offset +3]) / 100.0; // 429496.729 kW + Energy.export_active[0] = (float)((buffer[offset] << 24) + (buffer[offset +1] << 16) + (buffer[offset +2] << 8) + buffer[offset +3]) / 100.0; // 429496.729 kW float import_active = (float)((buffer[offset +4] << 24) + (buffer[offset +5] << 16) + (buffer[offset +6] << 8) + buffer[offset +7]) / 100.0; // 429496.729 kW EnergyUpdateTotal(import_active, true); // 484.708 kWh diff --git a/tasmota/xnrg_10_sdm630.ino b/tasmota/xnrg_10_sdm630.ino index 4bfeecc96..d239c1c73 100644 --- a/tasmota/xnrg_10_sdm630.ino +++ b/tasmota/xnrg_10_sdm630.ino @@ -40,22 +40,30 @@ TasmotaModbus *Sdm630Modbus; const uint16_t sdm630_start_addresses[] { - 0x0000, // L1 - SDM630_VOLTAGE [V] - 0x0002, // L2 - SDM630_VOLTAGE [V] - 0x0004, // L3 - SDM630_VOLTAGE [V] - 0x0006, // L1 - SDM630_CURRENT [A] - 0x0008, // L2 - SDM630_CURRENT [A] - 0x000A, // L3 - SDM630_CURRENT [A] - 0x000C, // L1 - SDM630_POWER [W] - 0x000E, // L2 - SDM630_POWER [W] - 0x0010, // L3 - SDM630_POWER [W] - 0x0018, // L1 - SDM630_REACTIVE_POWER [VAR] - 0x001A, // L2 - SDM630_REACTIVE_POWER [VAR] - 0x001C, // L3 - SDM630_REACTIVE_POWER [VAR] - 0x001E, // L1 - SDM630_POWER_FACTOR - 0x0020, // L2 - SDM630_POWER_FACTOR - 0x0022, // L3 - SDM630_POWER_FACTOR - 0x0156 // Total - SDM630_TOTAL_ACTIVE_ENERGY [Wh] + // 3P4 3P3 1P2 Unit Description + 0x0000, // + - + V Phase 1 line to neutral volts + 0x0002, // + - - V Phase 2 line to neutral volts + 0x0004, // + - - V Phase 3 line to neutral volts + 0x0006, // + + + A Phase 1 current + 0x0008, // + + - A Phase 2 current + 0x000A, // + + - A Phase 3 current + 0x000C, // + - + W Phase 1 power + 0x000E, // + - + W Phase 2 power + 0x0010, // + - - W Phase 3 power + 0x0018, // + - + VAr Phase 1 volt amps reactive + 0x001A, // + - - VAr Phase 2 volt amps reactive + 0x001C, // + - - VAr Phase 3 volt amps reactive + 0x001E, // + - + Phase 1 power factor + 0x0020, // + - - Phase 2 power factor + 0x0022, // + - - Phase 3 power factor + 0x0046, // + + + Hz Frequency of supply voltages + 0x0160, // + + + kWh Phase 1 export active energy + 0x0162, // + + + kWh Phase 2 export active energy + 0x0164, // + + + kWh Phase 3 export active energy +// 0x015A, // + + + kWh Phase 1 import active energy +// 0x015C, // + + + kWh Phase 2 import active energy +// 0x015E, // + + + kWh Phase 3 import active energy + 0x0156 // + + + kWh Total active energy }; struct SDM630 { @@ -153,6 +161,22 @@ void SDM630Every250ms(void) break; case 15: + Energy.frequency[0] = value; + break; + + case 16: + Energy.export_active[0] = value; + break; + + case 17: + Energy.export_active[1] = value; + break; + + case 18: + Energy.export_active[2] = value; + break; + + case 19: EnergyUpdateTotal(value, true); break; } @@ -179,6 +203,7 @@ void Sdm630SnsInit(void) if (result) { if (2 == result) { ClaimSerial(); } Energy.phase_count = 3; + Energy.frequency_common = true; // Use common frequency } else { energy_flg = ENERGY_NONE; } diff --git a/tasmota/xnrg_11_ddsu666.ino b/tasmota/xnrg_11_ddsu666.ino index 87b585d84..f01ad50a5 100644 --- a/tasmota/xnrg_11_ddsu666.ino +++ b/tasmota/xnrg_11_ddsu666.ino @@ -110,7 +110,7 @@ void DDSU666Every250ms(void) break; case 7: - Energy.export_active = value; // 6.216 kWh + Energy.export_active[0] = value; // 6.216 kWh break; } diff --git a/tasmota/xsns_53_sml.ino b/tasmota/xsns_53_sml.ino index c63478b48..3b4357b26 100755 --- a/tasmota/xsns_53_sml.ino +++ b/tasmota/xsns_53_sml.ino @@ -2151,6 +2151,7 @@ init10: #else #ifdef ESP32 meter_ss[meters] = new HardwareSerial(uart_index); + if (uart_index==0) { ClaimSerial(); } uart_index--; if (uart_index<0) uart_index=0; #else @@ -2216,7 +2217,13 @@ uint32_t SML_Write(uint32_t meter,char *hstr) { SML_Send_Seq(meter,hstr); return 1; } -#endif + +float SML_GetVal(uint32_t index) { + if (index<1 && index>SML_MAX_VARS) { index = 1;} + return meter_vars[index-1]; +} + +#endif // USE_SML_SCRIPT_CMD void SetDBGLed(uint8_t srcpin, uint8_t ledpin) {