diff --git a/CHANGELOG.md b/CHANGELOG.md index 45ce15fd8..7899108dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ All notable changes to this project will be documented in this file. - Support for Frysk language translations by Christiaan Heerze - ESP8266 Fallback to ``*.bin.gz`` binary when OTA upload of ``*.bin`` binary fails - Berry language improved Tasmota integration +- Filesystem commands ``Ufs``, ``UfsType``, ``UfsSize``, ``UfsFree``, ``UfsDelete`` and ``UfsRename`` +- Basic support for filesystem ``autoexec.bat`` ### Changed - IRremoteESP8266 library from v2.7.14 to v2.7.15 diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 175054b38..f68cf0a34 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -95,6 +95,8 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota - Commands ``ZbNameKey``, ``ZbDeviceTopic``, ``ZbNoPrefix``, ``ZbEndpointSuffix``, ``ZbNoAutoBind`` and ``ZbNameTopic`` as synonyms for ``SetOption83, 89, 100, 101, 110`` and ``112`` - Commands ``ZbNoAutoBind``, ``ZbReceivedTopic`` and ``ZbOmitDevice`` as synonyms for ``SetOption116, 118`` and ``119`` - Commands ``BuzzerActive`` and ``BuzzerPwm`` as synonyms for ``SetOption67`` and ``111`` +- Filesystem commands ``Ufs``, ``UfsType``, ``UfsSize``, ``UfsFree``, ``UfsDelete`` and ``UfsRename`` +- Basic support for filesystem ``autoexec.bat`` - Milliseconds to console output [#10152](https://github.com/arendst/Tasmota/issues/10152) - Gpio ``Option_a1`` enabling PWM2 high impedance if powered off as used by Wyze bulbs [#10196](https://github.com/arendst/Tasmota/issues/10196) - Rotary No Pullup GPIO selection ``Rotary A/B_n`` [#10407](https://github.com/arendst/Tasmota/issues/10407) diff --git a/lib/lib_display/Display_Renderer-gemu-1.0/library.properties b/lib/lib_display/Display_Renderer-gemu-1.0/library.properties index 29a16c0e7..7f8d6dc82 100644 --- a/lib/lib_display/Display_Renderer-gemu-1.0/library.properties +++ b/lib/lib_display/Display_Renderer-gemu-1.0/library.properties @@ -1,9 +1,9 @@ -name=Waveshare esp 2.9 inch e-paper display driver +name=Display renderer version=1.0 author=Gerhard Mutz maintainer=Gerhard Mutz -sentence=ESP8266 library for Waveshare e-paper display. +sentence=ESP8266 ESP32 library for Tasmota displays paragraph= category=Display -url=https://github.com/gemu2015/Sonoff-Tasmota/tree/displays/lib/esp-epaper-29-ws-20171230-gemu-1.0# +url=https://github.com/arendst/Tasmota architectures=* diff --git a/lib/lib_display/Epaper_29-gemu-1.0/library.properties b/lib/lib_display/Epaper_29-gemu-1.0/library.properties new file mode 100644 index 000000000..d6b5f57c6 --- /dev/null +++ b/lib/lib_display/Epaper_29-gemu-1.0/library.properties @@ -0,0 +1,9 @@ +name=Waveshare esp 2.9 inch e-paper display driver +version=1.0 +author=Gerhard Mutz +maintainer=Gerhard Mutz +sentence=ESP8266 ESP32 library for Waveshare 2.9 inch e-paper display +paragraph= +category=Display +url=https://github.com/arendst/Tasmota +architectures=* diff --git a/lib/lib_display/Epaper_42-gemu-1.0/library.properties b/lib/lib_display/Epaper_42-gemu-1.0/library.properties new file mode 100644 index 000000000..923da7925 --- /dev/null +++ b/lib/lib_display/Epaper_42-gemu-1.0/library.properties @@ -0,0 +1,9 @@ +name=Waveshare esp 4.2 inch e-paper display driver +version=1.0 +author=Gerhard Mutz +maintainer=Gerhard Mutz +sentence=ESP8266 ESP32 library for Waveshare e-paper display. +paragraph= +category=Display +url=https://github.com/arendst/Tasmota +architectures=* diff --git a/lib/lib_display/ILI9341-gemu-1.0/library.properties b/lib/lib_display/ILI9341-gemu-1.0/library.properties new file mode 100644 index 000000000..5373590b5 --- /dev/null +++ b/lib/lib_display/ILI9341-gemu-1.0/library.properties @@ -0,0 +1,9 @@ +name=ILI9341 +version=1.0.0 +author=Gerhard Mutz +maintainer=Gerhard Mutz +sentence=ILI9341 ESP8266 ESP32 display driver for Tasmota +paragraph=ILI9341 ESP8266 ESP32 display driver for Tasmota +category=Display +url=https://github.com/arendst/Tasmota +architectures=* diff --git a/lib/lib_display/Xlatb_RA8876-gemu-1.0/library.properties b/lib/lib_display/Xlatb_RA8876-gemu-1.0/library.properties index 6e478adf0..5eea15179 100644 --- a/lib/lib_display/Xlatb_RA8876-gemu-1.0/library.properties +++ b/lib/lib_display/Xlatb_RA8876-gemu-1.0/library.properties @@ -1,9 +1,9 @@ name=RA8876 -version=1.0.2 -author=Jaret Burkett -maintainer=Jaret Burkett -sentence=Library for RA8876 displays -paragraph=Library for RA8876 displays +version=1.0.0 +author=Jaret Burkett / Gerhard Mutz +maintainer=Gerhard Mutz +sentence=Tasmota Library for RA8876 displays +paragraph=Tasmota Library for RA8876 displays category=Display -url=https://github.com/jaretburkett/ILI9488 +url=https://github.com/arendst/Tasmota architectures=* diff --git a/lib/lib_div/ProcessControl/library.properties b/lib/lib_div/ProcessControl/library.properties new file mode 100644 index 000000000..bdfadee30 --- /dev/null +++ b/lib/lib_div/ProcessControl/library.properties @@ -0,0 +1,9 @@ +name=Process_control +version=1.0.0 +author=Colin Law +maintainer=Colin Law +sentence=C++ library of process control algorithms +paragraph=C++ library of process control algorithms +category=Heating +url=https://github.com/colinl/process-control.git +architectures=* \ No newline at end of file diff --git a/lib/lib_div/stm32flash-1.0-tasmota/library.properties b/lib/lib_div/stm32flash-1.0-tasmota/library.properties new file mode 100644 index 000000000..6161b02e1 --- /dev/null +++ b/lib/lib_div/stm32flash-1.0-tasmota/library.properties @@ -0,0 +1,9 @@ +name=stm32_flash +version=1.0.0 +author=Tormod Volden +maintainer=Tormod Volden +sentence=STM32 Flasher +paragraph=STM32 Flaher +category=Tools +url= +architectures=esp8266 \ No newline at end of file diff --git a/lib/libesp32/NimBLE-Arduino/library.json b/lib/libesp32/NimBLE-Arduino/library.json index 5eb6ec5b4..a64024df6 100644 --- a/lib/libesp32/NimBLE-Arduino/library.json +++ b/lib/libesp32/NimBLE-Arduino/library.json @@ -2,7 +2,7 @@ "name": "NimBLE-Arduino", "keywords": "esp32, bluetooth", "description": "Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE", - "version": "1.0.2", + "version": "1.1.0", "frameworks": "arduino", "platforms": "espressif32" } diff --git a/tasmota/support.ino b/tasmota/support.ino index 1b99b5cf1..0cb0daf5a 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -1667,6 +1667,92 @@ void TemplateJson(void) ResponseAppend_P(PSTR("],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"), Settings.user_template.flag, Settings.user_template_base +1); } +#if ( defined(USE_SCRIPT) && defined(SUPPORT_MQTT_EVENT) ) || defined (USE_DT_VARS) + +/*********************************************************************************************\ + * Parse json paylod with path +\*********************************************************************************************/ +// parser object, source keys, delimiter, float result or NULL, string result or NULL, string size +// return 1 if numeric 2 if string, else 0 = not found +uint32_t JsonParsePath(JsonParserObject *jobj, const char *spath, char delim, float *nres, char *sres, uint32_t slen) { + uint32_t res = 0; + const char *cp = spath; +#ifdef DEBUG_JSON_PARSE_PATH + AddLog(LOG_LEVEL_INFO, PSTR("JSON: parsing json key: %s from json: %s"), cp, jpath); +#endif + JsonParserObject obj = *jobj; + JsonParserObject lastobj = obj; + char selem[32]; + uint8_t aindex = 0; + String value = ""; + while (1) { + // read next element + for (uint32_t sp=0; sp Settings.param[P_BOOT_LOOP_OFFSET] +2) { // Restarted 4 times Settings.rule_enabled = 0; // Disable all rules + TasmotaGlobal.no_autoexec = true; } if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET] +3) { // Restarted 5 times for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) { diff --git a/tasmota/tasmota_globals.h b/tasmota/tasmota_globals.h index 2ac6a2343..9c05574d7 100644 --- a/tasmota/tasmota_globals.h +++ b/tasmota/tasmota_globals.h @@ -261,6 +261,8 @@ const uint16_t LOG_BUFFER_SIZE = 4000; // Max number of characters in lo #define TASM_FILE_DRIVER "/.drvset%03d" #define TASM_FILE_SENSOR "/.snsset%03d" #define TASM_FILE_ZIGBEE "/zb" // Zigbee settings blob as used by CC2530 on ESP32 +#define TASM_FILE_AUTOEXEC "/autoexec.bat" // Commands executed after restart +#define TASM_FILE_CONFIG "/config.sys" // Settings executed after restart #ifndef MQTT_MAX_PACKET_SIZE #define MQTT_MAX_PACKET_SIZE 1200 // Bytes diff --git a/tasmota/xdrv_03_energy.ino b/tasmota/xdrv_03_energy.ino index d63472a9d..822bb6401 100644 --- a/tasmota/xdrv_03_energy.ino +++ b/tasmota/xdrv_03_energy.ino @@ -501,7 +501,7 @@ void EnergyEverySecond(void) { // Overtemp check if (TasmotaGlobal.global_update) { - if (TasmotaGlobal.power && !isnan(TasmotaGlobal.temperature_celsius) && (TasmotaGlobal.temperature_celsius > (float)Settings.param[P_OVER_TEMP])) { // Device overtemp, turn off relays + if (TasmotaGlobal.power && !isnan(TasmotaGlobal.temperature_celsius) && (TasmotaGlobal.temperature_celsius > (float)Settings.param[P_OVER_TEMP])) { // SetOption42 Device overtemp, turn off relays AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: GlobTemp %1_f"), &TasmotaGlobal.temperature_celsius); diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index 330ddc13d..cc39a9af6 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -4326,14 +4326,13 @@ int16_t Run_script_sub(const char *type, int8_t tlen, struct GVARS *gv) { goto next_line; } #ifdef USE_SENDMAIL -/* - else if (!strncmp(lp, "sm", 2)) { - lp+=3; + else if (!strncmp(lp, "mail", 4)) { + lp+=5; char tmp[256]; Replace_Cmd_Vars(lp ,1 , tmp, sizeof(tmp)); SendMail(tmp); goto next_line; - }*/ + } #endif else if (!strncmp(lp,"=>",2) || !strncmp(lp,"->",2) || !strncmp(lp,"+>",2) || !strncmp(lp,"print",5)) { // execute cmd @@ -5819,14 +5818,14 @@ void dateTime(uint16_t* date, uint16_t* time) { #ifdef SUPPORT_MQTT_EVENT - +/* //#define DEBUG_MQTT_EVENT - +// parser object, source keys, delimiter, float result or NULL, string result or NULL, string size uint32_t JsonParsePath(JsonParserObject *jobj, const char *spath, char delim, float *nres, char *sres, uint32_t slen) { uint32_t res = 0; const char *cp = spath; -#ifdef DEBUG_MQTT_EVENT -// AddLog(LOG_LEVEL_INFO, PSTR("Script: parsing json key: %s from json: %s"), cp, jpath); +#ifdef DEBUG_JSON_PARSE_PATH + AddLog(LOG_LEVEL_INFO, PSTR("JSON: parsing json key: %s from json: %s"), cp, jpath); #endif JsonParserObject obj = *jobj; JsonParserObject lastobj = obj; @@ -5843,8 +5842,8 @@ uint32_t JsonParsePath(JsonParserObject *jobj, const char *spath, char delim, fl } selem[sp] = *cp++; } -#ifdef DEBUG_MQTT_EVENT - AddLog(LOG_LEVEL_INFO, PSTR("Script: cmp current key: %s"), selem); +#ifdef DEBUG_JSON_PARSE_PATH + AddLog(LOG_LEVEL_INFO, PSTR("JSON: cmp current key: %s"), selem); #endif // check for array char *sp = strchr(selem,'['); @@ -5856,8 +5855,8 @@ uint32_t JsonParsePath(JsonParserObject *jobj, const char *spath, char delim, fl // now check element obj = obj[selem]; if (!obj.isValid()) { -#ifdef DEBUG_MQTT_EVENT - AddLog(LOG_LEVEL_INFO, PSTR("Script: obj invalid: %s"), selem); +#ifdef DEBUG_JSON_PARSE_PATH + AddLog(LOG_LEVEL_INFO, PSTR("JSON: obj invalid: %s"), selem); #endif JsonParserToken tok = lastobj[selem]; if (tok.isValid()) { @@ -5881,8 +5880,8 @@ uint32_t JsonParsePath(JsonParserObject *jobj, const char *spath, char delim, fl } } -#ifdef DEBUG_MQTT_EVENT - AddLog(LOG_LEVEL_INFO, PSTR("Script: token invalid: %s"), selem); +#ifdef DEBUG_JSON_PARSE_PATH + AddLog(LOG_LEVEL_INFO, PSTR("JSON: token invalid: %s"), selem); #endif break; } @@ -5892,11 +5891,13 @@ uint32_t JsonParsePath(JsonParserObject *jobj, const char *spath, char delim, fl } if (!*cp) break; } - strlcpy(sres,value.c_str(),slen); + if (sres) { + strlcpy(sres,value.c_str(), slen); + } return res; } - +*/ #ifndef MQTT_EVENT_MSIZE #define MQTT_EVENT_MSIZE 256 #endif // MQTT_EVENT_MSIZE diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index e119c1117..06e1e82ea 100755 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -180,95 +180,6 @@ void DisplayClear(void) XdspCall(FUNC_DISPLAY_CLEAR); } -void DisplayDrawHLine(uint16_t x, uint16_t y, int16_t len, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_len = len; - dsp_color = color; - XdspCall(FUNC_DISPLAY_DRAW_HLINE); -} - -void DisplayDrawVLine(uint16_t x, uint16_t y, int16_t len, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_len = len; - dsp_color = color; - XdspCall(FUNC_DISPLAY_DRAW_VLINE); -} - -void DisplayDrawLine(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_x2 = x2; - dsp_y2 = y2; - dsp_color = color; - XdspCall(FUNC_DISPLAY_DRAW_LINE); -} - -void DisplayDrawCircle(uint16_t x, uint16_t y, uint16_t rad, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_rad = rad; - dsp_color = color; - XdspCall(FUNC_DISPLAY_DRAW_CIRCLE); -} - -void DisplayDrawFilledCircle(uint16_t x, uint16_t y, uint16_t rad, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_rad = rad; - dsp_color = color; - XdspCall(FUNC_DISPLAY_FILL_CIRCLE); -} - -void DisplayDrawRectangle(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_x2 = x2; - dsp_y2 = y2; - dsp_color = color; - XdspCall(FUNC_DISPLAY_DRAW_RECTANGLE); -} - -void DisplayDrawFilledRectangle(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color) -{ - dsp_x = x; - dsp_y = y; - dsp_x2 = x2; - dsp_y2 = y2; - dsp_color = color; - XdspCall(FUNC_DISPLAY_FILL_RECTANGLE); -} - -void DisplayDrawFrame(void) -{ - XdspCall(FUNC_DISPLAY_DRAW_FRAME); -} - -void DisplaySetSize(uint8_t size) -{ - Settings.display_size = size &3; - XdspCall(FUNC_DISPLAY_TEXT_SIZE); -} - -void DisplaySetFont(uint8_t font) -{ - Settings.display_font = font &3; - XdspCall(FUNC_DISPLAY_FONT_SIZE); -} - -void DisplaySetRotation(uint8_t rotation) -{ - Settings.display_rotate = rotation &3; - XdspCall(FUNC_DISPLAY_ROTATION); -} - void DisplayDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag) { dsp_x = x; @@ -559,10 +470,10 @@ void DisplayText(void) cp += var; if (temp < 0) { if (renderer) renderer->writeFastHLine(disp_xpos + temp, disp_ypos, -temp, fg_color); - else DisplayDrawHLine(disp_xpos + temp, disp_ypos, -temp, fg_color); + //else DisplayDrawHLine(disp_xpos + temp, disp_ypos, -temp, fg_color); } else { if (renderer) renderer->writeFastHLine(disp_xpos, disp_ypos, temp, fg_color); - else DisplayDrawHLine(disp_xpos, disp_ypos, temp, fg_color); + //else DisplayDrawHLine(disp_xpos, disp_ypos, temp, fg_color); } disp_xpos += temp; break; @@ -572,10 +483,10 @@ void DisplayText(void) cp += var; if (temp < 0) { if (renderer) renderer->writeFastVLine(disp_xpos, disp_ypos + temp, -temp, fg_color); - else DisplayDrawVLine(disp_xpos, disp_ypos + temp, -temp, fg_color); + //else DisplayDrawVLine(disp_xpos, disp_ypos + temp, -temp, fg_color); } else { if (renderer) renderer->writeFastVLine(disp_xpos, disp_ypos, temp, fg_color); - else DisplayDrawVLine(disp_xpos, disp_ypos, temp, fg_color); + //else DisplayDrawVLine(disp_xpos, disp_ypos, temp, fg_color); } disp_ypos += temp; break; @@ -587,7 +498,7 @@ void DisplayText(void) var = atoiv(cp, &temp1); cp += var; if (renderer) renderer->writeLine(disp_xpos, disp_ypos, temp, temp1, fg_color); - else DisplayDrawLine(disp_xpos, disp_ypos, temp, temp1, fg_color); + //else DisplayDrawLine(disp_xpos, disp_ypos, temp, temp1, fg_color); disp_xpos += temp; disp_ypos += temp1; break; @@ -596,14 +507,14 @@ void DisplayText(void) var = atoiv(cp, &temp); cp += var; if (renderer) renderer->drawCircle(disp_xpos, disp_ypos, temp, fg_color); - else DisplayDrawCircle(disp_xpos, disp_ypos, temp, fg_color); + //else DisplayDrawCircle(disp_xpos, disp_ypos, temp, fg_color); break; case 'K': // filled circle var = atoiv(cp, &temp); cp += var; if (renderer) renderer->fillCircle(disp_xpos, disp_ypos, temp, fg_color); - else DisplayDrawFilledCircle(disp_xpos, disp_ypos, temp, fg_color); + //else DisplayDrawFilledCircle(disp_xpos, disp_ypos, temp, fg_color); break; case 'r': // rectangle @@ -613,7 +524,7 @@ void DisplayText(void) var = atoiv(cp, &temp1); cp += var; if (renderer) renderer->drawRect(disp_xpos, disp_ypos, temp, temp1, fg_color); - else DisplayDrawRectangle(disp_xpos, disp_ypos, temp, temp1, fg_color); + //else DisplayDrawRectangle(disp_xpos, disp_ypos, temp, temp1, fg_color); break; case 'R': // filled rectangle @@ -623,7 +534,7 @@ void DisplayText(void) var = atoiv(cp, &temp1); cp += var; if (renderer) renderer->fillRect(disp_xpos, disp_ypos, temp, temp1, fg_color); - else DisplayDrawFilledRectangle(disp_xpos, disp_ypos, temp, temp1, fg_color); + //else DisplayDrawFilledRectangle(disp_xpos, disp_ypos, temp, temp1, fg_color); break; case 'u': // rounded rectangle @@ -696,9 +607,49 @@ void DisplayText(void) index_colors[temp] = ftemp; break; } +#ifdef USE_DT_VARS + if (*cp == 'v') { + cp++; + { int16_t num, gxp, gyp, textbcol, textfcol, font, textsize, txlen, dp; + var=atoiv(cp,&num); + cp+=var; + cp++; + var=atoiv(cp,&gxp); + cp+=var; + cp++; + var=atoiv(cp,&gyp); + cp+=var; + cp++; + var=atoiv(cp,&textbcol); + cp+=var; + cp++; + var=atoiv(cp,&textfcol); + cp+=var; + cp++; + var=atoiv(cp,&font); + cp+=var; + cp++; + var=atoiv(cp,&textsize); + cp+=var; + cp++; + var=atoiv(cp,&txlen); + cp+=var; + cp++; + var=atoiv(cp,&dp); + cp+=var; + cp++; + // text itself + char bbuff[32]; + cp = get_string(bbuff, sizeof(bbuff), cp); + char unit[4]; + cp = get_string(unit, sizeof(unit), cp); + define_dt_var(num, gxp, gyp, textbcol, textfcol, font, textsize, txlen, dp, bbuff, unit); + } + } +#endif // USE_DT_VARS // force draw grafics buffer if (renderer) renderer->Updateframe(); - else DisplayDrawFrame(); + //else DisplayDrawFrame(); break; case 'D': // set auto draw mode @@ -709,18 +660,18 @@ void DisplayText(void) case 's': // size sx if (renderer) renderer->setTextSize(*cp&7); - else DisplaySetSize(*cp&3); + //else DisplaySetSize(*cp&3); cp += 1; break; case 'f': // font sx { uint8_t font = *cp&7; if (renderer) renderer->setTextFont(font); - else DisplaySetFont(font); + //else DisplaySetFont(font); if (font) { // for backward compatibility set size to 1 on non GFX fonts if (renderer) renderer->setTextSize(1); - else DisplaySetSize(1); + //else DisplaySetSize(1); } cp += 1; } @@ -728,7 +679,7 @@ void DisplayText(void) case 'a': // rotation angle if (renderer) renderer->setRotation(*cp&3); - else DisplaySetRotation(*cp&3); + //else DisplaySetRotation(*cp&3); cp+=1; break; @@ -976,7 +927,7 @@ void DisplayText(void) // draw buffer if (auto_draw&1) { if (renderer) renderer->Updateframe(); - else DisplayDrawFrame(); + //else DisplayDrawFrame(); } } @@ -1019,6 +970,167 @@ void Display_Text_From_File(const char *file) { } #endif + +#ifdef USE_DT_VARS + +#ifndef MAX_DT_VARS +#define MAX_DT_VARS 8 +#endif // MAX_DT_VARS + +#define MAX_DVTSIZE 24 + +typedef struct { + uint16_t xp; + uint16_t yp; + uint8_t txtbcol; + uint8_t txtfcol; + int8_t txtsiz; + int8_t txtlen; + int8_t dp; + int8_t font; + char unit[6]; + char *jstrbuf; + char rstr[32]; +} DT_VARS; + +DT_VARS *dt_vars[MAX_DT_VARS]; + +void define_dt_var(uint32_t num, uint32_t xp, uint32_t yp, uint32_t txtbcol, uint32_t txtfcol, int32_t font, int32_t txtsiz, int32_t txtlen, int32_t dp, char *jstr, char *unit) { + if (num >= MAX_DT_VARS) return; + + if (dt_vars[num]) { + if (dt_vars[num]->jstrbuf) free(dt_vars[num]->jstrbuf); + free(dt_vars[num]); + } + //dt [dv0:100:100:0:3:2:1:10:2:WLAN#ID:uV:] + + DT_VARS *dtp = (DT_VARS*)malloc(sizeof(DT_VARS)); + if (!dtp) return; + + dt_vars[num] = dtp; + + dtp->xp = xp; + dtp->yp = yp; + dtp->txtbcol = txtbcol; + dtp->txtfcol = txtfcol; + dtp->font = font; + dtp->txtsiz = txtsiz; + if (txtlen > MAX_DVTSIZE) {txtlen = MAX_DVTSIZE;} + dtp->txtlen = txtlen; + dtp->dp = dp; + dtp->jstrbuf = (char*)malloc(strlen(jstr + 1)); + if (!dtp->jstrbuf) { + free (dtp); + return; + } + strcpy(dtp->jstrbuf, jstr); + strcpy(dtp->unit,unit); +} + +void draw_dt_vars(void) { + if (!renderer) return; + + for (uint32_t cnt = 0; cnt < MAX_DT_VARS; cnt++) { + if (dt_vars[cnt]) { + if (dt_vars[cnt]->jstrbuf) { + // draw + char vstr[MAX_DVTSIZE + 7]; + memset(vstr, ' ', sizeof(vstr)); + strcpy(vstr, dt_vars[cnt]->rstr); + strcat(vstr, " "); + strcat(vstr, dt_vars[cnt]->unit); + uint16_t slen = strlen(vstr); + vstr[slen] = ' '; + + if (!dt_vars[cnt]->txtlen) { + vstr[slen] = 0; + } else { + vstr[abs(int(dt_vars[cnt]->txtlen))] = 0; + } + if (dt_vars[cnt]->txtlen < 0) { + // right align + alignright(vstr); + } + + if (dt_vars[cnt]->txtsiz > 0) { + renderer->setDrawMode(0); + } else { + renderer->setDrawMode(2); + } + renderer->setTextColor(GetColorFromIndex(dt_vars[cnt]->txtfcol),GetColorFromIndex(dt_vars[cnt]->txtbcol)); + renderer->setTextFont(dt_vars[cnt]->font); + renderer->setTextSize(abs(dt_vars[cnt]->txtsiz)); + renderer->DrawStringAt(dt_vars[cnt]->xp, dt_vars[cnt]->yp, vstr, GetColorFromIndex(dt_vars[cnt]->txtfcol), 0); + + // reset display vars + renderer->setTextColor(fg_color, bg_color); + renderer->setDrawMode(auto_draw); + } + } + } +} + +#define DTV_JSON_SIZE 1024 + +void DTVarsTeleperiod(void) { + char *json = (char*)malloc(DTV_JSON_SIZE); + if (json) { + strlcpy(json, TasmotaGlobal.mqtt_data, DTV_JSON_SIZE); + get_dt_vars(json); + free(json); + } +} + +void get_dt_mqtt(void) { + ResponseClear(); + uint16_t script_tele_period_save = TasmotaGlobal.tele_period; + TasmotaGlobal.tele_period = 2; + XsnsNextCall(FUNC_JSON_APPEND, script_xsns_index); + TasmotaGlobal.tele_period = script_tele_period_save; + if (strlen(TasmotaGlobal.mqtt_data)) { + TasmotaGlobal.mqtt_data[0] = '{'; + snprintf_P(TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("%s}"), TasmotaGlobal.mqtt_data); + } + get_dt_vars(TasmotaGlobal.mqtt_data); +} + +void get_dt_vars(char *json) { + if (strlen(json)) { + JsonParser parser(json); + JsonParserObject obj = parser.getRootObject(); + + for (uint32_t cnt = 0; cnt < MAX_DT_VARS; cnt++) { + if (dt_vars[cnt]) { + if (dt_vars[cnt]->jstrbuf) { + char sbuf[32]; + uint32_t res = JsonParsePath(&obj, dt_vars[cnt]->jstrbuf, '#', NULL, sbuf, sizeof(sbuf)); + if (res) { + if (dt_vars[cnt]->dp < 0) { + // use string + strcpy(dt_vars[cnt]->rstr, sbuf); + } else { + // convert back and forth + dtostrfd(CharToFloat(sbuf), dt_vars[cnt]->dp, dt_vars[cnt]->rstr); + } + } + } + } + } + } +} + +void free_dt_vars(void) { + for (uint32_t cnt = 0; cnt < MAX_DT_VARS; cnt++) { + if (dt_vars[cnt]) { + if (dt_vars[cnt]->jstrbuf) free(dt_vars[cnt]->jstrbuf); + free(dt_vars[cnt]); + dt_vars[cnt] = 0; + } + } +} + +#endif // USE_DT_VARS + /*********************************************************************************************/ #ifdef USE_DISPLAY_MODES1TO5 @@ -1423,6 +1535,10 @@ void DisplayInitDriver(void) Display_Text_From_File("/display.ini"); #endif +#ifdef USE_DT_VARS + free_dt_vars(); +#endif + // AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "Display model %d"), Settings.display_model); if (Settings.display_model) { @@ -1688,7 +1804,7 @@ void CmndDisplaySize(void) if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 4)) { Settings.display_size = XdrvMailbox.payload; if (renderer) renderer->setTextSize(Settings.display_size); - else DisplaySetSize(Settings.display_size); + //else DisplaySetSize(Settings.display_size); } ResponseCmndNumber(Settings.display_size); } @@ -1698,7 +1814,7 @@ void CmndDisplayFont(void) if ((XdrvMailbox.payload >=0) && (XdrvMailbox.payload <= 4)) { Settings.display_font = XdrvMailbox.payload; if (renderer) renderer->setTextFont(Settings.display_font); - else DisplaySetFont(Settings.display_font); + //else DisplaySetFont(Settings.display_font); } ResponseCmndNumber(Settings.display_font); } @@ -2547,9 +2663,7 @@ bool Xdrv13(uint8_t function) case FUNC_PRE_INIT: DisplayInitDriver(); #ifdef USE_GRAPH - for (uint8_t count=0;countrename(fname1, fname2)) { + AddLog(LOG_LEVEL_INFO, PSTR("TFS: Rename failed")); + return false; + } + return true; +} + +/*********************************************************************************************\ + * Autoexec support +\*********************************************************************************************/ + +void UfsAutoexec(void) { + if (!ffs_type) { return; } + File file = ffsp->open(TASM_FILE_AUTOEXEC, "r"); + if (!file) { return; } + + char cmd_line[512]; + while (file.available()) { + uint16_t index = 0; + while (file.available()) { + uint8_t buf[1]; + file.read(buf, 1); + if ((buf[0] == '\n') || (buf[0] == '\r')) { + // Line terminated with linefeed or carriage return + if (index < sizeof(cmd_line) - 1) { + // Process line + break; + } else { + // Discard too long line and start with next line + index = 0; + } + } + else if ((0 == index) && isspace(buf[0])) { + // Skip leading spaces (' ','\t','\n','\v','\f','\r') + } + else if (index < sizeof(cmd_line) - 2) { + cmd_line[index++] = buf[0]; + } + } + if ((index > 0) && (cmd_line[0] != ';')) { // Information but no comment + cmd_line[index] = 0; + ExecuteCommand(cmd_line, SRC_AUTOEXEC); + } + delay(0); + } + + file.close(); +} + /*********************************************************************************************\ * Commands \*********************************************************************************************/ const char kUFSCommands[] PROGMEM = "Ufs|" // Prefix - "|Type|Size|Free|Delete"; + "|Type|Size|Free|Delete|Rename"; void (* const kUFSCommand[])(void) PROGMEM = { - &UFSInfo, &UFSType, &UFSSize, &UFSFree, &UFSDelete}; + &UFSInfo, &UFSType, &UFSSize, &UFSFree, &UFSDelete, &UFSRename}; void UFSInfo(void) { Response_P(PSTR("{\"Ufs\":{\"Type\":%d,\"Size\":%d,\"Free\":%d}"), ufs_type, UfsInfo(0, 0), UfsInfo(1, 0)); @@ -392,11 +448,32 @@ void UFSDelete(void) { } } +void UFSRename(void) { + // UfsRename sdcard or flashfs file if only one of them available + // UfsRename2 flashfs file if available + if (XdrvMailbox.data_len > 0) { + bool result = false; + const char *fname1 = strtok(XdrvMailbox.data, ","); + const char *fname2 = strtok(nullptr, ","); + if (fname1 && fname2) { + if (ffs_type && (ffs_type != ufs_type) && (2 == XdrvMailbox.index)) { + result = TfsRenameFile(fname1, fname2); + } else { + result = (ufs_type && ufsp->rename(fname1, fname2)); + } + } + if (!result) { + ResponseCmndChar(PSTR(D_JSON_FAILED)); + } else { + ResponseCmndDone(); + } + } +} + /*********************************************************************************************\ * Web support \*********************************************************************************************/ - #ifdef USE_WEBSERVER const char UFS_WEB_DIR[] PROGMEM = @@ -654,12 +731,12 @@ uint8_t UfsDownloadFile(char *file) { #ifdef ESP32_DOWNLOAD_TASK download_file.close(); - if (download_busy == true) { + if (UfsData.download_busy == true) { AddLog(LOG_LEVEL_INFO, PSTR("UFS: Download is busy")); return 0; } - download_busy = true; + UfsData.download_busy = true; char *path = (char*)malloc(128); strcpy(path,file); xTaskCreatePinnedToCore(donload_task, "DT", 6000, (void*)path, 3, NULL, 1); @@ -710,7 +787,7 @@ void donload_task(void *path) { } download_file.close(); download_Client.stop(); - download_busy = false; + UfsData.download_busy = false; vTaskDelete( NULL ); } #endif // ESP32_DOWNLOAD_TASK @@ -752,6 +829,17 @@ bool Xdrv50(uint8_t function) { UfsCheckSDCardInit(); break; #endif // USE_SDCARD + case FUNC_EVERY_SECOND: + if (UfsData.autoexec) { + // Safe to execute autoexec commands here + UfsData.autoexec = false; + if (!TasmotaGlobal.no_autoexec) { UfsAutoexec(); } + } + break; + case FUNC_MQTT_INIT: + // Do not execute autoexec commands here + UfsData.autoexec = true; + break; case FUNC_COMMAND: result = DecodeCommand(kUFSCommands, kUFSCommand); break;