From 039fd65f64ceb0ff9d92a51427011b3a5cd0348f Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Fri, 3 Dec 2021 20:10:24 +0100 Subject: [PATCH 1/9] LVGL simplified font code --- tasmota/xdrv_52_3_berry_lvgl.ino | 431 ++++++++++++++----------------- 1 file changed, 195 insertions(+), 236 deletions(-) diff --git a/tasmota/xdrv_52_3_berry_lvgl.ino b/tasmota/xdrv_52_3_berry_lvgl.ino index af435851b..dcf1f9968 100644 --- a/tasmota/xdrv_52_3_berry_lvgl.ino +++ b/tasmota/xdrv_52_3_berry_lvgl.ino @@ -404,6 +404,10 @@ extern "C" { be_return(vm); } + /*********************************************************************************************\ + * Support for lv_fonts + \*********************************************************************************************/ + // load font by name on file-system int lv0_load_font(bvm *vm) { int argc = be_top(vm); if (argc == 1 && be_isstring(vm, 1)) { @@ -421,6 +425,10 @@ extern "C" { be_raise(vm, kTypeError, nullptr); } + /*********************************************************************************************\ + * Support for Freetype fonts + \*********************************************************************************************/ + // load freetype font by name in file-system int lv0_load_freetype_font(bvm *vm) { #ifdef USE_LVGL_FREETYPE int argc = be_top(vm); @@ -448,261 +456,212 @@ extern "C" { #endif // USE_LVGL_FREETYPE } - int lv0_load_montserrat_font(bvm *vm) { - int argc = be_top(vm); - if (argc == 1 && be_isint(vm, 1)) { - const lv_font_t * font = nullptr; - int32_t font_size = be_toindex(vm, 1); + /*********************************************************************************************\ + * Support for embedded fonts in Flash + \*********************************************************************************************/ + // We create tables for Font matching + // Size of `0` indicates end of table + typedef struct { + int16_t size; + const lv_font_t *font; + } lv_font_table_t; - switch (font_size) { + typedef struct { + const char * name; + const lv_font_table_t * table; + } lv_font_names_t; - #if LV_FONT_MONTSERRAT_8 - case 8: - font = &lv_font_montserrat_8; - break; - #endif + // Montserrat Font + const lv_font_table_t lv_montserrat_fonts[] = { + #if LV_FONT_MONTSERRAT_8 + { 8, &lv_font_montserrat_8 }, + #endif + #if LV_FONT_MONTSERRAT_10 + { 10, &lv_font_montserrat_10 }, + #endif + #if LV_FONT_MONTSERRAT_12 + { 12, &lv_font_montserrat_12 }, + #endif + #if LV_FONT_MONTSERRAT_14 + { 14, &lv_font_montserrat_14 }, + #endif + #if LV_FONT_MONTSERRAT_16 + { 16, &lv_font_montserrat_16 }, + #endif + #if LV_FONT_MONTSERRAT_18 + { 18, &lv_font_montserrat_18 }, + #endif + #if LV_FONT_MONTSERRAT_20 + { 20, &lv_font_montserrat_20 }, + #endif + #if LV_FONT_MONTSERRAT_22 + { 22, &lv_font_montserrat_22 }, + #endif + #if LV_FONT_MONTSERRAT_24 + { 24, &lv_font_montserrat_24 }, + #endif + #if LV_FONT_MONTSERRAT_26 + { 26, &lv_font_montserrat_26 }, + #endif + #if LV_FONT_MONTSERRAT_28 + { 28, &lv_font_montserrat_28 }, + #endif + #if LV_FONT_MONTSERRAT_28_COMPRESSED + { 28, &lv_font_montserrat_28_compressed, }, + #endif + #if LV_FONT_MONTSERRAT_30 + { 30, &lv_font_montserrat_30 }, + #endif + #if LV_FONT_MONTSERRAT_32 + { 32, &lv_font_montserrat_32 }, + #endif + #if LV_FONT_MONTSERRAT_34 + { 34, &lv_font_montserrat_34 }, + #endif + #if LV_FONT_MONTSERRAT_36 + { 36, &lv_font_montserrat_36 }, + #endif + #if LV_FONT_MONTSERRAT_38 + { 38, &lv_font_montserrat_38 }, + #endif + #if LV_FONT_MONTSERRAT_40 + { 40, &lv_font_montserrat_40 }, + #endif + #if LV_FONT_MONTSERRAT_42 + { 42, &lv_font_montserrat_42 }, + #endif + #if LV_FONT_MONTSERRAT_44 + { 44, &lv_font_montserrat_44 }, + #endif + #if LV_FONT_MONTSERRAT_46 + { 46, &lv_font_montserrat_46 }, + #endif + #if LV_FONT_MONTSERRAT_48 + { 48, &lv_font_montserrat_48 }, + #endif + { 0, nullptr} + }; - #if LV_FONT_MONTSERRAT_10 - case 10: - font = &lv_font_montserrat_10; - break; - #endif + // Seg7 Font + const lv_font_table_t lv_seg7_fonts[] = { + { 8, &seg7_8 }, + { 10, &seg7_10 }, + { 12, &seg7_12 }, + { 14, &seg7_14 }, + { 16, &seg7_16 }, + { 18, &seg7_18 }, + { 20, &seg7_20 }, + { 24, &seg7_24 }, + { 28, &seg7_28 }, + { 36, &seg7_36 }, + { 48, &seg7_48 }, + }; - #if LV_FONT_MONTSERRAT_12 - case 12: - font = &lv_font_montserrat_12; - break; - #endif + // robotocondensed-latin1 + const lv_font_table_t lv_robotocondensed_fonts[] = { +#if ROBOTOCONDENSED_REGULAR_12_LATIN1 + { 12, &robotocondensed_regular_12_latin1 }, +#endif +#if ROBOTOCONDENSED_REGULAR_14_LATIN1 + { 14, &robotocondensed_regular_14_latin1 }, +#endif +#if ROBOTOCONDENSED_REGULAR_16_LATIN1 + { 16, &robotocondensed_regular_16_latin1 }, +#endif +#if ROBOTOCONDENSED_REGULAR_20_LATIN1 + { 20, &robotocondensed_regular_20_latin1 }, +#endif +#if ROBOTOCONDENSED_REGULAR_22_LATIN1 + { 22, &robotocondensed_regular_22_latin1 }, +#endif +#if ROBOTOCONDENSED_REGULAR_24_LATIN1 + { 24, &robotocondensed_regular_24_latin1 }, +#endif +#if ROBOTOCONDENSED_REGULAR_28_LATIN1 + { 28, &robotocondensed_regular_28_latin1 }, +#endif +#if ROBOTOCONDENSED_REGULAR_32_LATIN1 + { 32, &robotocondensed_regular_32_latin1 }, +#endif +#if ROBOTOCONDENSED_REGULAR_36_LATIN1 + { 36, &robotocondensed_regular_36_latin1 }, +#endif +#if ROBOTOCONDENSED_REGULAR_38_LATIN1 + { 38, &robotocondensed_regular_38_latin1 }, +#endif +#if ROBOTOCONDENSED_REGULAR_40_LATIN1 + { 40, &robotocondensed_regular_40_latin1 }, +#endif +#if ROBOTOCONDENSED_REGULAR_44_LATIN1 + { 44, &robotocondensed_regular_44_latin1 }, +#endif +#if ROBOTOCONDENSED_REGULAR_48_LATIN1 + { 48, &robotocondensed_regular_48_latin1 }, +#endif + }; - #if LV_FONT_MONTSERRAT_14 - case 14: - font = &lv_font_montserrat_14; - break; - #endif + // register all included fonts + const lv_font_names_t lv_embedded_fonts[] = { + { "montserrat", lv_montserrat_fonts }, + { "seg7", lv_seg7_fonts }, +#ifdef USE_LVGL_OPENHASP + { "robotocondensed", lv_robotocondensed_fonts }, +#endif + { nullptr, nullptr} + }; - #if LV_FONT_MONTSERRAT_16 - case 16: - font = &lv_font_montserrat_16; - break; - #endif - - #if LV_FONT_MONTSERRAT_18 - case 18: - font = &lv_font_montserrat_18; - break; - #endif - - #if LV_FONT_MONTSERRAT_20 - case 20: - font = &lv_font_montserrat_20; - break; - #endif - - #if LV_FONT_MONTSERRAT_22 - case 22: - font = &lv_font_montserrat_22; - break; - #endif - - #if LV_FONT_MONTSERRAT_24 - case 24: - font = &lv_font_montserrat_24; - break; - #endif - - #if LV_FONT_MONTSERRAT_26 - case 26: - font = &lv_font_montserrat_26; - break; - #endif - - #if LV_FONT_MONTSERRAT_28 - case 28: - font = &lv_font_montserrat_28; - break; - #endif - - #if LV_FONT_MONTSERRAT_30 - case 30: - font = &lv_font_montserrat_30; - break; - #endif - - #if LV_FONT_MONTSERRAT_32 - case 32: - font = &lv_font_montserrat_32; - break; - #endif - - #if LV_FONT_MONTSERRAT_34 - case 34: - font = &lv_font_montserrat_34; - break; - #endif - - #if LV_FONT_MONTSERRAT_36 - case 36: - font = &lv_font_montserrat_36; - break; - #endif - - #if LV_FONT_MONTSERRAT_38 - case 38: - font = &lv_font_montserrat_38; - break; - #endif - - #if LV_FONT_MONTSERRAT_40 - case 40: - font = &lv_font_montserrat_40; - break; - #endif - - #if LV_FONT_MONTSERRAT_42 - case 42: - font = &lv_font_montserrat_42; - break; - #endif - - #if LV_FONT_MONTSERRAT_44 - case 44: - font = &lv_font_montserrat_44; - break; - #endif - - #if LV_FONT_MONTSERRAT_46 - case 46: - font = &lv_font_montserrat_46; - break; - #endif - - #if LV_FONT_MONTSERRAT_48 - case 48: - font = &lv_font_montserrat_48; - break; - #endif - - #if LV_FONT_MONTSERRAT_28_COMPRESSED - case 28: - font = &lv_font_montserrat_28_compressed; - break; - #endif - - default: - break; - } - - if (font != nullptr) { - be_find_class(vm, "lv.lv_font"); - be_pushcomptr(vm, (void*)font); - be_call(vm, 1); - be_pop(vm, 1); - be_return(vm); - } else { - be_return_nil(vm); + // If size is zero, it is read at arg 1 + int lv_load_embedded_font(bvm *vm, const char * name, int16_t size) { + if (0 == size) { + if (be_top(vm) >= 1 && be_isint(vm, 1)) { + size = be_toindex(vm, 1); } } - be_raise(vm, kTypeError, nullptr); + if (name == nullptr || 0 == size) { + be_raise(vm, "value_error", ""); + } + // first look for font + const lv_font_names_t * font_name_cursor = lv_embedded_fonts; + for (font_name_cursor = lv_embedded_fonts; font_name_cursor->name; font_name_cursor++) { + if (strcmp(name, font_name_cursor->name) == 0) break; // found + } + if (font_name_cursor->name == nullptr) { + be_raisef(vm, "value_error", "unknown font '%s'", name); + } + // scan for font size + const lv_font_table_t * font_entry = font_name_cursor->table; + for (font_entry = font_name_cursor->table; font_entry->size; font_entry++) { + if (font_entry->size == size) break; // found + } + if (font_entry->size == 0) { + be_raisef(vm, "value_error", "unknown font size '%s-%i'", name, size); + } + + be_find_class(vm, "lv.lv_font"); + be_pushcomptr(vm, (void*)font_entry->font); + be_call(vm, 1); + be_pop(vm, 1); + be_return(vm); + } + + int lv0_load_montserrat_font(bvm *vm) { + return lv_load_embedded_font(vm, "montserrat", 0); } int lv0_load_seg7_font(bvm *vm) { - int argc = be_top(vm); - if (argc == 1 && be_isint(vm, 1)) { - const lv_font_t * font = nullptr; - int32_t font_size = be_toindex(vm, 1); - - switch (font_size) { - case 8: font = &seg7_8; break; - case 10: font = &seg7_10; break; - case 12: font = &seg7_12; break; - case 14: font = &seg7_14; break; - case 16: font = &seg7_16; break; - case 18: font = &seg7_18; break; - case 20: font = &seg7_20; break; - case 24: font = &seg7_24; break; - case 28: font = &seg7_28; break; - case 36: font = &seg7_36; break; - case 48: font = &seg7_48; break; - default: break; - } - - if (font != nullptr) { - be_find_class(vm, "lv.lv_font"); - be_pushcomptr(vm, (void*)font); - be_call(vm, 1); - be_pop(vm, 1); - be_return(vm); - } else { - be_return_nil(vm); - } - } - be_raise(vm, kTypeError, nullptr); + return lv_load_embedded_font(vm, "seg7", 0); } int lv0_load_robotocondensed_latin1_font(bvm *vm) { #ifdef USE_LVGL_OPENHASP - int argc = be_top(vm); - if (argc == 1 && be_isint(vm, 1)) { - const lv_font_t * font = nullptr; - int32_t font_size = be_toindex(vm, 1); - - switch (font_size) { -#if ROBOTOCONDENSED_REGULAR_12_LATIN1 - case 12: font = &robotocondensed_regular_12_latin1; break; -#endif -#if ROBOTOCONDENSED_REGULAR_14_LATIN1 - case 14: font = &robotocondensed_regular_14_latin1; break; -#endif -#if ROBOTOCONDENSED_REGULAR_16_LATIN1 - case 16: font = &robotocondensed_regular_16_latin1; break; -#endif -#if ROBOTOCONDENSED_REGULAR_20_LATIN1 - case 20: font = &robotocondensed_regular_20_latin1; break; -#endif -#if ROBOTOCONDENSED_REGULAR_22_LATIN1 - case 22: font = &robotocondensed_regular_22_latin1; break; -#endif -#if ROBOTOCONDENSED_REGULAR_24_LATIN1 - case 24: font = &robotocondensed_regular_24_latin1; break; -#endif -#if ROBOTOCONDENSED_REGULAR_28_LATIN1 - case 28: font = &robotocondensed_regular_28_latin1; break; -#endif -#if ROBOTOCONDENSED_REGULAR_32_LATIN1 - case 32: font = &robotocondensed_regular_32_latin1; break; -#endif -#if ROBOTOCONDENSED_REGULAR_36_LATIN1 - case 36: font = &robotocondensed_regular_36_latin1; break; -#endif -#if ROBOTOCONDENSED_REGULAR_38_LATIN1 - case 38: font = &robotocondensed_regular_38_latin1; break; -#endif -#if ROBOTOCONDENSED_REGULAR_40_LATIN1 - case 40: font = &robotocondensed_regular_40_latin1; break; -#endif -#if ROBOTOCONDENSED_REGULAR_44_LATIN1 - case 44: font = &robotocondensed_regular_44_latin1; break; -#endif -#if ROBOTOCONDENSED_REGULAR_48_LATIN1 - case 48: font = &robotocondensed_regular_48_latin1; break; -#endif - default: break; - } - - if (font != nullptr) { - be_find_class(vm, "lv.lv_font"); - be_pushcomptr(vm, (void*)font); - be_call(vm, 1); - be_pop(vm, 1); - be_return(vm); - } else { - be_return_nil(vm); - } - } + return lv_load_embedded_font(vm, "robotocondensed", 0); #endif // USE_LVGL_OPENHASP be_raise(vm, kTypeError, nullptr); } + /*********************************************************************************************\ + * Tasmota Logo + \*********************************************************************************************/ #include "lvgl_berry/tasmota_logo_64_truecolor_alpha.h" void lv_img_set_tasmota_logo(lv_obj_t * img) { From d6760962cdefb2734ecb7dcaf781097721641844 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Fri, 3 Dec 2021 20:12:46 +0100 Subject: [PATCH 2/9] LVGL screenshot in BMP format --- tasmota/xdrv_52_3_berry_lvgl.ino | 44 +++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/tasmota/xdrv_52_3_berry_lvgl.ino b/tasmota/xdrv_52_3_berry_lvgl.ino index af435851b..9a2973df1 100644 --- a/tasmota/xdrv_52_3_berry_lvgl.ino +++ b/tasmota/xdrv_52_3_berry_lvgl.ino @@ -956,11 +956,53 @@ extern "C" { if (!glue) { be_return_nil(vm); } char fname[32]; - snprintf(fname, sizeof(fname), "/screenshot-%d.raw", Rtc.utc_time); + snprintf(fname, sizeof(fname), "/screenshot-%d.bmp", Rtc.utc_time); File f = dfsp->open(fname, "w"); if (f) { glue->setScreenshotFile(&f); + uint32_t bmp_width = lv_disp_get_hor_res(nullptr); + uint32_t bmp_height = lv_disp_get_ver_res(nullptr); + + // write BMP header + static const uint8_t bmp_sign[] = { 0x42, 0x4d }; // BM = Windows + f.write(bmp_sign, sizeof(bmp_sign)); + size_t bmp_size = bmp_width * bmp_height * LV_COLOR_DEPTH / 8 + 0x44; + f.write((uint8_t*)&bmp_size, sizeof(bmp_size)); + uint32_t zero = 0; + f.write((uint8_t*) &zero, sizeof(zero)); // reserved 4-bytes + uint32_t bmp_offset_to_pixels = 0x44; // TODO + f.write((uint8_t*) &bmp_offset_to_pixels, sizeof(bmp_offset_to_pixels)); + + // DIB Header BITMAPINFOHEADER + size_t bmp_dib_header_size = 52; // BITMAPV2INFOHEADER + f.write((uint8_t*) &bmp_dib_header_size, sizeof(bmp_dib_header_size)); + + f.write((uint8_t*) &bmp_width, sizeof(bmp_width)); + f.write((uint8_t*) &bmp_height, sizeof(bmp_height)); + + // rest of header + // BITMAPV2INFOHEADER = 52 bytes header, 40 bytes sub-header + static const uint8_t bmp_dib_header[] = { + 0x01, 0x00, // planes + 16, 0x00, // bits per pixel = 16 + 0x03, 0x00, 0x00, 0x00, // compression = BI_BITFIELDS uncrompressed + 0x00, 0x00, 0x00, 0x00, // Image size, 0 is valid for BI_RGB (uncompressed) TODO + 0x00, 0x00, 0x00, 0x00, // X pixels per meter + 0x00, 0x00, 0x00, 0x00, // Y pixels per meter + 0x00, 0x00, 0x00, 0x00, // Colors in table + 0x00, 0x00, 0x00, 0x00, // Important color count + + // RGB masks + 0x00, 0xF8, 0x00, 0x00, // Red channel mask + 0xE0, 0x07, 0x00, 0x00, // Green channel mask + 0x1F, 0x00, 0x00, 0x00, // Blue channel mask + + 0x00, 0x00, // Padding to align on 4 bytes boundary + }; + f.write(bmp_dib_header, sizeof(bmp_dib_header)); + // now we can write the pixels array + // redraw screen lv_obj_invalidate(lv_scr_act()); lv_refr_now(lv_disp_get_default()); From 581d710a7b1d6c187b88c80cd4a0dbfe75515213 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Fri, 3 Dec 2021 20:33:20 +0100 Subject: [PATCH 3/9] Use toolchains 8.4.0-2021r2 --- platformio_tasmota32.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio_tasmota32.ini b/platformio_tasmota32.ini index 5ef6f0463..575f9d160 100644 --- a/platformio_tasmota32.ini +++ b/platformio_tasmota32.ini @@ -32,14 +32,14 @@ build_flags = ${esp_defaults.build_flags} -Wl,--wrap=panicHandler -Wl,--wrap=xt_unhandled_exception [core32] -platform = https://github.com/tasmota/platform-espressif32/releases/download/v3.4.0/Tasmota-platform-espressif32.zip +platform = https://github.com/tasmota/platform-espressif32/releases/download/v3.4.1/Tasmota-platform-espressif32.zip platform_packages = build_unflags = ${esp32_defaults.build_unflags} build_flags = ${esp32_defaults.build_flags} [core32solo1] -platform = https://github.com/tasmota/platform-espressif32/releases/download/v3.4.0/Tasmota-platform-espressif32.zip +platform = https://github.com/tasmota/platform-espressif32/releases/download/v3.4.1/Tasmota-platform-espressif32.zip platform_packages = framework-arduinoespressif32 @ https://github.com/tasmota/arduino-esp32/releases/download/2.0.1.1/framework-arduinoespressif32-solo1-release_IDF4.4.tar.gz build_unflags = ${esp32_defaults.build_unflags} build_flags = ${esp32_defaults.build_flags} From 86922aab8c9eb3d0b1fe749f1926d1cd8afa30b1 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Fri, 3 Dec 2021 21:09:19 +0100 Subject: [PATCH 4/9] Toolchains changed --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb781e0d4..804a381a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,10 +12,11 @@ All notable changes to this project will be documented in this file. - (Internal) Range conversion edge values - NimBLE to v.1.3.3 - MQTT TLS dual mode (CA or fingeprint) in same firmware, ``SetOption132 1`` to force fingerprint +- Toolchains for ESP32x changed from 8.4.0-2021r1 to 8.4.0-2021r2 ### Fixed - Tuya dimmer range issue (#13849) -- BLE Memory leak with update NimBLE v.1.3.1 to v.1.3.3 +- BLE Memory leak with update NimBLE v.1.3.1 to v.1.3.3 ## [10.0.0.3] 20211130 ### Added From 9cc2394d672c34adda3f036168f55307b077e6eb Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 4 Dec 2021 12:02:26 +0100 Subject: [PATCH 5/9] Add shift 74xx595 persistence --- tasmota/settings.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tasmota/settings.h b/tasmota/settings.h index 3686b1d42..b488df2e6 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -162,7 +162,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t show_heap_with_timestamp : 1; // bit 16 (v9.5.0.9) - SetOption130 - (Debug) Show heap with logging timestamp uint32_t tuya_allow_dimmer_0 : 1; // bit 17 (v10.0.0.3) - SetOption131 - (Tuya) Allow save dimmer = 0 receved by MCU uint32_t tls_use_fingerprint : 1; // bit 18 (v10.0.0.4) - SetOption132 - (TLS) use fingerprint validation instead of CA based - uint32_t spare19 : 1; // bit 19 + uint32_t shift595_option : 1; // bit 19 (v10.0.0.4) - SetOption133 - (595) uint32_t spare20 : 1; // bit 20 uint32_t spare21 : 1; // bit 21 uint32_t spare22 : 1; // bit 22 @@ -686,8 +686,9 @@ typedef struct { uint8_t weight_change; // E9F uint8_t web_color2[2][3]; // EA0 Needs to be on integer / 3 distance from web_color - uint8_t free_ea6[33]; // EA6 + uint8_t free_ea6[32]; // EA6 + uint8_t shift595; // EC6 uint8_t sta_config; // EC7 uint8_t sta_active; // EC8 uint8_t rule_stop; // EC9 From 3a92189c44eb61a9b8c1c3ced875451a221a5b0a Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 4 Dec 2021 12:26:19 +0100 Subject: [PATCH 6/9] Add command SspmDisplay Add command ``SspmDisplay 0/1`` to change GUI display to powered on relays only. --- tasmota/xdrv_86_esp32_sonoff_spm.ino | 106 +++++++++++++++++---------- 1 file changed, 68 insertions(+), 38 deletions(-) diff --git a/tasmota/xdrv_86_esp32_sonoff_spm.ino b/tasmota/xdrv_86_esp32_sonoff_spm.ino index 9f858691b..afe70b115 100644 --- a/tasmota/xdrv_86_esp32_sonoff_spm.ino +++ b/tasmota/xdrv_86_esp32_sonoff_spm.ino @@ -175,6 +175,7 @@ typedef struct { uint8_t command_sequence; uint8_t mstate; uint8_t last_button; + uint8_t gui_display; bool discovery_triggered; } TSspm; @@ -1082,29 +1083,30 @@ bool SSPMButton(void) { /*********************************************************************************************/ const uint16_t SSPM_SIZE = 128; -const char kSSPMEnergyPhases[] PROGMEM = "%*_f%*_f%*_f%*_f|[%*_f,%*_f,%*_f,%*_f]"; -char* SSPMEnergyFormat(char* result, float* input, uint32_t resolution, bool json) { - char layout[100]; - GetTextIndexed(layout, sizeof(layout), json, kSSPMEnergyPhases); - ext_snprintf_P(result, SSPM_SIZE, layout, resolution, &input[0], resolution, &input[1], resolution, &input[2], resolution, &input[3]); +char* SSPMEnergyFormat(char* result, float* input, uint32_t resolution, uint8_t* indirect, uint8_t offset, uint32_t count) { + result[0] = '\0'; + for (uint32_t i = 0; i < count; i++) { + ext_snprintf_P(result, SSPM_SIZE, PSTR("%s%*_f"), result, resolution, &input[indirect[offset +i]]); + } + ext_snprintf_P(result, SSPM_SIZE, PSTR("%s"), result); return result; } const char HTTP_SSPM_VOLTAGE[] PROGMEM = - "{s}" D_VOLTAGE "%s" D_UNIT_VOLT "{e}"; // {s} = , {m} = , {e} = + "{s}" D_VOLTAGE "%s" D_UNIT_VOLT "{e}"; // {s} = , {m} = , {e} = const char HTTP_SSPM_CURRENT[] PROGMEM = - "{s}" D_CURRENT "%s" D_UNIT_AMPERE "{e}"; + "{s}" D_CURRENT "%s" D_UNIT_AMPERE "{e}"; const char HTTP_SSPM_POWER[] PROGMEM = - "{s}" D_POWERUSAGE_ACTIVE "%s" D_UNIT_WATT "{e}"; + "{s}" D_POWERUSAGE_ACTIVE "%s" D_UNIT_WATT "{e}"; const char HTTP_SSPM_POWER2[] PROGMEM = - "{s}" D_POWERUSAGE_APPARENT "%s" D_UNIT_VA "{e}" - "{s}" D_POWERUSAGE_REACTIVE "%s" D_UNIT_VAR "{e}" - "{s}" D_POWER_FACTOR "%s{e}"; + "{s}" D_POWERUSAGE_APPARENT "%s" D_UNIT_VA "{e}" + "{s}" D_POWERUSAGE_REACTIVE "%s" D_UNIT_VAR "{e}" + "{s}" D_POWER_FACTOR "%s{e}"; const char HTTP_SSPM_ENERGY[] PROGMEM = - "{s}" D_ENERGY_TODAY "%s" D_UNIT_KILOWATTHOUR "{e}" - "{s}" D_ENERGY_YESTERDAY "%s" D_UNIT_KILOWATTHOUR "{e}" - "{s}" D_ENERGY_TOTAL "%s" D_UNIT_KILOWATTHOUR "{e}"; + "{s}" D_ENERGY_TODAY "%s" D_UNIT_KILOWATTHOUR "{e}" + "{s}" D_ENERGY_YESTERDAY "%s" D_UNIT_KILOWATTHOUR "{e}" + "{s}" D_ENERGY_TOTAL "%s" D_UNIT_KILOWATTHOUR "{e}"; void SSPMEnergyShow(bool json) { if (!TasmotaGlobal.devices_present) { return; } // Not ready yet @@ -1152,30 +1154,50 @@ void SSPMEnergyShow(bool json) { } ResponseAppend_P(PSTR("]}")); } else { - Sspm->rotate++; - if (Sspm->rotate >= TasmotaGlobal.devices_present) { - Sspm->rotate = 0; + uint8_t relay[SSPM_MAX_MODULES * 4]; + uint8_t indirect[SSPM_MAX_MODULES * 4]; + + uint32_t index = 0; + power_t power = TasmotaGlobal.power; + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + if ((0 == Sspm->gui_display) || + ((1 == Sspm->gui_display) && (power >> i) &1)) { + relay[index] = i +1; + indirect[index] = i; + index++; + } } - uint32_t module = Sspm->rotate >> 2; - uint32_t relay_base = module * 4; - WSContentSend_P(PSTR("{t}{s}")); // First column is empty ({t} = , {s} =
) - for (uint32_t i = 1; i < 5; i++) { - WSContentSend_P(PSTR("L%d"), relay_base +i); + + if (index) { + uint32_t offset = 0; + if (index > 4) { + Sspm->rotate++; + if (Sspm->rotate >= ((index -1) >> 2) << 3) { + Sspm->rotate = 0; + } + offset = (Sspm->rotate >> 2) * 4; + } + uint32_t count = index - offset; + if (count > 4) { count = 4; } + WSContentSend_P(PSTR("
{t}{s}")); // First column is empty ({t} = , {s} = ) + char value_chr[SSPM_SIZE]; + WSContentSend_PD(HTTP_SSPM_VOLTAGE, SSPMEnergyFormat(value_chr, Sspm->voltage[0], Settings->flag2.voltage_resolution, indirect, offset, count)); + WSContentSend_PD(HTTP_SSPM_CURRENT, SSPMEnergyFormat(value_chr, Sspm->current[0], Settings->flag2.current_resolution, indirect, offset, count)); + WSContentSend_PD(HTTP_SSPM_POWER, SSPMEnergyFormat(value_chr, Sspm->active_power[0], Settings->flag2.wattage_resolution, indirect, offset, count)); + char valu2_chr[SSPM_SIZE]; + char valu3_chr[SSPM_SIZE]; + WSContentSend_PD(HTTP_SSPM_POWER2, SSPMEnergyFormat(value_chr, Sspm->apparent_power[0], Settings->flag2.wattage_resolution, indirect, offset, count), + SSPMEnergyFormat(valu2_chr, Sspm->reactive_power[0], Settings->flag2.wattage_resolution, indirect, offset, count), + SSPMEnergyFormat(valu3_chr, Sspm->power_factor[0], 2, indirect, offset, count)); + WSContentSend_PD(HTTP_SSPM_ENERGY, SSPMEnergyFormat(value_chr, Sspm->energy_today[0], Settings->flag2.energy_resolution, indirect, offset, count), + SSPMEnergyFormat(valu2_chr, Sspm->energy_yesterday[0], Settings->flag2.energy_resolution, indirect, offset, count), + SSPMEnergyFormat(valu3_chr, Sspm->energy_total[0], Settings->flag2.energy_resolution, indirect, offset, count)); + WSContentSend_P(PSTR("
) + for (uint32_t i = 0; i < count; i++) { + WSContentSend_P(PSTR("L%d"), relay[offset +i]); + } + WSContentSend_P(PSTR("{e}")); // Last column is units ({e} =
{t}")); // {t} = - Define for next FUNC_WEB_SENSOR } - WSContentSend_P(PSTR(") - char value_chr[SSPM_SIZE]; - WSContentSend_PD(HTTP_SSPM_VOLTAGE, SSPMEnergyFormat(value_chr, Sspm->voltage[module], Settings->flag2.voltage_resolution, json)); - WSContentSend_PD(HTTP_SSPM_CURRENT, SSPMEnergyFormat(value_chr, Sspm->current[module], Settings->flag2.current_resolution, json)); - WSContentSend_PD(HTTP_SSPM_POWER, SSPMEnergyFormat(value_chr, Sspm->active_power[module], Settings->flag2.wattage_resolution, json)); - char valu2_chr[SSPM_SIZE]; - char valu3_chr[SSPM_SIZE]; - WSContentSend_PD(HTTP_SSPM_POWER2, SSPMEnergyFormat(value_chr, Sspm->apparent_power[module], Settings->flag2.wattage_resolution, json), - SSPMEnergyFormat(valu2_chr, Sspm->reactive_power[module], Settings->flag2.wattage_resolution, json), - SSPMEnergyFormat(valu3_chr, Sspm->power_factor[module], 2, json)); - WSContentSend_PD(HTTP_SSPM_ENERGY, SSPMEnergyFormat(value_chr, Sspm->energy_today[module], Settings->flag2.energy_resolution, json), - SSPMEnergyFormat(valu2_chr, Sspm->energy_yesterday[module], Settings->flag2.energy_resolution, json), - SSPMEnergyFormat(valu3_chr, Sspm->energy_total[module], Settings->flag2.energy_resolution, json)); - WSContentSend_P(PSTR("
{e}")); // Last column is units ({e} =
{t}")); // {t} = - Define for next FUNC_WEB_SENSOR } } @@ -1184,10 +1206,10 @@ void SSPMEnergyShow(bool json) { \*********************************************************************************************/ const char kSSPMCommands[] PROGMEM = "SSPM|" // Prefix - "Log|Energy|History|Scan|IamHere" ; + "Log|Energy|History|Scan|IamHere|Display" ; void (* const SSPMCommand[])(void) PROGMEM = { - &CmndSSPMLog, &CmndSSPMEnergy, &CmndSSPMEnergyHistory, &CmndSSPMScan, &CmndSSPMIamHere }; + &CmndSSPMLog, &CmndSSPMEnergy, &CmndSSPMEnergyHistory, &CmndSSPMScan, &CmndSSPMIamHere, &CmndSSPMDisplay }; void CmndSSPMLog(void) { // Report 29 log entries @@ -1222,6 +1244,14 @@ void CmndSSPMIamHere(void) { ResponseCmndDone(); } +void CmndSSPMDisplay(void) { + // Select either all relays or only powered on relays + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Sspm->gui_display = XdrvMailbox.payload; + } + ResponseCmndNumber(Sspm->gui_display); +} + /*********************************************************************************************\ * Interface \*********************************************************************************************/ From bcbef695ce0a40fff12b1960552d1367f2164d2a Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sat, 4 Dec 2021 13:46:43 +0100 Subject: [PATCH 7/9] Berry sync with upstream --- lib/libesp32/Berry/src/be_class.c | 2 +- lib/libesp32/Berry/src/be_class.h | 2 +- lib/libesp32/Berry/src/be_jsonlib.c | 2 +- lib/libesp32/Berry/src/be_strlib.c | 1 - lib/libesp32/Berry/src/be_vm.c | 14 +++++++------- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/libesp32/Berry/src/be_class.c b/lib/libesp32/Berry/src/be_class.c index a960d4b24..c2042fd39 100644 --- a/lib/libesp32/Berry/src/be_class.c +++ b/lib/libesp32/Berry/src/be_class.c @@ -220,7 +220,7 @@ static binstance* newobject(bvm *vm, bclass *c) /* Instanciate new instance from stack with argc parameters */ /* Pushes the constructor on the stack to be executed if a construtor is found */ /* Returns true if a constructor is found */ -bbool be_class_newobj(bvm *vm, bclass *c, int32_t pos, int argc, int mode) +bbool be_class_newobj(bvm *vm, bclass *c, int pos, int argc, int mode) { bvalue init; binstance *obj = newobject(vm, c); /* create empty object hierarchy from class hierarchy */ diff --git a/lib/libesp32/Berry/src/be_class.h b/lib/libesp32/Berry/src/be_class.h index 59abbab30..405ea6d38 100644 --- a/lib/libesp32/Berry/src/be_class.h +++ b/lib/libesp32/Berry/src/be_class.h @@ -58,7 +58,7 @@ void be_prim_method_bind(bvm *vm, bclass *c, bstring *name, bntvfunc f); void be_closure_method_bind(bvm *vm, bclass *c, bstring *name, bclosure *cl); int be_class_closure_count(bclass *c); void be_class_upvalue_init(bvm *vm, bclass *c); -bbool be_class_newobj(bvm *vm, bclass *c, int32_t pos, int argc, int mode); +bbool be_class_newobj(bvm *vm, bclass *c, int pos, int argc, int mode); int be_instance_member_simple(bvm *vm, binstance *obj, bstring *name, bvalue *dst); int be_instance_member(bvm *vm, binstance *obj, bstring *name, bvalue *dst); int be_class_member(bvm *vm, bclass *obj, bstring *name, bvalue *dst); diff --git a/lib/libesp32/Berry/src/be_jsonlib.c b/lib/libesp32/Berry/src/be_jsonlib.c index 2ee2a4daa..1d7049ea1 100644 --- a/lib/libesp32/Berry/src/be_jsonlib.c +++ b/lib/libesp32/Berry/src/be_jsonlib.c @@ -54,7 +54,7 @@ static int is_object(bvm *vm, const char *class, int idx) } be_remove(vm, -2); } - const char *name = be_classname(vm, idx); + const char *name = be_classname(vm, -1); bbool ret = !strcmp(name, class); be_pop(vm, 1); return ret; diff --git a/lib/libesp32/Berry/src/be_strlib.c b/lib/libesp32/Berry/src/be_strlib.c index e82ec3cf2..53f35607b 100644 --- a/lib/libesp32/Berry/src/be_strlib.c +++ b/lib/libesp32/Berry/src/be_strlib.c @@ -330,7 +330,6 @@ static bstring* string_range(bvm *vm, bstring *str, binstance *range) { bint lower, upper; bint size = str_len(str); /* size of source string */ - // bint size = be_data_size(vm, -1); /* get source list size */ /* get index range */ bvalue temp; be_instance_member(vm, range, be_newstr(vm, "__lower__"), &temp); diff --git a/lib/libesp32/Berry/src/be_vm.c b/lib/libesp32/Berry/src/be_vm.c index dd60e34b7..67519ee39 100644 --- a/lib/libesp32/Berry/src/be_vm.c +++ b/lib/libesp32/Berry/src/be_vm.c @@ -142,7 +142,7 @@ _vm->cf->status = PRIM_FUNC; \ } -static void prep_closure(bvm *vm, int32_t pos, int argc, int mode); +static void prep_closure(bvm *vm, int pos, int argc, int mode); static void attribute_error(bvm *vm, const char *t, bvalue *b, bvalue *c) { @@ -1186,7 +1186,7 @@ newframe: /* a new call frame */ } } -static void prep_closure(bvm *vm, int32_t pos, int argc, int mode) +static void prep_closure(bvm *vm, int pos, int argc, int mode) { bvalue *v, *end; bproto *proto = var2cl(vm->reg + pos)->proto; @@ -1211,7 +1211,7 @@ static void prep_closure(bvm *vm, int32_t pos, int argc, int mode) } } -static void do_closure(bvm *vm, int32_t pos, int argc) +static void do_closure(bvm *vm, int pos, int argc) { // bvalue *v, *end; // bproto *proto = var2cl(reg)->proto; @@ -1225,7 +1225,7 @@ static void do_closure(bvm *vm, int32_t pos, int argc) vm_exec(vm); } -static void do_ntvclos(bvm *vm, int32_t pos, int argc) +static void do_ntvclos(bvm *vm, int pos, int argc) { bntvclos *f = var_toobj(vm->reg + pos); push_native(vm, vm->reg + pos, argc, 0); @@ -1233,7 +1233,7 @@ static void do_ntvclos(bvm *vm, int32_t pos, int argc) ret_native(vm); } -static void do_ntvfunc(bvm *vm, int32_t pos, int argc) +static void do_ntvfunc(bvm *vm, int pos, int argc) { bntvfunc f = var_tontvfunc(vm->reg + pos); push_native(vm, vm->reg + pos, argc, 0); @@ -1241,7 +1241,7 @@ static void do_ntvfunc(bvm *vm, int32_t pos, int argc) ret_native(vm); } -static void do_class(bvm *vm, int32_t pos, int argc) +static void do_class(bvm *vm, int pos, int argc) { if (be_class_newobj(vm, var_toobj(vm->reg + pos), pos, ++argc, 0)) { be_incrtop(vm); @@ -1254,7 +1254,7 @@ void be_dofunc(bvm *vm, bvalue *v, int argc) { be_assert(vm->reg <= v && v < vm->stacktop); be_assert(vm->stack <= vm->reg && vm->reg < vm->stacktop); - int32_t pos = v - vm->reg; + int pos = v - vm->reg; switch (var_type(v)) { case BE_CLASS: do_class(vm, pos, argc); break; case BE_CLOSURE: do_closure(vm, pos, argc); break; From 888cbb999d50fba71d3f81d058cd6cc83c1caba8 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sat, 4 Dec 2021 13:49:06 +0100 Subject: [PATCH 8/9] Rename be_map_release to be_map_compact --- lib/libesp32/Berry/src/be_api.c | 2 +- lib/libesp32/Berry/src/be_class.c | 2 +- lib/libesp32/Berry/src/be_map.c | 2 +- lib/libesp32/Berry/src/be_map.h | 2 +- lib/libesp32/Berry/src/be_module.c | 2 +- lib/libesp32/Berry/src/be_solidifylib.c | 2 +- lib/libesp32/Berry/src/be_var.c | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/libesp32/Berry/src/be_api.c b/lib/libesp32/Berry/src/be_api.c index d883c08d7..79d5c48ff 100644 --- a/lib/libesp32/Berry/src/be_api.c +++ b/lib/libesp32/Berry/src/be_api.c @@ -51,7 +51,7 @@ static void class_init(bvm *vm, bclass *c, const bnfuncinfo *lib) ++slib; } } - be_map_release(vm, c->members); /* clear space */ + be_map_compact(vm, c->members); /* clear space */ } } diff --git a/lib/libesp32/Berry/src/be_class.c b/lib/libesp32/Berry/src/be_class.c index c2042fd39..0f4efb3d5 100644 --- a/lib/libesp32/Berry/src/be_class.c +++ b/lib/libesp32/Berry/src/be_class.c @@ -40,7 +40,7 @@ bclass* be_newclass(bvm *vm, bstring *name, bclass *super) void be_class_compress(bvm *vm, bclass *c) { if (!gc_isconst(c) && c->members) { - be_map_release(vm, c->members); /* clear space */ + be_map_compact(vm, c->members); /* clear space */ } } diff --git a/lib/libesp32/Berry/src/be_map.c b/lib/libesp32/Berry/src/be_map.c index 004406f46..37f9efc62 100644 --- a/lib/libesp32/Berry/src/be_map.c +++ b/lib/libesp32/Berry/src/be_map.c @@ -343,7 +343,7 @@ bmapnode* be_map_val2node(bvalue *value) return (bmapnode *)((size_t)value - sizeof(bmapkey)); } -void be_map_release(bvm *vm, bmap *map) +void be_map_compact(bvm *vm, bmap *map) { (void)vm; if (!gc_isconst(map)) { diff --git a/lib/libesp32/Berry/src/be_map.h b/lib/libesp32/Berry/src/be_map.h index d632f0d0b..7ae76962c 100644 --- a/lib/libesp32/Berry/src/be_map.h +++ b/lib/libesp32/Berry/src/be_map.h @@ -56,6 +56,6 @@ bvalue* be_map_insertstr(bvm *vm, bmap *map, bstring *key, bvalue *value); void be_map_removestr(bvm *vm, bmap *map, bstring *key); bmapnode* be_map_next(bmap *map, bmapiter *iter); bmapnode* be_map_val2node(bvalue *value); -void be_map_release(bvm *vm, bmap *map); +void be_map_compact(bvm *vm, bmap *map); #endif diff --git a/lib/libesp32/Berry/src/be_module.c b/lib/libesp32/Berry/src/be_module.c index c661528a1..0256809af 100644 --- a/lib/libesp32/Berry/src/be_module.c +++ b/lib/libesp32/Berry/src/be_module.c @@ -99,7 +99,7 @@ static bmodule* new_module(bvm *vm, const bntvmodule *nm) obj->table = NULL; /* gc protection */ obj->table = be_map_new(vm); insert_attrs(vm, obj->table, nm); - be_map_release(vm, obj->table); /* clear space */ + be_map_compact(vm, obj->table); /* clear space */ be_stackpop(vm, 1); } return obj; diff --git a/lib/libesp32/Berry/src/be_solidifylib.c b/lib/libesp32/Berry/src/be_solidifylib.c index d8291b365..2b82b44fd 100644 --- a/lib/libesp32/Berry/src/be_solidifylib.c +++ b/lib/libesp32/Berry/src/be_solidifylib.c @@ -42,7 +42,7 @@ static void m_solidify_bvalue(bvm *vm, bvalue * value, const char *classname, co static void m_solidify_map(bvm *vm, bmap * map, const char *class_name) { // compact first - be_map_release(vm, map); + be_map_compact(vm, map); logfmt(" be_nested_map(%i,\n", map->count); diff --git a/lib/libesp32/Berry/src/be_var.c b/lib/libesp32/Berry/src/be_var.c index ebc70ecea..4fee144cd 100644 --- a/lib/libesp32/Berry/src/be_var.c +++ b/lib/libesp32/Berry/src/be_var.c @@ -87,7 +87,7 @@ bvalue* be_global_var(bvm *vm, int index) void be_global_release_space(bvm *vm) { - be_map_release(vm, global(vm).vtab); + be_map_compact(vm, global(vm).vtab); be_vector_release(vm, &global(vm).vlist); } @@ -130,7 +130,7 @@ int be_builtin_new(bvm *vm, bstring *name) void be_bulitin_release_space(bvm *vm) { - be_map_release(vm, builtin(vm).vtab); + be_map_compact(vm, builtin(vm).vtab); be_vector_release(vm, &builtin(vm).vlist); } #else From 2f9172a59f0dac19e09e805b033377378bb67797 Mon Sep 17 00:00:00 2001 From: Barbudor Date: Sat, 4 Dec 2021 15:03:15 +0100 Subject: [PATCH 9/9] fix pulsetime for more than 8 relays/power devices --- tasmota/support_tasmota.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index f3e4fe977..3129c2831 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -1043,7 +1043,7 @@ void Every100mSeconds(void) if (TasmotaGlobal.pulse_timer[i] != 0L) { // Timer active? if (TimeReached(TasmotaGlobal.pulse_timer[i])) { // Timer finished? TasmotaGlobal.pulse_timer[i] = 0L; // Turn off this timer - for (uint32_t j = 0; j < TasmotaGlobal.devices_present; j = j +MAX_PULSETIMERS) { + for (uint32_t j = 0; (i + j) < TasmotaGlobal.devices_present; j = j +MAX_PULSETIMERS) { ExecuteCommandPower(i + j +1, (POWER_ALL_OFF_PULSETIME_ON == Settings->poweronstate) ? POWER_ON : POWER_OFF, SRC_PULSETIMER); } }