diff --git a/.gitignore b/.gitignore index 503ccf780..53c8da544 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,13 @@ ## OS specific ######## .DS_Store .fuse_hidden* + +## Compilation artefacts ######## *.pyc +*.d +*.o +*.gcno +*.gcda ## Project files ###### .platformio diff --git a/CHANGELOG.md b/CHANGELOG.md index f6baaaa56..1608a6987 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ All notable changes to this project will be documented in this file. - Berry add ``gpio`` module - Berry add ``light`` module - Support for dummy energy monitor using user values set by commands ``VoltageSet``, ``CurrentSet``, ``PowerSet`` and ``FrequencySet``. Enable by selecting any GPIO as ``Option A2`` (#10640) +- Command ``Backlog0`` to allow execution of following commands without delay +- Tasmota discovery as alternative to Home Assistant discovery using define ``USE_TASMOTA_DISCOVERY`` ### Changed - PubSubClient library from EspEasy v2.7.12 to Tasmota v2.8.12 @@ -25,6 +27,7 @@ All notable changes to this project will be documented in this file. - Limit number of relay/button columns in GUI to 8 (#11546) - ADC range result from int to float using command ``FreqRes`` for decimal resolution selection (#11545) - Teleinfo, if raw mode selected also return telemety values in SENSOR data +- Removed overtemp detection on external energy monitoring devices (#11628) ### Fixed - HC-SR04 on ESP32 release serial interface if not used (#11507) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 55c397eac..f61d91dcb 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -83,6 +83,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota - Command ``Sensor80 1 <0..7>`` to control MFRC522 RFID antenna gain from 18dB (0) to 48dB (7) [#11073](https://github.com/arendst/Tasmota/issues/11073) - Command ``SerialBuffer 256..520`` to change hardware serial receive buffer size from default (256) to max local buffer size (520) [#11448](https://github.com/arendst/Tasmota/issues/11448) - Command ``SetOption126 1`` to enable DS18x20 arithmetic mean over teleperiod for JSON temperature based on [#11472](https://github.com/arendst/Tasmota/issues/11472) +- Command ``Backlog0`` to allow execution of following commands without delay - Commands ``MqttKeepAlive 1..100`` to set Mqtt Keep Alive timer (default 30) and ``MqttTimeout 1..100`` to set Mqtt Socket Timeout (default 4) [#5341](https://github.com/arendst/Tasmota/issues/5341) - Commands ``DisplayType`` to select sub-modules where implemented and ``DisplayInvert`` to select inverted display where implemented - Support for SML VBUS [#11125](https://github.com/arendst/Tasmota/issues/11125) @@ -103,6 +104,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota - ESP32 support for WS2812 hardware driver via RMT or I2S - ESP32 support for secondary I2C controller - ESP32 support for internal Hall Effect sensor connected to both GPIO36 and GPIO39 only +- Tasmota discovery as alternative to Home Assistant discovery using define ``USE_TASMOTA_DISCOVERY`` ### Changed - TasmotaSerial library from v3.2.0 to v3.3.0 @@ -114,6 +116,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota - DeepSleep announcement topic [#11223](https://github.com/arendst/Tasmota/issues/11223) - Limit number of relay/button columns in GUI to 8 [#11546](https://github.com/arendst/Tasmota/issues/11546) - ADC range result from int to float using command ``FreqRes`` for decimal resolution selection [#11545](https://github.com/arendst/Tasmota/issues/11545) +- Removed overtemp detection on external energy monitoring devices [#11628](https://github.com/arendst/Tasmota/issues/11628) ### Fixed - PN532 on ESP32 Serial flush both Tx and Rx buffers [#10910](https://github.com/arendst/Tasmota/issues/10910) diff --git a/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.cpp b/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.cpp index dbfd00e2d..5e88150cc 100644 --- a/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.cpp +++ b/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.cpp @@ -1243,6 +1243,16 @@ void Adafruit_GFX::setTextSize(uint8_t s_x, uint8_t s_y) { textsize_y = (s_y > 0) ? s_y : 1; } +void Adafruit_GFX::setwidth(uint16_t w) { + WIDTH = w; + _width = w; +} + +void Adafruit_GFX::setheight(uint16_t h) { + HEIGHT = h; + _height = h; +} + /**************************************************************************/ /*! @brief Set rotation setting for display diff --git a/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.h b/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.h index dc970b26d..8af31324e 100644 --- a/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.h +++ b/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.h @@ -187,6 +187,10 @@ virtual void /************************************************************************/ int16_t height(void) const { return _height; } + void setwidth(uint16_t w); + + void setheight(uint16_t h); + /************************************************************************/ /*! @brief Get rotation setting for display diff --git a/lib/lib_display/UDisplay/keywords.txt b/lib/lib_display/UDisplay/keywords.txt new file mode 100644 index 000000000..bb1efcdcc --- /dev/null +++ b/lib/lib_display/UDisplay/keywords.txt @@ -0,0 +1,30 @@ +####################################### +# Syntax Coloring Map +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +ST7789 KEYWORD1 + + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +setRotation KEYWORD2 +setAddrWindow KEYWORD2 +pushColor KEYWORD2 +drawPixel KEYWORD2 +drawFastVLine KEYWORD2 +drawFastHLine KEYWORD2 +fillRect KEYWORD2 +setRotation KEYWORD2 +setRotation KEYWORD2 +height KEYWORD2 +width KEYWORD2 +invertDisplay KEYWORD2 +drawImage KEYWORD2 +setScrollArea KEYWORD2 +scroll KEYWORD2 diff --git a/lib/lib_display/UDisplay/library.properties b/lib/lib_display/UDisplay/library.properties new file mode 100644 index 000000000..c7dd23a3a --- /dev/null +++ b/lib/lib_display/UDisplay/library.properties @@ -0,0 +1,9 @@ +name=universal display Library +version=0.1 +author=Gerhard Mutz +maintainer=Gerhard Mutz +sentence=This is a library a couple of displays. +paragraph=This is a library a couple of displays. +category=Display +url=https://github.com/arendst/Tasmota +architectures=* diff --git a/lib/lib_display/UDisplay/uDisplay.cpp b/lib/lib_display/UDisplay/uDisplay.cpp new file mode 100644 index 000000000..0c15c8712 --- /dev/null +++ b/lib/lib_display/UDisplay/uDisplay.cpp @@ -0,0 +1,607 @@ +/* + uDisplay.cpp - universal display driver support for Tasmota + + Copyright (C) 2021 Gerhard Mutz and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include "uDisplay.h" + + +const uint16_t udisp_colors[]={UDISP_BLACK,UDISP_WHITE,UDISP_RED,UDISP_GREEN,UDISP_BLUE,UDISP_CYAN,UDISP_MAGENTA,\ + UDISP_YELLOW,UDISP_NAVY,UDISP_DARKGREEN,UDISP_DARKCYAN,UDISP_MAROON,UDISP_PURPLE,UDISP_OLIVE,\ +UDISP_LIGHTGREY,UDISP_DARKGREY,UDISP_ORANGE,UDISP_GREENYELLOW,UDISP_PINK}; + +uint16_t uDisplay::GetColorFromIndex(uint8_t index) { + if (index >= sizeof(udisp_colors) / 2) index = 0; + return udisp_colors[index]; +} + +extern uint8_t *buffer; + +uDisplay::uDisplay(char *lp) : Renderer(800, 600) { + // analyse decriptor + uint8_t section = 0; + dsp_ncmds = 0; + char linebuff[128]; + while (*lp) { + + uint16_t llen = strlen_ln(lp); + strncpy(linebuff, lp, llen); + linebuff[llen] = 0; + lp += llen; + char *lp1 = linebuff; + + if (*lp1 == '#') break; + if (*lp1 == '\n') lp1++; + while (*lp1 == ' ') lp1++; + //Serial.printf(">> %s\n",lp1); + if (*lp1 != ';') { + // check ids: + if (*lp1 == ':') { + // id line + lp1++; + section = *lp1++; + } else { + switch (section) { + case 'H': + // header line + // SD1306,128,64,1,I2C,5a,*,*,* + str2c(&lp1, dname, sizeof(dname)); + char ibuff[16]; + gxs = next_val(&lp1); + setwidth(gxs); + gys = next_val(&lp1); + setheight(gys); + bpp = next_val(&lp1); + str2c(&lp1, ibuff, sizeof(ibuff)); + if (!strncmp(ibuff, "I2C", 3)) { + interface = _UDSP_I2C; + i2caddr = next_hex(&lp1); + i2c_scl = next_val(&lp1); + i2c_sda = next_val(&lp1); + reset = next_val(&lp1); + section = 0; + } else if (!strncmp(ibuff, "SPI", 3)) { + interface = _UDSP_SPI; + spi_nr = next_val(&lp1); + spi_cs = next_val(&lp1); + spi_clk = next_val(&lp1); + spi_mosi = next_val(&lp1); + spi_dc = next_val(&lp1); + bpanel = next_val(&lp1); + reset = next_val(&lp1); + spi_miso = next_val(&lp1); + spi_speed = next_val(&lp1); + + section = 0; + Serial.printf("%d %d %d %d %d %d %d %d\n", spi_cs, spi_clk, spi_mosi, spi_dc, bpanel, reset, spi_miso, spi_speed); + } + break; + case 'S': + splash_font = next_val(&lp1); + splash_size = next_val(&lp1); + fg_col = next_val(&lp1); + if (bpp == 16) { + fg_col = GetColorFromIndex(fg_col); + } + bg_col = next_val(&lp1); + if (bpp == 16) { + bg_col = GetColorFromIndex(bg_col); + } + splash_xp = next_val(&lp1); + splash_yp = next_val(&lp1); + break; + case 'I': + // init data + if (interface == _UDSP_I2C) { + dsp_cmds[dsp_ncmds++] = next_hex(&lp1); + if (!str2c(&lp1, ibuff, sizeof(ibuff))) { + dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16); + } + } else { + while (1) { + if (!str2c(&lp1, ibuff, sizeof(ibuff))) { + dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16); + } else { + break; + } + if (dsp_ncmds >= sizeof(dsp_cmds)) break; + + } + } + break; + case 'o': + str2c(&lp1, ibuff, sizeof(ibuff)); + dsp_off = strtol(ibuff, 0, 16); + break; + case 'O': + str2c(&lp1, ibuff, sizeof(ibuff)); + dsp_on = strtol(ibuff, 0, 16); + break; + case '0': + rot_0 = next_hex(&lp1); + break; + case '1': + rot_1 = next_hex(&lp1); + break; + case '2': + rot_2 = next_hex(&lp1); + break; + case '3': + rot_3 = next_hex(&lp1); + break; + case 'A': + saw_1 = next_hex(&lp1); + saw_2 = next_hex(&lp1); + saw_3 = next_hex(&lp1); + break; + } + } + } + if (*lp == '\n') { + lp++; + } else { + lp = strchr(lp, '\n'); + if (!lp) break; + lp++; + } + } +} + + +Renderer *uDisplay::Init(void) { + + + if (reset >= 0) { + pinMode(reset, OUTPUT); + digitalWrite(reset, HIGH); + delay(50); + digitalWrite(reset, LOW); + delay(50); + digitalWrite(reset, HIGH); + delay(200); + } + + if (interface == _UDSP_I2C) { + Wire.begin(i2c_sda, i2c_scl); + if (bpp < 16) { + if (buffer) free(buffer); + buffer = (uint8_t*)calloc((width()*height()*bpp)/8, 1); + + for (uint32_t cnt = 0; cnt < dsp_ncmds; cnt++) { + i2c_command(dsp_cmds[cnt]); + } + } + } + if (interface == _UDSP_SPI) { + if (bpanel >= 0) { +#ifdef ESP32 + ledcSetup(ESP32_PWM_CHANNEL, 4000, 8); + ledcAttachPin(bpanel, ESP32_PWM_CHANNEL); + ledcWrite(ESP32_PWM_CHANNEL, 128); +#else + pinMode(bpanel, OUTPUT); + digitalWrite(bpanel, HIGH); +#endif // ESP32 + } + if (spi_dc >= 0) { + pinMode(spi_dc, OUTPUT); + digitalWrite(spi_dc, HIGH); + } + if (spi_cs >= 0) { + pinMode(spi_cs, OUTPUT); + digitalWrite(spi_cs, HIGH); + } + + spiSettings = SPISettings(spi_speed, MSBFIRST, SPI_MODE3); + +#ifdef ESP8266 + SPI.begin(); + uspi = &SPI; +#else + if (spi_nr != 1) { + uspi = new SPIClass(HSPI); + } else { + uspi = &SPI; + } + uspi->begin(spi_clk, spi_miso, spi_mosi, -1); +#endif + + uint16_t index = 0; + + SPI_BEGIN_TRANSACTION + while (1) { + uint8_t iob; + SPI_CS_LOW + SPI_DC_LOW + iob = dsp_cmds[index++]; + uspi->write(iob); + SPI_DC_HIGH + uint8_t args = dsp_cmds[index++]; + //Serial.printf("cmd, args %x, %d ", iob, args&0x7f); + for (uint32_t cnt = 0; cnt < (args & 0x7f); cnt++) { + iob = dsp_cmds[index++]; + //Serial.printf("%02x ", iob ); + uspi->write(iob); + } + SPI_CS_HIGH + //Serial.printf("\n"); + if (args & 0x80) delay(120); + if (index >= dsp_ncmds) break; + } + SPI_END_TRANSACTION + + } + return this; +} + +void uDisplay::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { + setRotation(rot); + invertDisplay(false); + setTextWrap(false); + cp437(true); + setTextFont(font); + setTextSize(size); + setTextColor(fg_col, bg_col); + setCursor(0,0); + fillScreen(bg_col); + Updateframe(); +} + +void uDisplay::spi_command(uint8_t val) { + SPI_BEGIN_TRANSACTION + SPI_DC_LOW + SPI_CS_LOW + uspi->write(val); + SPI_CS_HIGH + SPI_DC_HIGH + SPI_END_TRANSACTION +} + +void uDisplay::i2c_command(uint8_t val) { + //Serial.printf("%02x\n",val ); + Wire.beginTransmission(i2caddr); + Wire.write(0); + Wire.write(val); + Wire.endTransmission(); +} + +#define SH1106_SETLOWCOLUMN 0 +#define SH1106_SETHIGHCOLUMN 0x10 +#define SH1106_SETSTARTLINE 0x40 + + +void uDisplay::Updateframe(void) { + + if (interface == _UDSP_I2C) { + i2c_command(SH1106_SETLOWCOLUMN | 0x0); // low col = 0 + i2c_command(SH1106_SETHIGHCOLUMN | 0x0); // hi col = 0 + i2c_command(SH1106_SETSTARTLINE | 0x0); // line #0 + + uint8_t ys = gys >> 3; + uint8_t xs = gxs >> 3; + //uint8_t xs = 132 >> 3; + uint8_t m_row = 0; + uint8_t m_col = 2; + + uint16_t p = 0; + + uint8_t i, j, k = 0; + + for ( i = 0; i < ys; i++) { + // send a bunch of data in one xmission + i2c_command(0xB0 + i + m_row);//set page address + i2c_command(m_col & 0xf);//set lower column address + i2c_command(0x10 | (m_col >> 4));//set higher column address + + for( j = 0; j < 8; j++){ + Wire.beginTransmission(i2caddr); + Wire.write(0x40); + for ( k = 0; k < xs; k++, p++) { + Wire.write(buffer[p]); + } + Wire.endTransmission(); + } + } + } +} + +void uDisplay::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { + + if (interface != _UDSP_SPI) { + Renderer::drawFastVLine(x, y, h, color); + return; + } + // Rudimentary clipping + if ((x >= _width) || (y >= _height)) return; + if ((y + h - 1) >= _height) h = _height - y; + + SPI_BEGIN_TRANSACTION + + SPI_CS_LOW + + setAddrWindow_int(x, y, 1, h); + + while (h--) { + uspi->write16(color); + } + + SPI_CS_HIGH + + SPI_END_TRANSACTION +} + +void uDisplay::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { + + if (interface != _UDSP_SPI) { + Renderer::drawFastHLine(x, y, w, color); + return; + } + + // Rudimentary clipping + if((x >= _width) || (y >= _height)) return; + if((x+w-1) >= _width) w = _width-x; + + + SPI_BEGIN_TRANSACTION + + SPI_CS_LOW + + setAddrWindow_int(x, y, w, 1); + + + while (w--) { + uspi->write16(color); + } + + SPI_CS_HIGH + + SPI_END_TRANSACTION +} + +void uDisplay::fillScreen(uint16_t color) { + fillRect(0, 0, gxs, gys, color); +} + +// fill a rectangle +void uDisplay::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { + + if (interface != _UDSP_SPI) { + Renderer::fillRect(x, y, w, h, color); + return; + } + + // rudimentary clipping (drawChar w/big text requires this) + if((x >= gxs) || (y >= gys)) return; + if((x + w - 1) >= gxs) w = gxs - x; + if((y + h - 1) >= gys) h = gys - y; + + + SPI_BEGIN_TRANSACTION + SPI_CS_LOW + + setAddrWindow_int(x, y, w, h); + + for (y = h; y > 0; y--) { + for (x = w; x > 0; x--) { + uspi->write16(color); + } + } + SPI_CS_HIGH + SPI_END_TRANSACTION +} + + +void uDisplay::Splash(void) { + setTextFont(splash_font); + setTextSize(splash_size); + DrawStringAt(splash_xp, splash_yp, dname, fg_col, 0); + Updateframe(); +} + +void uDisplay::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { + + if (!x0 && !y0 && !x1 && !y1) { + SPI_CS_HIGH + SPI_END_TRANSACTION + } else { + SPI_CS_LOW + SPI_BEGIN_TRANSACTION + setAddrWindow_int(x0, y0, x1 - x0, y1 - y0 ); + } +} + +void uDisplay::setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { + uint32_t xa = ((uint32_t)x << 16) | (x+w-1); + uint32_t ya = ((uint32_t)y << 16) | (y+h-1); + + SPI_DC_LOW + uspi->write(saw_1); + SPI_DC_HIGH + + uspi->write32(xa); + + SPI_DC_LOW + uspi->write(saw_2); + SPI_DC_HIGH + + uspi->write32(ya); + + SPI_DC_LOW + uspi->write(saw_3); // write to RAM + SPI_DC_HIGH + +} + +void uDisplay::pushColors(uint16_t *data, uint16_t len, boolean first) { + uint16_t color; + + while (len--) { + color = *data++; + uspi->write16(color); + } + +} + +void uDisplay::drawPixel(int16_t x, int16_t y, uint16_t color) { + + if (interface != _UDSP_SPI) { + Renderer::drawPixel(x, y, color); + return; + } + + if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; + + + SPI_BEGIN_TRANSACTION + + SPI_CS_LOW + + setAddrWindow_int(x, y, 1, 1); + + uspi->write16(color); + + SPI_CS_HIGH + + SPI_END_TRANSACTION +} + +void uDisplay::setRotation(uint8_t m) { + if (interface != _UDSP_SPI) { + Renderer::setRotation(m); + return; + } + switch (rotation) { + case 0: + if (interface == _UDSP_SPI) spi_command(rot_0); + _width = gxs; + _height = gys; + break; + case 1: + if (interface == _UDSP_SPI) spi_command(rot_1); + _width = gys; + _height = gxs; + break; + case 2: + if (interface == _UDSP_SPI) spi_command(rot_2); + _width = gxs; + _height = gys; + break; + case 3: + if (interface == _UDSP_SPI) spi_command(rot_3); + _width = gys; + _height = gxs; + break; + } +} + +void uDisplay::DisplayOnff(int8_t on) { + + if (interface == _UDSP_I2C) { + if (on) { + i2c_command(dsp_on); + } else { + i2c_command(dsp_off); + } + } else { + if (on) { + spi_command(dsp_on); + if (bpanel >= 0) { +#ifdef ESP32 + ledcWrite(ESP32_PWM_CHANNEL, dimmer); +#else + digitalWrite(bpanel, HIGH); +#endif + } + + } else { + spi_command(dsp_off); + if (bpanel >= 0) { +#ifdef ESP32 + ledcWrite(ESP32_PWM_CHANNEL, 0); +#else + digitalWrite(bpanel, LOW); +#endif + } + } + } +} + +void uDisplay::dim(uint8_t dim) { + dimmer = dim; + if (dimmer > 15) dimmer = 15; + dimmer = ((float)dimmer / 15.0) * 255.0; +#ifdef ESP32 + ledcWrite(ESP32_PWM_CHANNEL, dimmer); +#endif +} + + + +uint8_t uDisplay::strlen_ln(char *str) { + for (uint32_t cnt = 0; cnt < 256; cnt++) { + if (!str[cnt] || str[cnt] == '\n') return cnt; + } + return 0; +} + +char *uDisplay::devname(void) { + return dname; +} + +uint32_t uDisplay::str2c(char **sp, char *vp, uint32_t len) { + char *lp = *sp; + if (len) len--; + char *cp = strchr(lp, ','); + if (cp) { + while (1) { + if (*lp == ',') { + *vp = 0; + *sp = lp + 1; + return 0; + } + if (len) { + *vp++ = *lp++; + len--; + } else { + lp++; + } + } + } else { + uint8_t slen = strlen(lp); + if (slen) { + strlcpy(vp, *sp, len); + *sp = lp + slen; + return 0; + } + } + return 1; +} + +int32_t uDisplay::next_val(char **sp) { + char ibuff[16]; + str2c(sp, ibuff, sizeof(ibuff)); + return atoi(ibuff); +} + +uint32_t uDisplay::next_hex(char **sp) { + char ibuff[16]; + str2c(sp, ibuff, sizeof(ibuff)); + return strtol(ibuff, 0, 16); +} diff --git a/lib/lib_display/UDisplay/uDisplay.h b/lib/lib_display/UDisplay/uDisplay.h new file mode 100644 index 000000000..f5f3c789d --- /dev/null +++ b/lib/lib_display/UDisplay/uDisplay.h @@ -0,0 +1,114 @@ +#ifndef _UDISP_ +#define _UDISP_ + +#include +#include + +#define _UDSP_I2C 1 +#define _UDSP_SPI 2 + +#define UDISP1_WHITE 1 +#define UDISP1_BLACK 0 + + +// Color definitions +#define UDISP_BLACK 0x0000 /* 0, 0, 0 */ +#define UDISP_NAVY 0x000F /* 0, 0, 128 */ +#define UDISP_DARKGREEN 0x03E0 /* 0, 128, 0 */ +#define UDISP_DARKCYAN 0x03EF /* 0, 128, 128 */ +#define UDISP_MAROON 0x7800 /* 128, 0, 0 */ +#define UDISP_PURPLE 0x780F /* 128, 0, 128 */ +#define UDISP_OLIVE 0x7BE0 /* 128, 128, 0 */ +#define UDISP_LIGHTGREY 0xC618 /* 192, 192, 192 */ +#define UDISP_DARKGREY 0x7BEF /* 128, 128, 128 */ +#define UDISP_BLUE 0x001F /* 0, 0, 255 */ +#define UDISP_GREEN 0x07E0 /* 0, 255, 0 */ +#define UDISP_CYAN 0x07FF /* 0, 255, 255 */ +#define UDISP_RED 0xF800 /* 255, 0, 0 */ +#define UDISP_MAGENTA 0xF81F /* 255, 0, 255 */ +#define UDISP_YELLOW 0xFFE0 /* 255, 255, 0 */ +#define UDISP_WHITE 0xFFFF /* 255, 255, 255 */ +#define UDISP_ORANGE 0xFD20 /* 255, 165, 0 */ +#define UDISP_GREENYELLOW 0xAFE5 /* 173, 255, 47 */ +#define UDISP_PINK 0xF81F + +#define SPI_BEGIN_TRANSACTION uspi->beginTransaction(spiSettings); +#define SPI_END_TRANSACTION uspi->endTransaction(); +#define SPI_CS_LOW if (spi_cs >= 0) digitalWrite(spi_cs, LOW); +#define SPI_CS_HIGH if (spi_cs >= 0) digitalWrite(spi_cs, HIGH); +#define SPI_DC_LOW if (spi_dc >= 0) digitalWrite(spi_dc, LOW); +#define SPI_DC_HIGH if (spi_dc >= 0) digitalWrite(spi_dc, HIGH); + +#define ESP32_PWM_CHANNEL 1 + +class uDisplay : public Renderer { + public: + uDisplay(char *); + Renderer *Init(void); + void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font); + void Updateframe(); + void DisplayOnff(int8_t on); + void Splash(void); + char *devname(void); + uint16_t fgcol(void) const { return fg_col; }; + uint16_t bgcol(void) const { return bg_col; }; + void dim(uint8_t dim); + uint16_t GetColorFromIndex(uint8_t index); + void setRotation(uint8_t m); + void fillScreen(uint16_t color); + void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void pushColors(uint16_t *data, uint16_t len, boolean first); + + private: + void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); + void drawPixel(int16_t x, int16_t y, uint16_t color); + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + uint32_t str2c(char **sp, char *vp, uint32_t len); + void i2c_command(uint8_t val); + void spi_command(uint8_t val); + uint8_t strlen_ln(char *str); + int32_t next_val(char **sp); + uint32_t next_hex(char **sp); + void setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h); + char dname[16]; + int8_t bpp; + uint8_t interface; + uint8_t i2caddr; + int8_t i2c_scl; + int8_t i2c_sda; + int8_t reset; + uint8_t dsp_cmds[128]; + uint8_t dsp_ncmds; + uint8_t dsp_on; + uint8_t dsp_off; + uint16_t splash_font; + uint16_t splash_size; + uint16_t splash_xp; + uint16_t splash_yp; + uint16_t fg_col; + uint16_t bg_col; + uint16_t gxs; + uint16_t gys; + int8_t spi_cs; + int8_t spi_clk; + int8_t spi_mosi; + int8_t spi_dc; + int8_t bpanel; + int8_t spi_miso; + uint8_t dimmer; + SPIClass *uspi; + SPISettings spiSettings; + uint32_t spi_speed; + uint8_t spi_nr = 1; + uint8_t rot_0; + uint8_t rot_1; + uint8_t rot_2; + uint8_t rot_3; + uint8_t saw_1; + uint8_t saw_2; + uint8_t saw_3; + uint8_t flags; +}; + +#endif // _UDISP_ diff --git a/lib/libesp32/Berry-0.1.10/library.properties b/lib/libesp32/Berry-0.1.10/library.properties deleted file mode 100644 index 23cdd9946..000000000 --- a/lib/libesp32/Berry-0.1.10/library.properties +++ /dev/null @@ -1,7 +0,0 @@ -name=Berry -version=0.1.10 -author=Guan Wenliang , -maintainer=Stephan Hadinger -sentence=Berry scripting language for Tasmota32 -paragraph=Berry is a ultra-lightweight dynamically typed embedded scripting language. -architectures=esp32 diff --git a/lib/libesp32/Berry-0.1.10/src/berry_conf.h b/lib/libesp32/Berry-0.1.10/src/berry_conf.h deleted file mode 100644 index f645c0338..000000000 --- a/lib/libesp32/Berry-0.1.10/src/berry_conf.h +++ /dev/null @@ -1 +0,0 @@ -#include "port/berry_conf.h" \ No newline at end of file diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_driverlib.c b/lib/libesp32/Berry-0.1.10/src/port/be_driverlib.c deleted file mode 100644 index 4e9b8cce8..000000000 --- a/lib/libesp32/Berry-0.1.10/src/port/be_driverlib.c +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************** - * Tasmota lib - * - * To use: `d = Driver()` - * - *******************************************************************/ -#include "be_object.h" - -// #if !BE_USE_PRECOMPILED_OBJECT -#if 1 // TODO we will do pre-compiled later -void be_load_driverlib(bvm *vm) -{ - static const bnfuncinfo members[] = { - { "every_second", NULL }, - { "every_100ms", NULL }, - { "web_add_button", NULL }, - { "web_add_main_button", NULL }, - { "save_before_restart", NULL }, - { "web_sensor", NULL }, - { "json_append", NULL }, - { "button_pressed", NULL }, - - { NULL, NULL } - }; - be_regclass(vm, "Driver", members); -} -#else -/* @const_object_info_begin -module tasmota (scope: global, depend: 1) { - get_free_heap, func(l_getFreeHeap) -} -@const_object_info_end */ -#include "../generate/be_fixed_tasmota.h" -#endif diff --git a/lib/libesp32/Berry-0.1.10/LICENSE b/lib/libesp32/Berry/LICENSE similarity index 100% rename from lib/libesp32/Berry-0.1.10/LICENSE rename to lib/libesp32/Berry/LICENSE diff --git a/lib/libesp32/Berry/berry-logo.png b/lib/libesp32/Berry/berry-logo.png new file mode 100644 index 000000000..1eb419089 Binary files /dev/null and b/lib/libesp32/Berry/berry-logo.png differ diff --git a/lib/libesp32/Berry/default/be_driverlib.c b/lib/libesp32/Berry/default/be_driverlib.c new file mode 100644 index 000000000..fd9c2ccbb --- /dev/null +++ b/lib/libesp32/Berry/default/be_driverlib.c @@ -0,0 +1,110 @@ +/******************************************************************** + * Tasmota lib + * + * To use: `d = Driver()` + * + *******************************************************************/ +#include "be_object.h" +#include "be_string.h" +#include "be_gc.h" + +extern int d_getTasmotaGlob(bvm *vm); + + +/******************************************************************** + "class Driver2 : Driver " + "def add_cmd(c, f) " + "var tasmota = self.get_tasmota() " + "tasmota.add_cmd(c, / cmd, idx, payload, payload_json -> f(self, cmd, idx, payload, payload_json)) " + "end " + "end " + "Driver = Driver2 " +********************************************************************/ +/******************************************************************** +** Solidified function: add_cmd +********************************************************************/ + +/********** Solidified proto: add_cmd_0 */ +static const bupvaldesc add_cmd_0_upvals[2] = { + be_local_const_upval(1, 2), + be_local_const_upval(1, 0), +}; + +be_define_local_const_str(add_cmd_0_str_name, "add_cmd_0", 607256038, 0, 8, 0); +be_define_local_const_str(add_cmd_0_str_source, "input", -103256197, 0, 5, 0); + +static const uint32_t add_cmd_0_code[8] = { + 0x68100000, // 0000 GETUPV R4 U0 + 0x68140001, // 0001 GETUPV R5 U1 + 0x5C180000, // 0002 MOVE R6 R0 + 0x5C1C0200, // 0003 MOVE R7 R1 + 0x5C200400, // 0004 MOVE R8 R2 + 0x5C240600, // 0005 MOVE R9 R3 + 0x7C100A00, // 0006 CALL R4 5 + 0x80040800, // 0007 RET 1 R4 +}; + +be_define_local_proto(add_cmd_0, 10, 4, 0, 0, 1); + +/********** Solidified proto: add_cmd */ +static const bproto *add_cmd_subproto[1] = { + &add_cmd_0_proto, +}; + +be_define_local_const_str(add_cmd_str_name, "add_cmd", -933336417, 0, 7, 0); +be_define_local_const_str(add_cmd_str_source, "input", -103256197, 0, 5, 0); +be_define_local_const_str(add_cmd_str_0, "get_tasmota", 334356779, 0, 11, 0); +be_define_local_const_str(add_cmd_str_1, "add_cmd", -933336417, 0, 7, 0); + +static const bvalue add_cmd_ktab[2] = { + { { .s=be_local_const_str(add_cmd_str_0) }, BE_STRING}, + { { .s=be_local_const_str(add_cmd_str_1) }, BE_STRING}, +}; + +static const uint32_t add_cmd_code[8] = { + 0x8C0C0100, // 0000 GETMET R3 R0 R256 + 0x7C0C0200, // 0001 CALL R3 1 + 0x8C100701, // 0002 GETMET R4 R3 R257 + 0x5C180200, // 0003 MOVE R6 R1 + 0x841C0000, // 0004 CLOSURE R7 P0 + 0x7C100600, // 0005 CALL R4 3 + 0xA0000000, // 0006 CLOSE 0 + 0x80000000, // 0007 RET 0 R0 +}; + +be_define_local_proto(add_cmd, 8, 3, 1, 1, 0); +be_define_local_closure(add_cmd); + +/*******************************************************************/ + +// #if !BE_USE_PRECOMPILED_OBJECT +#if 1 // TODO we will do pre-compiled later +void be_load_driverlib(bvm *vm) +{ + static const bnfuncinfo members[] = { + { "every_second", NULL }, + { "every_100ms", NULL }, + { "web_add_button", NULL }, + { "web_add_main_button", NULL }, + { "save_before_restart", NULL }, + { "web_sensor", NULL }, + { "json_append", NULL }, + { "button_pressed", NULL }, + + { "get_tasmota", d_getTasmotaGlob }, + + { NULL, (bntvfunc) BE_CLOSURE }, /* mark section for berry closures */ + { "add_cmd", (bntvfunc) &add_cmd_closure }, + + { NULL, NULL } + }; + be_regclass(vm, "Driver", members); +} +#else +/* @const_object_info_begin +module tasmota (scope: global, depend: 1) { + get_free_heap, func(l_getFreeHeap) +} +@const_object_info_end */ +#include "../generate/be_fixed_tasmota.h" +#endif diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_energylib.c b/lib/libesp32/Berry/default/be_energylib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/port/be_energylib.c rename to lib/libesp32/Berry/default/be_energylib.c diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_gpio_lib.c b/lib/libesp32/Berry/default/be_gpio_lib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/port/be_gpio_lib.c rename to lib/libesp32/Berry/default/be_gpio_lib.c diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_light_lib.c b/lib/libesp32/Berry/default/be_light_lib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/port/be_light_lib.c rename to lib/libesp32/Berry/default/be_light_lib.c diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_modtab.c b/lib/libesp32/Berry/default/be_modtab.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/port/be_modtab.c rename to lib/libesp32/Berry/default/be_modtab.c diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_port.cpp b/lib/libesp32/Berry/default/be_port.cpp similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/port/be_port.cpp rename to lib/libesp32/Berry/default/be_port.cpp diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_tasmotalib.c b/lib/libesp32/Berry/default/be_tasmotalib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/port/be_tasmotalib.c rename to lib/libesp32/Berry/default/be_tasmotalib.c diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_wirelib.c b/lib/libesp32/Berry/default/be_wirelib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/port/be_wirelib.c rename to lib/libesp32/Berry/default/be_wirelib.c diff --git a/lib/libesp32/Berry-0.1.10/src/port/berry_conf.h b/lib/libesp32/Berry/default/berry_conf.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/port/berry_conf.h rename to lib/libesp32/Berry/default/berry_conf.h diff --git a/lib/libesp32/Berry-0.1.10/src/port/gpio.txt b/lib/libesp32/Berry/default/gpio.txt similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/port/gpio.txt rename to lib/libesp32/Berry/default/gpio.txt diff --git a/lib/libesp32/Berry/examples/anon_func.be b/lib/libesp32/Berry/examples/anon_func.be new file mode 100644 index 000000000..78854ce64 --- /dev/null +++ b/lib/libesp32/Berry/examples/anon_func.be @@ -0,0 +1,20 @@ +# anonymous function and closure +def count(x) + var arr = [] + for i : 0 .. x + arr.push( + def (n) # loop variable cannot be used directly as free variable + return def () + return n * n + end + end (i) # define and call anonymous function + ) + end + return arr +end + +for xx : count(6) + print(xx()) # 0, 1, 4 ... n * n +end + +return count diff --git a/lib/libesp32/Berry/examples/bigloop.be b/lib/libesp32/Berry/examples/bigloop.be new file mode 100644 index 000000000..a3a77768b --- /dev/null +++ b/lib/libesp32/Berry/examples/bigloop.be @@ -0,0 +1,15 @@ +import time + +c = time.clock() +do + i = 0 + while i < 100000000 + i += 1 + end +end +print('while iteration 100000000 times', time.clock() - c, 's') + +c = time.clock() +for i : 1 .. 100000000 +end +print('for iteration 100000000 times', time.clock() - c, 's') diff --git a/lib/libesp32/Berry/examples/bintree.be b/lib/libesp32/Berry/examples/bintree.be new file mode 100644 index 000000000..81936f8a0 --- /dev/null +++ b/lib/libesp32/Berry/examples/bintree.be @@ -0,0 +1,60 @@ +# Reference from https://github.com/BerryMathDevelopmentTeam/BerryMath/blob/master/testscript/BinaryTree.bm + +class node + var v, l, r + def init(v, l, r) + self.v = v + self.l = l + self.r = r + end + def insert(v) + if v < self.v + if self.l + self.l.insert(v) + else + self.l = node(v) + end + else + if self.r + self.r.insert(v) + else + self.r = node (v) + end + end + end + def sort(l) + if (self.l) self.l.sort(l) end + l.push(self.v) + if (self.r) self.r.sort(l) end + end +end + +class btree + var root + def insert(v) + if self.root + self.root.insert(v) + else + self.root = node(v) + end + end + def sort() + var l = [] + if self.root + self.root.sort(l) + end + return l + end +end + +var tree = btree() +tree.insert(-100) +tree.insert(5); +tree.insert(3); +tree.insert(9); +tree.insert(10); +tree.insert(10000000); +tree.insert(1); +tree.insert(-1); +tree.insert(-10); +print(tree.sort()); diff --git a/lib/libesp32/Berry/examples/calcpi.be b/lib/libesp32/Berry/examples/calcpi.be new file mode 100644 index 000000000..053f87875 --- /dev/null +++ b/lib/libesp32/Berry/examples/calcpi.be @@ -0,0 +1,16 @@ +def cpi(n) + i = 2 + pi = 3 + while i <= n + term = 4.0 / (i * (i + 1) * (i + 2)) + if i % 4 + pi = pi + term + else + pi = pi - term + end + i = i + 2 + end + return pi +end + +print("pi =", cpi(100)) diff --git a/lib/libesp32/Berry/examples/exception.be b/lib/libesp32/Berry/examples/exception.be new file mode 100644 index 000000000..3a3098dce --- /dev/null +++ b/lib/libesp32/Berry/examples/exception.be @@ -0,0 +1,12 @@ +import debug + +def test_func() + try + compile('def +() end')() + except .. as e, v + print('catch execption:', str(e) + ' >>>\n ' + str(v)) + debug.traceback() + end +end + +test_func() diff --git a/lib/libesp32/Berry/examples/fib_rec.be b/lib/libesp32/Berry/examples/fib_rec.be new file mode 100644 index 000000000..31ed3817b --- /dev/null +++ b/lib/libesp32/Berry/examples/fib_rec.be @@ -0,0 +1,12 @@ +import time + +def fib(x) + if x <= 2 + return 1 + end + return fib(x - 1) + fib(x - 2) +end + +c = time.clock() +print("fib:", fib(38)) # minimum stack size: 78!! +print("time:", time.clock() - c, 's') diff --git a/lib/libesp32/Berry/examples/guess_number.be b/lib/libesp32/Berry/examples/guess_number.be new file mode 100644 index 000000000..6cbd07e7c --- /dev/null +++ b/lib/libesp32/Berry/examples/guess_number.be @@ -0,0 +1,26 @@ +import time +import math + +math.srand(time.time()) +res = math.rand() % 100 +max_test = 7 +test = -1 +idx = 1 +print('Guess a number between 0 and 99. You have', max_test, 'chances.') +while test != res && idx <= max_test + test = number(input(str(idx) + ': enter the number you guessed: ')) + if type(test) != 'int' + print('This is not an integer. Continue!') + continue + elif test > res + print('This number is too large.') + elif test < res + print('This number is too small.') + end + idx = idx + 1 +end +if test == res + print('You win!') +else + print('You failed, the correct answer is', res) +end diff --git a/lib/libesp32/Berry/examples/json.be b/lib/libesp32/Berry/examples/json.be new file mode 100644 index 000000000..d98dff8bb --- /dev/null +++ b/lib/libesp32/Berry/examples/json.be @@ -0,0 +1,4 @@ +import json +print(json.load('{"key": "value"}')) +print(json.dump({'test key': nil})) +print(json.dump({'key1': nil, 45: true}, 'format')) diff --git a/lib/libesp32/Berry/examples/lambda.be b/lib/libesp32/Berry/examples/lambda.be new file mode 100644 index 000000000..1d0b709bb --- /dev/null +++ b/lib/libesp32/Berry/examples/lambda.be @@ -0,0 +1,8 @@ +# simple lambda example +print((/a b c-> a * b + c)(2, 3, 4)) + +# Y-Combinator and factorial functions +Y = /f-> (/x-> f(/n-> x(x)(n)))(/x-> f(/n-> x(x)(n))) +F = /f-> /x-> x ? f(x - 1) * x : 1 +fact = Y(F) +print('fact(10) == ' .. fact(10)) diff --git a/lib/libesp32/Berry/examples/listdir.be b/lib/libesp32/Berry/examples/listdir.be new file mode 100644 index 000000000..2dd880118 --- /dev/null +++ b/lib/libesp32/Berry/examples/listdir.be @@ -0,0 +1,16 @@ +import os + +def scandir(path) + print('path: ' + path) + for name : os.listdir(path) + var fullname = os.path.join(path, name) + if os.path.isfile(fullname) + print('file: ' + fullname) + else + print('path: ' + fullname) + scandir(fullname) + end + end +end + +scandir('.') diff --git a/lib/libesp32/Berry/examples/qsort.be b/lib/libesp32/Berry/examples/qsort.be new file mode 100644 index 000000000..b09b65672 --- /dev/null +++ b/lib/libesp32/Berry/examples/qsort.be @@ -0,0 +1,42 @@ +def qsort(data) + # do once sort + def once(left, right) + var pivot = data[left] # use the 0th value as the pivot + while left < right # check if sort is complete + # put the value less than the pivot to the left + while left < right && data[right] >= pivot + right -= 1 # skip values greater than pivot + end + data[left] = data[right] + # put the value greater than the pivot on the right + while left < right && data[left] <= pivot + left += 1 # skip values less than pivot + end + data[right] = data[left] + end + # now we have the index of the pivot, store it + data[left] = pivot + return left # return the index of the pivot + end + # recursive quick sort algorithm + def _sort(left, right) + if left < right # executed when the array is not empty + var index = once(left, right) # get index of pivot for divide and conquer + _sort(left, index - 1) # sort the data on the left + _sort(index + 1, right) # sort the data on the right + end + end + # start quick sort + _sort(0, data.size() - 1) + return data +end + +import time, math +math.srand(time.time()) # sse system time as a random seed +data = [] +# put 20 random numbers into the array +for i : 1 .. 20 + data.push(math.rand() % 100) +end +# sort and print +print(qsort(data)) diff --git a/lib/libesp32/Berry/examples/repl.be b/lib/libesp32/Berry/examples/repl.be new file mode 100644 index 000000000..aac26b0a1 --- /dev/null +++ b/lib/libesp32/Berry/examples/repl.be @@ -0,0 +1,61 @@ +do + def ismult(msg) + import string + return string.split(msg, -5)[1] == '\'EOS\'' + end + + def multline(src, msg) + if !ismult(msg) + print('syntax_error: ' + msg) + return + end + while true + try + src += '\n' + input('>> ') + return compile(src) + except 'syntax_error' as e, m + if !ismult(m) + print('syntax_error: ' + m) + return + end + end + end + end + + def parse() + var fun, src = input('> ') + try + fun = compile('return (' + src + ')') + except 'syntax_error' as e, m + try + fun = compile(src) + except 'syntax_error' as e, m + fun = multline(src, m) + end + end + return fun + end + + def run(fun) + try + var res = fun() + if res print(res) end + except .. as e, m + import debug + print(e .. ': ' .. m) + debug.traceback() + end + end + + def repl() + while true + var fun = parse() + if fun != nil + run(fun) + end + end + end + + print("Berry Berry REPL!") + repl() +end diff --git a/lib/libesp32/Berry/examples/string.be b/lib/libesp32/Berry/examples/string.be new file mode 100644 index 000000000..299834e21 --- /dev/null +++ b/lib/libesp32/Berry/examples/string.be @@ -0,0 +1,32 @@ +s = "This is a long string test. 0123456789 abcdefg ABCDEFG" +print(s) + +a = .5 +print(a) + +import string as s + +print(s.hex(0x45678ABCD, 16)) + +def bin(x, num) + assert(type(x) == 'int', 'the type of \'x\' must be integer') + # test the 'x' bits + var bits = 1 + for i : 0 .. 62 + if x & (1 << 63 - i) + bits = 64 - i + break + end + end + if type(num) == 'int' && num > 0 && num <= 64 + bits = bits < num ? num : bits + end + var result = '' + bits -= 1 + for i : 0 .. bits + result += x & (1 << (bits - i)) ? '1' : '0' + end + return result +end + +print(bin(33)) diff --git a/lib/libesp32/Berry/examples/strmod.be b/lib/libesp32/Berry/examples/strmod.be new file mode 100644 index 000000000..8660f5b4e --- /dev/null +++ b/lib/libesp32/Berry/examples/strmod.be @@ -0,0 +1,7 @@ +import string + +print(string.format('%.3d', 12)) +print(string.format('%.3f', 12)) +print(string.format('%20.7f', 14.5)) +print(string.format('-- %-40s ---', 'this is a string format test')) +print(string.format('-- %40s ---', 'this is a string format test')) diff --git a/lib/libesp32/Berry-0.1.10/generate/be_const_strtab.h b/lib/libesp32/Berry/generate/be_const_strtab.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_const_strtab.h rename to lib/libesp32/Berry/generate/be_const_strtab.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_const_strtab_def.h b/lib/libesp32/Berry/generate/be_const_strtab_def.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_const_strtab_def.h rename to lib/libesp32/Berry/generate/be_const_strtab_def.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_bytes.h b/lib/libesp32/Berry/generate/be_fixed_be_class_bytes.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_bytes.h rename to lib/libesp32/Berry/generate/be_fixed_be_class_bytes.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_list.h b/lib/libesp32/Berry/generate/be_fixed_be_class_list.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_list.h rename to lib/libesp32/Berry/generate/be_fixed_be_class_list.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_map.h b/lib/libesp32/Berry/generate/be_fixed_be_class_map.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_map.h rename to lib/libesp32/Berry/generate/be_fixed_be_class_map.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_range.h b/lib/libesp32/Berry/generate/be_fixed_be_class_range.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_range.h rename to lib/libesp32/Berry/generate/be_fixed_be_class_range.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_debug.h b/lib/libesp32/Berry/generate/be_fixed_debug.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_debug.h rename to lib/libesp32/Berry/generate/be_fixed_debug.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_gc.h b/lib/libesp32/Berry/generate/be_fixed_gc.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_gc.h rename to lib/libesp32/Berry/generate/be_fixed_gc.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_gpio.h b/lib/libesp32/Berry/generate/be_fixed_gpio.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_gpio.h rename to lib/libesp32/Berry/generate/be_fixed_gpio.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_json.h b/lib/libesp32/Berry/generate/be_fixed_json.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_json.h rename to lib/libesp32/Berry/generate/be_fixed_json.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_m_builtin.h b/lib/libesp32/Berry/generate/be_fixed_m_builtin.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_m_builtin.h rename to lib/libesp32/Berry/generate/be_fixed_m_builtin.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_math.h b/lib/libesp32/Berry/generate/be_fixed_math.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_math.h rename to lib/libesp32/Berry/generate/be_fixed_math.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_os.h b/lib/libesp32/Berry/generate/be_fixed_os.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_os.h rename to lib/libesp32/Berry/generate/be_fixed_os.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_path.h b/lib/libesp32/Berry/generate/be_fixed_path.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_path.h rename to lib/libesp32/Berry/generate/be_fixed_path.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_solidify.h b/lib/libesp32/Berry/generate/be_fixed_solidify.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_solidify.h rename to lib/libesp32/Berry/generate/be_fixed_solidify.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_string.h b/lib/libesp32/Berry/generate/be_fixed_string.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_string.h rename to lib/libesp32/Berry/generate/be_fixed_string.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_sys.h b/lib/libesp32/Berry/generate/be_fixed_sys.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_sys.h rename to lib/libesp32/Berry/generate/be_fixed_sys.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_tasmota.h b/lib/libesp32/Berry/generate/be_fixed_tasmota.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_tasmota.h rename to lib/libesp32/Berry/generate/be_fixed_tasmota.h diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_time.h b/lib/libesp32/Berry/generate/be_fixed_time.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/generate/be_fixed_time.h rename to lib/libesp32/Berry/generate/be_fixed_time.h diff --git a/lib/libesp32/Berry/library.json b/lib/libesp32/Berry/library.json new file mode 100644 index 000000000..c1a6bf633 --- /dev/null +++ b/lib/libesp32/Berry/library.json @@ -0,0 +1,29 @@ +{ + "name":"Berry", + "description":"Berry scripting language for Tasmota32", + "keywords":"berry, script", + "authors": + { + "name": "Guan Wenliang , ", + "maintainer": true + }, + "repository": + { + "type": "git", + "url": "https://github.com/Skiars/berry" + }, + "version": "7.0", + "license": "MIT License", + "frameworks": "*", + "platforms": "*", + "build": { + "srcFilter": [ + "+<*.c>", + "+<../default/*.c>", + "+<../default/*.cpp>", + "+<../default/*.hpp>", + "+<*.cpp>", + "+<*.h>" + ] + } +} \ No newline at end of file diff --git a/lib/libesp32/Berry-0.1.10/src/be_api.c b/lib/libesp32/Berry/src/be_api.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_api.c rename to lib/libesp32/Berry/src/be_api.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_baselib.c b/lib/libesp32/Berry/src/be_baselib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_baselib.c rename to lib/libesp32/Berry/src/be_baselib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_bytecode.c b/lib/libesp32/Berry/src/be_bytecode.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_bytecode.c rename to lib/libesp32/Berry/src/be_bytecode.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_bytecode.h b/lib/libesp32/Berry/src/be_bytecode.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_bytecode.h rename to lib/libesp32/Berry/src/be_bytecode.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_byteslib.c b/lib/libesp32/Berry/src/be_byteslib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_byteslib.c rename to lib/libesp32/Berry/src/be_byteslib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_class.c b/lib/libesp32/Berry/src/be_class.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_class.c rename to lib/libesp32/Berry/src/be_class.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_class.h b/lib/libesp32/Berry/src/be_class.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_class.h rename to lib/libesp32/Berry/src/be_class.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_code.c b/lib/libesp32/Berry/src/be_code.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_code.c rename to lib/libesp32/Berry/src/be_code.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_code.h b/lib/libesp32/Berry/src/be_code.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_code.h rename to lib/libesp32/Berry/src/be_code.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_constobj.h b/lib/libesp32/Berry/src/be_constobj.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_constobj.h rename to lib/libesp32/Berry/src/be_constobj.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_debug.c b/lib/libesp32/Berry/src/be_debug.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_debug.c rename to lib/libesp32/Berry/src/be_debug.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_debug.h b/lib/libesp32/Berry/src/be_debug.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_debug.h rename to lib/libesp32/Berry/src/be_debug.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_debuglib.c b/lib/libesp32/Berry/src/be_debuglib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_debuglib.c rename to lib/libesp32/Berry/src/be_debuglib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_decoder.h b/lib/libesp32/Berry/src/be_decoder.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_decoder.h rename to lib/libesp32/Berry/src/be_decoder.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_exec.c b/lib/libesp32/Berry/src/be_exec.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_exec.c rename to lib/libesp32/Berry/src/be_exec.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_exec.h b/lib/libesp32/Berry/src/be_exec.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_exec.h rename to lib/libesp32/Berry/src/be_exec.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_filelib.c b/lib/libesp32/Berry/src/be_filelib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_filelib.c rename to lib/libesp32/Berry/src/be_filelib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_func.c b/lib/libesp32/Berry/src/be_func.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_func.c rename to lib/libesp32/Berry/src/be_func.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_func.h b/lib/libesp32/Berry/src/be_func.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_func.h rename to lib/libesp32/Berry/src/be_func.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_gc.c b/lib/libesp32/Berry/src/be_gc.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_gc.c rename to lib/libesp32/Berry/src/be_gc.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_gc.h b/lib/libesp32/Berry/src/be_gc.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_gc.h rename to lib/libesp32/Berry/src/be_gc.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_gclib.c b/lib/libesp32/Berry/src/be_gclib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_gclib.c rename to lib/libesp32/Berry/src/be_gclib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_jsonlib.c b/lib/libesp32/Berry/src/be_jsonlib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_jsonlib.c rename to lib/libesp32/Berry/src/be_jsonlib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_lexer.c b/lib/libesp32/Berry/src/be_lexer.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_lexer.c rename to lib/libesp32/Berry/src/be_lexer.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_lexer.h b/lib/libesp32/Berry/src/be_lexer.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_lexer.h rename to lib/libesp32/Berry/src/be_lexer.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_libs.c b/lib/libesp32/Berry/src/be_libs.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_libs.c rename to lib/libesp32/Berry/src/be_libs.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_libs.h b/lib/libesp32/Berry/src/be_libs.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_libs.h rename to lib/libesp32/Berry/src/be_libs.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_list.c b/lib/libesp32/Berry/src/be_list.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_list.c rename to lib/libesp32/Berry/src/be_list.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_list.h b/lib/libesp32/Berry/src/be_list.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_list.h rename to lib/libesp32/Berry/src/be_list.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_listlib.c b/lib/libesp32/Berry/src/be_listlib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_listlib.c rename to lib/libesp32/Berry/src/be_listlib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_map.c b/lib/libesp32/Berry/src/be_map.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_map.c rename to lib/libesp32/Berry/src/be_map.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_map.h b/lib/libesp32/Berry/src/be_map.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_map.h rename to lib/libesp32/Berry/src/be_map.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_maplib.c b/lib/libesp32/Berry/src/be_maplib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_maplib.c rename to lib/libesp32/Berry/src/be_maplib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_mathlib.c b/lib/libesp32/Berry/src/be_mathlib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_mathlib.c rename to lib/libesp32/Berry/src/be_mathlib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_mem.c b/lib/libesp32/Berry/src/be_mem.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_mem.c rename to lib/libesp32/Berry/src/be_mem.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_mem.h b/lib/libesp32/Berry/src/be_mem.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_mem.h rename to lib/libesp32/Berry/src/be_mem.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_module.c b/lib/libesp32/Berry/src/be_module.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_module.c rename to lib/libesp32/Berry/src/be_module.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_module.h b/lib/libesp32/Berry/src/be_module.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_module.h rename to lib/libesp32/Berry/src/be_module.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_object.c b/lib/libesp32/Berry/src/be_object.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_object.c rename to lib/libesp32/Berry/src/be_object.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_object.h b/lib/libesp32/Berry/src/be_object.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_object.h rename to lib/libesp32/Berry/src/be_object.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_opcodes.h b/lib/libesp32/Berry/src/be_opcodes.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_opcodes.h rename to lib/libesp32/Berry/src/be_opcodes.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_oslib.c b/lib/libesp32/Berry/src/be_oslib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_oslib.c rename to lib/libesp32/Berry/src/be_oslib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_parser.c b/lib/libesp32/Berry/src/be_parser.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_parser.c rename to lib/libesp32/Berry/src/be_parser.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_parser.h b/lib/libesp32/Berry/src/be_parser.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_parser.h rename to lib/libesp32/Berry/src/be_parser.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_rangelib.c b/lib/libesp32/Berry/src/be_rangelib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_rangelib.c rename to lib/libesp32/Berry/src/be_rangelib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_repl.c b/lib/libesp32/Berry/src/be_repl.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_repl.c rename to lib/libesp32/Berry/src/be_repl.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_repl.h b/lib/libesp32/Berry/src/be_repl.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_repl.h rename to lib/libesp32/Berry/src/be_repl.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_solidifylib.c b/lib/libesp32/Berry/src/be_solidifylib.c similarity index 51% rename from lib/libesp32/Berry-0.1.10/src/be_solidifylib.c rename to lib/libesp32/Berry/src/be_solidifylib.c index cd355bc3d..56304bea3 100644 --- a/lib/libesp32/Berry-0.1.10/src/be_solidifylib.c +++ b/lib/libesp32/Berry/src/be_solidifylib.c @@ -45,46 +45,39 @@ static const char * m_type_ktab(int type) } } -static void m_solidify_closure(bvm *vm, bclosure *cl, int builtins) -{ - bproto *pr = cl->proto; - const char * func_name = str(pr->name); +static void m_solidify_proto(bvm *vm, bproto *pr, const char * func_name, int builtins) +{ + // const char * func_name = str(pr->name); const char * func_source = str(pr->source); - // logfmt("// == builtin_count %i\n", builtins); - // logfmt("// type %i, ", cl->type); - // logfmt("// marked %i, ", cl->marked); - // logfmt("// nupvals %i\n", cl->nupvals); + if (pr->nproto > 0) { + for (int32_t i = 0; i < pr->nproto; i++) { + size_t sub_len = strlen(func_name) + 10; + char sub_name[sub_len]; + snprintf(sub_name, sizeof(sub_name), "%s_%d", func_name, i); + m_solidify_proto(vm, pr->ptab[i], sub_name, builtins); + } + } - // logfmt("// PROTO:\n"); - // logfmt("// type %i, ", pr->type); - // logfmt("// marked %i, ", pr->marked); - // logfmt("// nstack %i, ", pr->nstack); - // logfmt("// argcs %i, ", pr->argc); - // // logfmt("// varg %i\n", pr->varg); + logfmt("\n/********** Solidified proto: %s */\n", func_name); - // logfmt("// gray %p\n", (void*)pr->gray); - // logfmt("// upvals %p\n", (void*)pr->upvals); - // logfmt("// proto_tab %p (%i)\n", (void*)pr->ptab, pr->nproto); + if (pr->nproto > 0) { + logfmt("static const bproto *%s_subproto[%i] = {\n", func_name, pr->nproto); + for (int32_t i = 0; i < pr->nproto; i++) { + logfmt(" &%s_%d_proto,\n", func_name, i); + // logfmt(" be_local_const_upval(%i, %i),\n", pr->upvals[i].instack, pr->upvals[i].idx); TODO + } + logfmt("};\n\n"); + } - // logfmt("// name %s\n", str(pr->name)); - // logfmt("// source %s\n", str(pr->source)); - - // logfmt("\n"); - - // logfmt("// ktab %p (%i)\n", (void*)pr->ktab, pr->nconst); - // for (int i = 0; i < pr->nconst; i++) { - // logfmt("// const[%i] type %i (%s) %p", i, pr->ktab[i].type, be_vtype2str(&pr->ktab[i]), pr->ktab[i].v.p); - // if (pr->ktab[i].type == BE_STRING) { - // logfmt(" = '%s'", str(pr->ktab[i].v.s)); - // } - // logfmt("\n"); - // } - - logfmt("\n"); - logfmt("/********************************************************************\n"); - logfmt("** Solidified function: %s\n", func_name); - logfmt("********************************************************************/\n\n"); + if (pr->nupvals > 0) { + logfmt("static const bupvaldesc %s_upvals[%i] = {\n", func_name, pr->nupvals); + for (int32_t i = 0; i < pr->nupvals; i++) { + logfmt(" be_local_const_upval(%i, %i),\n", pr->upvals[i].instack, pr->upvals[i].idx); + // logfmt("// upval[%d] = { .instack = %i, .idx = %i }\n", i, pr->upvals[i].instack, pr->upvals[i].idx); + } + logfmt("};\n\n"); + } /* create static strings for name and source */ logfmt("be_define_local_const_str(%s_str_name, \"%s\", %i, 0, %u, 0);\n", @@ -107,30 +100,32 @@ static void m_solidify_closure(bvm *vm, bclosure *cl, int builtins) } logfmt("\n"); - logfmt("static const bvalue %s_ktab[%i] = {\n", func_name, pr->nconst); - for (int k = 0; k < pr->nconst; k++) { - int type = pr->ktab[k].type; - const char *type_name = m_type_ktab(type); - if (type_name == NULL) { - char error[64]; - snprintf(error, sizeof(error), "Unsupported type in function constants: %i", type); - be_raise(vm, "internal_error", error); - } - if (type == BE_STRING) { - logfmt(" { { .s=be_local_const_str(%s_str_%i) }, %s},\n", func_name, k, type_name); - } else if (type == BE_INT) { - logfmt(" { { .i=%" BE_INT_FMTLEN "i }, %s},\n", pr->ktab[k].v.i, type_name); - } else if (type == BE_REAL) { -#if BE_USE_SINGLE_FLOAT - logfmt(" { { .p=(void*)0x%08X }, %s},\n", (uint32_t) pr->ktab[k].v.p, type_name); -#else - logfmt(" { { .p=(void*)0x%016llX }, %s},\n", (uint64_t) pr->ktab[k].v.p, type_name); -#endif - } else if (type == BE_BOOL) { - logfmt(" { { .b=%i }, %s},\n", pr->ktab[k].v.b, type_name); + if (pr->nconst > 0) { + logfmt("static const bvalue %s_ktab[%i] = {\n", func_name, pr->nconst); + for (int k = 0; k < pr->nconst; k++) { + int type = pr->ktab[k].type; + const char *type_name = m_type_ktab(type); + if (type_name == NULL) { + char error[64]; + snprintf(error, sizeof(error), "Unsupported type in function constants: %i", type); + be_raise(vm, "internal_error", error); + } + if (type == BE_STRING) { + logfmt(" { { .s=be_local_const_str(%s_str_%i) }, %s},\n", func_name, k, type_name); + } else if (type == BE_INT) { + logfmt(" { { .i=%" BE_INT_FMTLEN "i }, %s},\n", pr->ktab[k].v.i, type_name); + } else if (type == BE_REAL) { + #if BE_USE_SINGLE_FLOAT + logfmt(" { { .p=(void*)0x%08X }, %s},\n", (uint32_t) pr->ktab[k].v.p, type_name); + #else + logfmt(" { { .p=(void*)0x%016llX }, %s},\n", (uint64_t) pr->ktab[k].v.p, type_name); + #endif + } else if (type == BE_BOOL) { + logfmt(" { { .b=%i }, %s},\n", pr->ktab[k].v.b, type_name); + } } + logfmt("};\n\n"); } - logfmt("};\n\n"); logfmt("static const uint32_t %s_code[%i] = {\n", func_name, pr->codesize); for (int pc = 0; pc < pr->codesize; pc++) { @@ -150,52 +145,28 @@ static void m_solidify_closure(bvm *vm, bclosure *cl, int builtins) } logfmt("};\n\n"); - logfmt("static const bproto %s_proto = {\n", func_name); - // bcommon_header - logfmt(" NULL, // bgcobject *next\n"); - logfmt(" %i, // type\n", pr->type); - logfmt(" GC_CONST, // marked\n"); - // - logfmt(" %i, // nstack\n", pr->nstack); - logfmt(" %i, // nupvals\n", pr->nupvals); - logfmt(" %i, // argc\n", pr->argc); - logfmt(" %i, // varg\n", pr->varg); - if (pr->nproto > 0) { - be_raise(vm, "internal_error", "unsupported non-null proto list"); + logfmt("be_define_local_proto(%s, %d, %d, %d, %d, %d);\n", + func_name, pr->nstack, pr->argc, (pr->nconst > 0) ? 1 : 0, (pr->nproto > 0) ? 1 : 0, (pr->nupvals > 0) ? 1 : 0); +} + +static void m_solidify_closure(bvm *vm, bclosure *cl, int builtins) +{ + bproto *pr = cl->proto; + const char * func_name = str(pr->name); + + if (cl->nupvals > 0) { + be_raise(vm, "internal_error", "Unsupported upvals in closure"); } - logfmt(" NULL, // bgcobject *gray\n"); - logfmt(" NULL, // bupvaldesc *upvals\n"); - logfmt(" (bvalue*) &%s_ktab, // ktab\n", func_name); - logfmt(" NULL, // bproto **ptab\n"); - logfmt(" (binstruction*) &%s_code, // code\n", func_name); - logfmt(" be_local_const_str(%s_str_name), // name\n", func_name); - logfmt(" %i, // codesize\n", pr->codesize); - logfmt(" %i, // nconst\n", pr->nconst); - logfmt(" %i, // nproto\n", pr->nproto); - logfmt(" be_local_const_str(%s_str_source), // source\n", func_name); - // - logfmt("#if BE_DEBUG_RUNTIME_INFO /* debug information */\n"); - logfmt(" NULL, // lineinfo\n"); - logfmt(" 0, // nlineinfo\n"); - logfmt("#endif\n"); - logfmt("#if BE_DEBUG_VAR_INFO\n"); - logfmt(" NULL, // varinfo\n"); - logfmt(" 0, // nvarinfo\n"); - logfmt("#endif\n"); - logfmt("};\n\n"); + + logfmt("\n"); + logfmt("/********************************************************************\n"); + logfmt("** Solidified function: %s\n", func_name); + logfmt("********************************************************************/\n"); + + m_solidify_proto(vm, pr, func_name, builtins); // closure - logfmt("static const bclosure %s_closure = {\n", func_name); - // bcommon_header - logfmt(" NULL, // bgcobject *next\n"); - logfmt(" %i, // type\n", cl->type); - logfmt(" GC_CONST, // marked\n"); - // - logfmt(" %i, // nupvals\n", cl->nupvals); - logfmt(" NULL, // bgcobject *gray\n"); - logfmt(" (bproto*) &%s_proto, // proto\n", func_name); - logfmt(" { NULL } // upvals\n"); - logfmt("};\n\n"); + logfmt("be_define_local_closure(%s);\n\n", func_name); logfmt("/*******************************************************************/\n\n"); } diff --git a/lib/libesp32/Berry-0.1.10/src/be_string.c b/lib/libesp32/Berry/src/be_string.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_string.c rename to lib/libesp32/Berry/src/be_string.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_string.h b/lib/libesp32/Berry/src/be_string.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_string.h rename to lib/libesp32/Berry/src/be_string.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_strlib.c b/lib/libesp32/Berry/src/be_strlib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_strlib.c rename to lib/libesp32/Berry/src/be_strlib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_strlib.h b/lib/libesp32/Berry/src/be_strlib.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_strlib.h rename to lib/libesp32/Berry/src/be_strlib.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_sys.h b/lib/libesp32/Berry/src/be_sys.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_sys.h rename to lib/libesp32/Berry/src/be_sys.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_syslib.c b/lib/libesp32/Berry/src/be_syslib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_syslib.c rename to lib/libesp32/Berry/src/be_syslib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_timelib.c b/lib/libesp32/Berry/src/be_timelib.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_timelib.c rename to lib/libesp32/Berry/src/be_timelib.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_var.c b/lib/libesp32/Berry/src/be_var.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_var.c rename to lib/libesp32/Berry/src/be_var.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_var.h b/lib/libesp32/Berry/src/be_var.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_var.h rename to lib/libesp32/Berry/src/be_var.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_vector.c b/lib/libesp32/Berry/src/be_vector.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_vector.c rename to lib/libesp32/Berry/src/be_vector.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_vector.h b/lib/libesp32/Berry/src/be_vector.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_vector.h rename to lib/libesp32/Berry/src/be_vector.h diff --git a/lib/libesp32/Berry-0.1.10/src/be_vm.c b/lib/libesp32/Berry/src/be_vm.c similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_vm.c rename to lib/libesp32/Berry/src/be_vm.c diff --git a/lib/libesp32/Berry-0.1.10/src/be_vm.h b/lib/libesp32/Berry/src/be_vm.h similarity index 100% rename from lib/libesp32/Berry-0.1.10/src/be_vm.h rename to lib/libesp32/Berry/src/be_vm.h diff --git a/lib/libesp32/Berry-0.1.10/src/berry.h b/lib/libesp32/Berry/src/berry.h similarity index 84% rename from lib/libesp32/Berry-0.1.10/src/berry.h rename to lib/libesp32/Berry/src/berry.h index 25e9f3c85..760ec2961 100644 --- a/lib/libesp32/Berry-0.1.10/src/berry.h +++ b/lib/libesp32/Berry/src/berry.h @@ -101,7 +101,7 @@ enum berrorcode { #elif defined(__GNUC__) /* in GCC */ #define BERRY_LOCAL __attribute__ ((visibility ("hidden"))) #else /* other platforms */ - #define BERRY_LOCAL static + #define BERRY_LOCAL #endif #ifdef __cplusplus @@ -252,7 +252,7 @@ typedef struct bntvmodule { /* support for solidified berry functions */ /* native const strings outside of global string hash */ #define be_define_local_const_str(_name, _s, _hash, _extra, _len, _next) \ - BERRY_LOCAL const bcstring be_local_const_str_##_name = { \ + static const bcstring be_local_const_str_##_name = { \ .next = (bgcobject *)NULL, \ .type = BE_STRING, \ .marked = GC_CONST, \ @@ -264,6 +264,68 @@ typedef struct bntvmodule { #define be_local_const_str(_name) (bstring*) &be_local_const_str_##_name +/* conditional macro see https://stackoverflow.com/questions/11632219/c-preprocessor-macro-specialisation-based-on-an-argument */ +#define BE_IIF(cond) BE_IIF_ ## cond +#define BE_IIF_0(t, f) f +#define BE_IIF_1(t, f) t + +#if BE_DEBUG_VAR_INFO + #define be_local_const_upval(ins, idx) { "", ins, idx } +#else + #define be_local_const_upval(ins, idx) { ins, idx } +#endif + +/* conditional block in bproto depending on compilation options */ +#if BE_DEBUG_RUNTIME_INFO + #define PROTO_RUNTIME_BLOCK \ + NULL, /* varinfo */ \ + 0, /* nvarinfo */ +#else + #define PROTO_RUNTIME_BLOCK +#endif +#if BE_DEBUG_VAR_INFO + #define PROTO_VAR_INFO_BLOCK\ + NULL, /* varinfo */ \ + 0, /* nvarinfo */ +#else + #define PROTO_VAR_INFO_BLOCK +#endif + +/* define bproto */ +#define be_define_local_proto(_name, _nstack, _argc, _is_const, _is_subproto, _is_upval) \ + static const bproto _name##_proto = { \ + NULL, /* bgcobject *next */ \ + 8, /* type BE_PROTO */ \ + GC_CONST, /* marked outside of GC */ \ + (_nstack), /* nstack */ \ + BE_IIF(_is_upval)(sizeof(_name##_upvals)/sizeof(bupvaldesc),0),/* nupvals */ \ + (_argc), /* argc */ \ + 0, /* varg */ \ + NULL, /* bgcobject *gray */ \ + BE_IIF(_is_upval)((bupvaldesc*)&_name##_upvals,NULL), /* bupvaldesc *upvals */ \ + BE_IIF(_is_const)((bvalue*)&_name##_ktab,NULL), /* ktab */ \ + BE_IIF(_is_subproto)((struct bproto**)&_name##_subproto,NULL),/* bproto **ptab */ \ + (binstruction*) &_name##_code, /* code */ \ + be_local_const_str(_name##_str_name), /* name */ \ + sizeof(_name##_code)/sizeof(uint32_t), /* codesize */ \ + BE_IIF(_is_const)(sizeof(_name##_ktab)/sizeof(bvalue),0),/* nconst */ \ + BE_IIF(_is_subproto)(sizeof(_name##_subproto)/sizeof(bproto*),0),/* proto */ \ + be_local_const_str(_name##_str_source), /* source */ \ + PROTO_RUNTIME_BLOCK \ + PROTO_VAR_INFO_BLOCK \ + } + +#define be_define_local_closure(_name) \ + const bclosure _name##_closure = { \ + NULL, /* bgcobject *next */ \ + 36, /* type BE_CLOSURE */ \ + GC_CONST, /* marked */ \ + 0, /* nupvals */ \ + NULL, /* bgcobject *gray */ \ + (bproto*) &_name##_proto, /* proto */ \ + { NULL } /* upvals */ \ + } + /* debug hook typedefs */ #define BE_HOOK_LINE 1 diff --git a/lib/libesp32/Berry/src/berry_conf.h b/lib/libesp32/Berry/src/berry_conf.h new file mode 100644 index 000000000..c0ec957c4 --- /dev/null +++ b/lib/libesp32/Berry/src/berry_conf.h @@ -0,0 +1 @@ +#include "../default/berry_conf.h" \ No newline at end of file diff --git a/lib/libesp32/Berry/testall.be b/lib/libesp32/Berry/testall.be new file mode 100755 index 000000000..57414dbc5 --- /dev/null +++ b/lib/libesp32/Berry/testall.be @@ -0,0 +1,44 @@ +#! ./berry +import os + +os.system('lcov', '-q -c -i -d . -o init.info') + +var exec = './berry' +var path = 'tests' +var testcases = os.listdir(path) +var total = 0, failed = 0 + +for i : testcases + if os.path.splitext(i)[1] == '.be' + print('\033[0;36mrun testcase: ' + i + '\033[0m') + var ret = os.system(exec, os.path.join(path, i)) + if ret != 0 + print('\033[0;31mreturn code:', ret, '\033[0m') + failed += 1 + end + total += 1 + end +end + +print('\033[0;32mtest results: ' + + str(total) + ' total, ' + str(failed) + ' failed' + + (failed ? '' : ' (all tests passed)') + + '.\033[0m') + +if failed != 0 + os.exit(-1) +end + +var cmds = [ + 'lcov -q -c -d ./ -o cover.info', + 'lcov -q -a init.info -a cover.info -o total.info', + 'lcov --remove total.info */usr/include/* -o final.info', + 'genhtml -q -o test_report --legend --title "lcov" --prefix=./ final.info', + 'rm -f init.info cover.info total.info final.info' +] + +for cmd : cmds + if os.system(cmd) + os.exit(-1) + end +end diff --git a/lib/libesp32/Berry/tests/assignment.be b/lib/libesp32/Berry/tests/assignment.be new file mode 100644 index 000000000..71bb81ebf --- /dev/null +++ b/lib/libesp32/Berry/tests/assignment.be @@ -0,0 +1,34 @@ +class Test + var a +end + +# continuous assignment of global suffix expressions +o = Test() +o.a = 100 +assert(o.a == 100) +o.a += 10 +assert(o.a == 110) + +p = Test() +p.a = Test() +p.a.a = 50 +assert(p.a.a == 50) +p.a.a += 10 +assert(p.a.a == 60) + +# continuous assignment of local suffix expressions +def test_func() + var o = Test() + o.a = 100 + assert(o.a == 100) + o.a += 10 + assert(o.a == 110) + + var p = Test() + p.a = Test() + p.a.a = 50 + assert(p.a.a == 50) + p.a.a += 10 + assert(p.a.a == 60) +end +test_func() diff --git a/lib/libesp32/Berry/tests/bool.be b/lib/libesp32/Berry/tests/bool.be new file mode 100644 index 000000000..670f9bfd8 --- /dev/null +++ b/lib/libesp32/Berry/tests/bool.be @@ -0,0 +1,18 @@ +# test cases for boolean expressions + +assert(1 != false && 1 != true) +assert(0 != false && 0 != true) +assert(!!1 == true) +assert(!!0 == false) + +a = true +b = false +assert(!!list == true) +assert(a && b == false) +assert(!(a && b)) +def test(a, b) + while !(a && b) + assert(false) + end +end +test(true, true) diff --git a/lib/libesp32/Berry/tests/bytes.be b/lib/libesp32/Berry/tests/bytes.be new file mode 100644 index 000000000..cce46120f --- /dev/null +++ b/lib/libesp32/Berry/tests/bytes.be @@ -0,0 +1,167 @@ +#- basic initialization -# +b=bytes() +assert(str(b) == "bytes('')") +b=bytes("") +assert(str(b) == "bytes('')") +b=bytes(0) +assert(str(b) == "bytes('')") +b=bytes(1) +assert(str(b) == "bytes('')") +b=bytes(-1) +assert(str(b) == "bytes('')") +assert(b.size() == 0) + +b=bytes("a") +assert(str(b) == "bytes('')") +b=bytes(3.5) +assert(str(b) == "bytes('')") +b=bytes([]) +assert(str(b) == "bytes('')") + +b=bytes("1122AAaaBBbb") +assert(str(b) == "bytes('1122AAAABBBB')") +assert(b.size() == 6) +b=bytes("112") +assert(str(b) == "bytes('11')") +b=bytes("++") +assert(str(b) == "bytes('00')") + +#- add -# +b=bytes() +b.add(0x22) +assert(str(b) == "bytes('22')") +b.add(0x12345678, 0) +assert(str(b) == "bytes('22')") +b.add(0x12345678, 1) +assert(str(b) == "bytes('2278')") +b.add(0x12345678, 2) +assert(str(b) == "bytes('22787856')") +b.add(0x12345678, 4) +assert(str(b) == "bytes('2278785678563412')") +b.add(0x12345678, -1) #- big endian -# +assert(str(b) == "bytes('227878567856341278')") +b.add(0x12345678, -2) +assert(str(b) == "bytes('2278785678563412785678')") +b.add(0x12345678, -4) +assert(str(b) == "bytes('227878567856341278567812345678')") + +#- get -# +b=bytes("000102030405") +assert(b.get(0) == 0) +assert(b.get(-1) == 0) #- could consider nil as well -# +assert(b.get(6) == 0) #- could consider nil as well -# +assert(b.get(1) == 1) +assert(b.get(5) == 5) + +assert(b.get(1,0) == nil) +assert(b.get(1,1) == 0x01) +assert(b.get(1,2) == 0x0201) +assert(b.get(1,4) == 0x04030201) +assert(b.get(1,-1) == 0x01) +assert(b.get(1,-2) == 0x0102) #- big endian -# +assert(b.get(1,-4) == 0x01020304) + +#- resize -# +assert(bytes().size() == 0) +b=bytes("112233") +b.resize(2) +assert(str(b) == "bytes('1122')") +assert(b.size() == 2) +b.resize(4) +assert(str(b) == "bytes('11220000')") +assert(b.size() == 4) +b.resize(20) +assert(str(b) == "bytes('1122000000000000000000000000000000000000')") +assert(b.size() == 20) +b.resize(0) +assert(str(b) == "bytes('')") +assert(b.size() == 0) + +#- clear -# +b=bytes("aabb") +b.clear() +assert(str(b) == "bytes('')") + +#- == != -# +assert(bytes() == bytes()) +assert(bytes("11") == bytes("11")) +assert(bytes("11") == bytes()..0x11) +assert(! (bytes("11") == bytes(0x12)) ) +assert(! (bytes("11") == 0x11) ) +assert(! (bytes("11") != bytes("11")) ) +assert(bytes("11") != bytes("1122")) +assert(bytes("11") != bytes("12")) +assert(bytes("11") != bytes()) + +#- + -# +b1 = bytes("1122") +b2 = bytes("334455") +b = b1 + b2 +assert(str(b1) == "bytes('1122')") +assert(str(b2) == "bytes('334455')") +assert(str(b) == "bytes('1122334455')") +b = b2 + b1 +assert(str(b) == "bytes('3344551122')") + +#- .. -# +b1 = bytes("1122") +b2 = bytes("334455") +b = b1..b2 +assert(str(b1) == "bytes('1122334455')") +assert(str(b2) == "bytes('334455')") +assert(str(b) == "bytes('1122334455')") + +#- item -# +b = bytes("334455") +assert(b[0] == 0x33) +assert(b[1] == 0x44) +assert(b[2] == 0x55) + +#- item range -# +b = bytes("00112233445566778899AABBCCDDEEFF") +assert(str(b[1..1]) =="bytes('11')") +assert(str(b[-11..1]) =="bytes('0011')") +assert(str(b[0..40]) =="bytes('00112233445566778899AABBCCDDEEFF')") +assert(str(b[1..0]) =="bytes('')") + +#- copy -# +b=bytes("112233") +b2=b.copy() +assert(str(b) =="bytes('112233')") +assert(str(b2) =="bytes('112233')") +b2.clear() +assert(str(b) =="bytes('112233')") +assert(str(b2) =="bytes('')") + +#- setitem -# +b=bytes("112233") +assert(str(b) =="bytes('112233')") +b[1]=0xAA +assert(str(b) =="bytes('11AA33')") +b[0]=0xBB +assert(str(b) =="bytes('BBAA33')") +b[2]=-1 +assert(str(b) =="bytes('BBAAFF')") + +#- resize -# +b=bytes() +b.resize(20) +assert(str(b) =="bytes('0000000000000000000000000000000000000000')") +b2=b.copy() +assert(str(b2) =="bytes('0000000000000000000000000000000000000000')") + +#- asstring -# +b=bytes() +assert(b.asstring() == '') +b=bytes("334455") +assert(b.asstring() == '3DU') +b=bytes("33456502") +assert(b.asstring() == '3Ee\x02') + +#- fromstring -# +b=bytes() +b.fromstring("Aa0") +assert(str(b) =="bytes('416130')") +b=bytes() +b.fromstring("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") +assert(str(b) =="bytes('4C6F72656D20697073756D20646F6C6F722073697420616D65742C20636F6E73656374657475722061646970697363696E6720656C69742C2073656420646F20656975736D6F642074656D706F7220696E6369646964756E74207574206C61626F726520657420646F6C6F7265206D61676E6120616C697175612E')") diff --git a/lib/libesp32/Berry/tests/checkspace.be b/lib/libesp32/Berry/tests/checkspace.be new file mode 100644 index 000000000..f4079d952 --- /dev/null +++ b/lib/libesp32/Berry/tests/checkspace.be @@ -0,0 +1,35 @@ +import os + +def strfind(str, char) + var len = size(str) + for i : 0 .. len - 1 + if str[i] == char + return true + end + end + return false +end + +def checkfile(path) + var subname = os.path.splitext(path)[1] + if (subname == '.c' || subname == '.h' || + subname == '.cpp' || subname == '.be' || subname == '.json') + var f = open(path) + assert(!strfind(f.read(), '\t'), 'file \'' + path + '\' has tab character') + f.close() + end +end + +def findpath(path) + var ls = os.listdir(path) + for name : ls + var fullname = os.path.join(path, name) + if os.path.isfile(fullname) + checkfile(fullname) + elif fullname != '.' && fullname != '..' + findpath(fullname) + end + end +end + +findpath('.') diff --git a/lib/libesp32/Berry/tests/class.be b/lib/libesp32/Berry/tests/class.be new file mode 100644 index 000000000..fb310e802 --- /dev/null +++ b/lib/libesp32/Berry/tests/class.be @@ -0,0 +1,22 @@ +class Test + var maximum + def init(maximum) + self.maximum = maximum + end + def iter() # method closure upvalues test + var i = -1, maximum = self.maximum + return def () + i += 1 + if i > maximum + raise 'stop_iteration' + end + return i + end + end +end + +var sum = 0 +for i : Test(10) + sum += i +end +assert(sum == 55, 'iteraion sum is ' + str(sum) + ' (expected 55).') diff --git a/lib/libesp32/Berry/tests/cond_expr.be b/lib/libesp32/Berry/tests/cond_expr.be new file mode 100644 index 000000000..dc70fd306 --- /dev/null +++ b/lib/libesp32/Berry/tests/cond_expr.be @@ -0,0 +1,10 @@ +assert("" != 0 ? true : false) +assert(false || !(true ? false : true) && true) +var t1 = 8, t2 = false +if t1 ? 7 + t1 : t2 + var a = 'good' + assert((a == 'good' ? a + '!' : a) == 'good!') + assert((a == 'good?' ? a + '!' : a) != 'good!') +else + assert('condition expression test failed') +end diff --git a/lib/libesp32/Berry/tests/debug.be b/lib/libesp32/Berry/tests/debug.be new file mode 100644 index 000000000..9e732f6c3 --- /dev/null +++ b/lib/libesp32/Berry/tests/debug.be @@ -0,0 +1,4 @@ +import debug + +class A end +debug.attrdump(A) #- should not crash -# \ No newline at end of file diff --git a/lib/libesp32/Berry/tests/for.be b/lib/libesp32/Berry/tests/for.be new file mode 100644 index 000000000..ec4a910cd --- /dev/null +++ b/lib/libesp32/Berry/tests/for.be @@ -0,0 +1,44 @@ +var global + +global = 0 +for i : 0 .. 10 + global += i +end +assert(global == 55) + +global = 0 +for i : 0 .. 20 + if i > 10 + break + end + global += i +end +assert(global == 55) + +global = 0 +for i : 0 .. 20 + if i > 10 + continue + end + global += i +end +assert(global == 55) + +assert(def () + for i : 0 .. 20 + if i > 10 + return i + end + end + end() == 11) + +# test for "stop_iteration" exception as recurrence +def for_rec(depth) + for i : 0 .. 10 + if i == 4 && depth < 200 + for_rec(depth + 1) + end + end +end + +for_rec(0) diff --git a/lib/libesp32/Berry/tests/function.be b/lib/libesp32/Berry/tests/function.be new file mode 100644 index 000000000..81310408b --- /dev/null +++ b/lib/libesp32/Berry/tests/function.be @@ -0,0 +1,12 @@ +# CLOSE opcode test +var gbl +def func1() + var a = 'func1_a' + def func2() + return a + end + gbl = func2 + return 400000 + 500 +end +assert(func1() == 400500) +assert(gbl() == 'func1_a') diff --git a/lib/libesp32/Berry/tests/json.be b/lib/libesp32/Berry/tests/json.be new file mode 100644 index 000000000..ee009755b --- /dev/null +++ b/lib/libesp32/Berry/tests/json.be @@ -0,0 +1,53 @@ +import json + +# load tests + +def assert_load(text, value) + assert(json.load(text) == value) +end + +def assert_load_failed(text) + assert(json.load(text) == nil) +end + +assert_load('null', nil) +assert_load('true', true) +assert_load('false', false) +assert_load('123', 123) +assert_load('12.3', 12.3) +assert_load('"abc"', 'abc') +# strings +assert_load('"\\"\\\\\\/\\b\\f\\n\\r\\t"', '\"\\/\b\f\n\r\t') +assert_load('"\\u1234\\u2345\\u04aF\\u003A"', 'ሴ⍅ү:') +assert_load_failed('"\\u3fr"'); +assert_load_failed('"\\q"'); +assert_load_failed('"123'); +# list +assert_load('[1, null]', [1, nil]) +assert_load_failed('[x]') +assert_load_failed('[1, nil]') +assert_load_failed('[1, null') +# object +var o = json.load('{"key": 1}') +assert(o['key'] == 1 && o.size() == 1) +assert_load_failed('{"ke: 1}') +assert_load_failed('{"key": 1x}') +assert_load_failed('{"key"}') +assert_load_failed('{"key": 1, }') + +# dump tests + +def assert_dump(value, text, format) + assert(json.dump(value, format) == text) +end + +assert_dump(nil, 'null'); +assert_dump(true, 'true'); +assert_dump(false, 'false'); +assert_dump(1.23, '1.23'); +assert_dump('String', '"String"'); +assert_dump([1, 'x'], '[1,"x"]'); +assert_dump({1: 'x'}, '{"1":"x"}'); +assert_dump([1, 'x'], '[\n 1,\n "x"\n]', 'format'); +assert_dump({1: 'x'}, '{\n "1": "x"\n}', 'format'); +assert_dump({1: 'x', 'k': 'v'}, '{"k":"v","1":"x"}'); diff --git a/lib/libesp32/Berry/tests/lexer.be b/lib/libesp32/Berry/tests/lexer.be new file mode 100644 index 000000000..3dc34169d --- /dev/null +++ b/lib/libesp32/Berry/tests/lexer.be @@ -0,0 +1,62 @@ +import math + +def check(a, b) + assert(math.abs(a - b) < 1e-6) +end + +def test_source(src, msg) + try + compile(src) + assert(false, 'unexpected execution flow') + except .. as e, m + assert(e == 'syntax_error') + assert(m == 'string:1: ' + msg) + end +end + +#---- + this is a + mult-line comment +----# + +compile('x = 5; 0..x') +assert('\x5a' == 'Z') +assert('\132' == 'Z') +assert('\a\b\f\n\r\t\v\\\'\"\?' == '\x07\x08\x0c\x0a\x0d\x09\x0b\x5c\x27\x22\x3f') +assert(.45 == 0.45) +assert(0X10 == 16) +assert(0x10 == 16) +assert(0X1A == 26) +assert(0x1a == 26) +check(45., 45) +check(45.e-1, 4.5) +check(45.E-1, 4.5) +check(45.1e-1, 4.51) +check(45.1e2, 4510) +check(45.e2, 4500) +check(45.e+2, 4500) + +test_source('x = 5; 0...x;', 'unexpected symbol near \'.\'') +test_source('x = 5; 0...x;', 'unexpected symbol near \'.\'') +test_source('45..', 'unexpected symbol near \'EOS\'') +test_source('0xg', 'invalid hexadecimal number') +test_source('"\\x5g"', 'invalid hexadecimal number') +test_source('0x5g', 'malformed number') +test_source('"\\779"', 'invalid octal number') +test_source('"\n', 'unfinished string') + +var malformed_numbers = [ + '45f', + '45.f', + '45.ef', + '45.e-f', + '45.e-1f', + '45.e-1.', + '45.5.', + '0x45.', + '0x45j' +] + +for i : malformed_numbers + test_source(i, 'malformed number') +end diff --git a/lib/libesp32/Berry/tests/list.be b/lib/libesp32/Berry/tests/list.be new file mode 100644 index 000000000..a6ec7ecc7 --- /dev/null +++ b/lib/libesp32/Berry/tests/list.be @@ -0,0 +1,74 @@ +l = [1, 2, 3, 4, 5] +assert(l[0] == 1) +assert(l[1] == 2) +assert(l[2] == 3) +assert(l[3] == 4) +assert(l[4] == 5) +assert(str(l) == '[1, 2, 3, 4, 5]') + +it = l.iter() +assert(it() == 1) +assert(it() == 2) +assert(it() == 3) +assert(it() == 4) +assert(it() == 5) + +l.insert(0, 10) +assert(l[0] == 10) +assert(l.size() == 6) +l.remove(0) +assert(l.size() == 5) +assert(l[0] == 1) +l.setitem(0, 42) +assert(l[0] == 42) +assert(l.item(2) == 3) +l.resize(10) +assert(l.size() == 10) +assert(l.tostring() == '[42, 2, 3, 4, 5, nil, nil, nil, nil, nil]') + +assert(([] == []) == true) +assert(([] != []) == false) +assert(([1] == [1]) == true) +assert(([1] != [1]) == false) +assert(([1] == [0]) == false) +assert(([1] != [0]) == true) +assert(([1, 2, 3] == [1, 2, 3]) == true) +assert(([1, 2, 3] != [1, 2, 3]) == false) +assert(([1, 2, 3] == [1, 2, 4]) == false) +assert(([1, 2, 3] != [1, 2, 4]) == true) +assert(([1, 2, ['w']] == [1, 2, ['w']]) == true) +assert(([1, 2, ['w']] != [1, 2, ['w']]) == false) +assert(([1, 2, ['w']] == [1, 2, ['z']]) == false) +assert(([1, 2, ['w']] != [1, 2, ['z']]) == true) +assert(([1, 2, ['w']] == [1, 2, []]) == false) +assert(([1, 2, ['w']] != [1, 2, []]) == true) + +var l = [0, 1, 2, 3] +assert(l[-1] == 3) +assert(l[-2] == 2) +var t = l.copy() +l.insert(-2, 4) +assert(t == [0, 1, 2, 3] && t != l) +assert(l == [0, 1, 4, 2, 3]) +l.remove(-2) +assert(l == [0, 1, 4, 3]) +assert(l.reverse() == [3, 4, 1, 0]) +assert(l + [5, 6] == [3, 4, 1, 0, 5, 6]) +l = [0] +assert(l .. '3' == [0, '3']) +l.push(1) +assert(l == [0, '3', 1]) +assert(l.concat() == '031') +l.pop() +assert(l == [0, '3']) +l.pop(0) +assert(l == ['3']) + +l1 = [0, 1] +l2 = [2, 3] +assert(l1+l2==[0, 1, 2, 3]) +assert(l1 == [0, 1]) +assert(l2 == [2, 3]) +assert(l1+[2] == [0, 1, 2]) +assert([-1]+l1 == [-1, 0, 1]) +assert(l1 == [0, 1]) diff --git a/lib/libesp32/Berry/tests/os.be b/lib/libesp32/Berry/tests/os.be new file mode 100644 index 000000000..37811bef1 --- /dev/null +++ b/lib/libesp32/Berry/tests/os.be @@ -0,0 +1,51 @@ +import os + +# os.path.join test +assert(os.path.join('') == '') +assert(os.path.join('abc', 'de') == 'abc/de') +assert(os.path.join('abc', '/de') == '/de') +assert(os.path.join('a', 'de') == 'a/de') +assert(os.path.join('abc/', 'de') == 'abc/de') +assert(os.path.join('abc', 'de', '') == 'abc/de/') +assert(os.path.join('abc', '', '', 'de') == 'abc/de') +assert(os.path.join('abc', '/de', 'fghij') == '/de/fghij') +assert(os.path.join('abc', 'xyz', '/de', 'fghij') == '/de/fghij') + +# os.path.split test +def split(str, list) + var res = os.path.split(str) + assert(res[0] == list[0] && res[1] == list[1], + 'unexpected results: ' .. res .. ', reference value: ' .. list) +end + +split('/', ['/', '']) +split('//', ['//', '']) +split('///', ['///', '']) +split('a/', ['a', '']) +split('a//', ['a', '']) +split('a/b/c', ['a/b', 'c']) +split('a/b/', ['a/b', '']) +split('a//b//', ['a//b', '']) +split('a/../b', ['a/..', 'b']) +split('abcd////ef/////', ['abcd////ef', '']) +split('abcd////ef', ['abcd', 'ef']) + +# os.path.splitext test +def splitext(str, list) + var res = os.path.splitext(str) + assert(res[0] == list[0] && res[1] == list[1], + 'unexpected results: ' .. res .. ', reference value: ' .. list) +end + +splitext('a.b', ['a', '.b']) +splitext('a..b', ['a.', '.b']) +splitext('/a..b', ['/a.', '.b']) +splitext('/.b', ['/.b', '']) +splitext('/..b', ['/..b', '']) +splitext('..b', ['..b', '']) +splitext('...b', ['...b', '']) +splitext('.b', ['.b', '']) +splitext('ac..b', ['ac.', '.b']) +splitext('ac.b', ['ac', '.b']) +splitext('ac/.b', ['ac/.b', '']) +splitext('ac/..b', ['ac/..b', '']) diff --git a/lib/libesp32/Berry/tests/overload.be b/lib/libesp32/Berry/tests/overload.be new file mode 100644 index 000000000..a9e72081b --- /dev/null +++ b/lib/libesp32/Berry/tests/overload.be @@ -0,0 +1,14 @@ +class test + def init() + self._a = 123 + end + def +() + return self._a + end + def ()() + return self._a + end + var _a +end + +print(test() + test()) diff --git a/lib/libesp32/Berry/tests/relop.be b/lib/libesp32/Berry/tests/relop.be new file mode 100644 index 000000000..a9a9805f1 --- /dev/null +++ b/lib/libesp32/Berry/tests/relop.be @@ -0,0 +1,40 @@ +def assert_true(status) + assert(status == true, 'assert(true) failed!') +end + +def assert_false(status) + assert(status == false, 'assert(false) failed!') +end + +assert_true(0 == 0) +assert_false(0 != 0) +assert_true(0 != 1) +assert_false(0 == 1) + + +assert_true(0.0 == 0) +assert_false(0.0 != 0) +assert_true(0.0 != 1.0) +assert_false(0.0 == 1.0) + +assert_true(nil == nil) +assert_false(nil != nil) +assert_true(true != nil) +assert_false(true == nil) +assert_true(nil != false) +assert_false(nil == false) + +assert_true(list == list) +assert_false(list == map) + +assert_true([] == []) +assert_true([true] == [true]) +assert_true([[]] == [[]]) +assert_false([[]] != [[]]) +assert_false([0] == []) +assert_false([] != []) +assert_true([] != nil) +assert_false([] == nil) + +assert_true({} != nil) +assert_false({} == nil) diff --git a/lib/libesp32/Berry/tests/string.be b/lib/libesp32/Berry/tests/string.be new file mode 100644 index 000000000..fad58f935 --- /dev/null +++ b/lib/libesp32/Berry/tests/string.be @@ -0,0 +1,30 @@ +import string as s + +assert(s.find('012345', '23') == 2) +assert(s.find('012345', '23', 1) == 2) +assert(s.find('012345', '23', 1, 3) == -1) +assert(s.find('012345', '23', 2, 4) == 2) +assert(s.find('012345', '23', 3) == -1) + +assert(s.find('012345', '') == 0) +assert(s.find('012345', '', 0, 0) == 0) +assert(s.find('012345', '', 1) == 1) +assert(s.find('012345', '', 1, 1) == 1) +assert(s.find('012345', '', 1, 0) == -1) +assert(s.find('012345', '', 6) == 6) +assert(s.find('012345', '', 7) == -1) + +assert(s.count('012345', '') == 7) +assert(s.count('012345', '', 2) == 5) +assert(s.count('012345', '', 6) == 1) + +assert(s.count('121314', '1') == 3) +assert(s.count('121314', '1', 1) == 2) +assert(s.count('121314', '1', 2) == 2) +assert(s.count('121314', '1', 1, 2) == 0) +assert(s.count('121314', '1', 1, 3) == 1) + +assert(s.split('a b c d e f', '1') == ['a b c d e f']) +assert(s.split('a b c d e f', ' ') == ['a', 'b', 'c', 'd', 'e', 'f']) +assert(s.split('a b c d e f', ' ', 2) == ['a', 'b', 'c d e f']) +assert(s.split('a b c d e f', '') == ['a b c d e f']) diff --git a/lib/libesp32/Berry/tests/subobject.be b/lib/libesp32/Berry/tests/subobject.be new file mode 100644 index 000000000..010e8af29 --- /dev/null +++ b/lib/libesp32/Berry/tests/subobject.be @@ -0,0 +1,29 @@ +class mylist : classof([]) end + +assert(issubclass(mylist, list) == true) +assert(issubclass(mylist, []) == true) +assert(issubclass(mylist(), list) == false) +assert(issubclass(mylist(), []) == false) + +assert(isinstance(mylist, list) == false) +assert(isinstance(mylist, []) == false) +assert(isinstance(mylist(), list) == true) +assert(isinstance(mylist(), []) == true) + +assert(issubclass(list, list) == true) +assert(issubclass(list, []) == true) +assert(issubclass(list(), list) == false) +assert(issubclass(list(), []) == false) + +assert(isinstance(list, list) == false) +assert(isinstance(list, []) == false) +assert(isinstance(list(), list) == true) +assert(isinstance(list(), []) == true) + +assert(issubclass(list, list) == true) +assert(issubclass(list, []) == true) +assert(issubclass(list(), list) == false) +assert(issubclass(list(), []) == false) + +assert(issubclass(list, mylist) == false) +assert(isinstance([], mylist) == false) diff --git a/lib/libesp32/Berry/tests/suffix.be b/lib/libesp32/Berry/tests/suffix.be new file mode 100644 index 000000000..222b092d8 --- /dev/null +++ b/lib/libesp32/Berry/tests/suffix.be @@ -0,0 +1,11 @@ +var keys = [ 'key1', 'key2', 'key3', 'key4' ] +var pairs = { + keys[0]: 'value1', + keys[1]: 'value2', + keys[2]: 'value3', + keys[3]: 'value4' +} + +for i : 0 .. keys.size() - 1 + assert(pairs[keys[i]] == 'value' .. i + 1) +end diff --git a/lib/libesp32/Berry/tools/coc/.gitignore b/lib/libesp32/Berry/tools/coc/.gitignore new file mode 100644 index 000000000..be1fbe796 --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/.gitignore @@ -0,0 +1 @@ +coc diff --git a/lib/libesp32/Berry/tools/coc/Makefile b/lib/libesp32/Berry/tools/coc/Makefile new file mode 100644 index 000000000..773994b3c --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/Makefile @@ -0,0 +1,26 @@ +TARGET = coc +CXXFLAGS = -std=c++11 -O2 +CXX = g++ + +OBJS = coc_string.o \ + hash_map.o \ + macro_table.o \ + main.o \ + block_builder.o \ + str_build.o \ + coc_parser.o + +ifeq ($(OS), Windows_NT) # Windows + TARGET := $(TARGET).exe +endif + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(Q) $(CXX) $(OBJS) -o $@ + +$(OBJS): %.o: %.cpp + $(Q) $(CXX) $(CXXFLAGS) -c $< -o $@ + +clean: + $(Q) $(RM) $(OBJS) diff --git a/lib/libesp32/Berry/tools/coc/REEADME.md b/lib/libesp32/Berry/tools/coc/REEADME.md new file mode 100644 index 000000000..329c66d46 --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/REEADME.md @@ -0,0 +1,3 @@ +# The Constant Object Compiler (coc) + +The constant object compiler (coc) is a C preprocessor that generates the corresponding C99 code based on the constant object declaration block. diff --git a/lib/libesp32/Berry/tools/coc/block_builder.cpp b/lib/libesp32/Berry/tools/coc/block_builder.cpp new file mode 100755 index 000000000..eecf9fd8e --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/block_builder.cpp @@ -0,0 +1,197 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#include "block_builder.h" +#include "hash_map.h" +#include "macro_table.h" +#include "object_block.h" +#include +#include + +static bool depend(const object_block *object, const macro_table *macro) +{ + auto it = object->attr.find("depend"); + if (it != object->attr.end()) { + return macro->query(it->second); + } + return true; +} + +block_builder::block_builder(const object_block *object, const macro_table *macro) +{ + m_block.name = object->name; + if (depend(object, macro)) { + m_block.type = object->type; + m_block.attr = object->attr; + for (auto i : object->data) { + if (i.second.depend.empty() || macro->query(i.second.depend)) { + m_block.data[i.first] = i.second.value; + m_strtab.push_back(i.first); + } + } + } +} + +std::string block_builder::block_tostring(const block &block) +{ + std::ostringstream ostr; + if (block.type == "map") { + ostr << map_tostring(block, block.name); + } else if (block.type == "class") { + ostr << class_tostring(block); + } else if (block.type == "vartab") { + ostr << vartab_tostring(block); + } else if (block.type == "module") { + ostr << module_tostring(block); + } + return ostr.str(); +} + +std::string block_builder::class_tostring(const block &block) +{ + bool empty_map = block.data.empty(); + std::ostringstream ostr; + hash_map map(block.data); + std::string map_name(block.name + "_map"); + + if (!empty_map) { + ostr << map_tostring(block, map_name, true) << std::endl; + } + ostr << scope(block) << " be_define_const_class(\n " + << block.name << ",\n " + << map.var_count() << ",\n " + << super(block) << ",\n " + << name(block) << "\n" + ");" << std::endl; + return ostr.str(); +} + +std::string block_builder::map_tostring(const block &block, const std::string &name, bool local) +{ + std::ostringstream ostr; + hash_map map(block.data); + + hash_map::entry_table list = map.entry_list(); + ostr << "static be_define_const_map_slots(" << name << ") {\n"; + for (auto it : list) { + ostr << " { be_const_key(" << it.key << ", " + << it.next << "), " << it.value << " }," << std::endl; + } + ostr << "};\n\n"; + + ostr << (local ? "static" : scope(block)) + << " be_define_const_map(\n " + << name << ",\n " + << list.size() << "\n" + ");" << std::endl; + return ostr.str(); +} + +std::string block_builder::vartab_tostring(const block &block) +{ + std::ostringstream ostr; + struct block idxblk; + std::vector varvec; + int index = 0; + + idxblk = block; + idxblk.data.clear(); + for (auto it : block.data) { + varvec.push_back(it.second); + it.second = "int(" + std::to_string(index++) + ")"; + idxblk.data.insert(it); + } + + ostr << map_tostring(idxblk, block.name + "_map", true) << std::endl; + ostr << "static const bvalue __vlist_array[] = {\n"; + for (auto it : varvec) { + ostr << " be_const_" << it << "," << std::endl; + } + ostr << "};\n\n"; + + ostr << "static be_define_const_vector(\n " + << block.name << "_vector,\n " + "__vlist_array,\n " + << varvec.size() << "\n" + ");" << std::endl; + return ostr.str(); +} + +std::string block_builder::module_tostring(const block &block) +{ + std::ostringstream ostr; + std::string name("m_lib" + block.name); + std::string map_name(name + "_map"); + + ostr << map_tostring(block, map_name, true) << std::endl + << "static be_define_const_module(\n " + << name << ",\n " + "\"" << block.name << "\"\n" + ");" << std::endl; + std::string scp = scope(block); + if (scp != "static") { /* extern */ + ostr << "\n" << scp + << " be_define_const_native_module(" + << block.name << ", " + << init(block) << ");" << std::endl; + } + return ostr.str(); +} + +std::string block_builder::scope(const block &block) +{ + auto it = block.attr.find("scope"); + return it != block.attr.end() && it->second == "local" ? + "static" : "BE_EXPORT_VARIABLE"; +} + +std::string block_builder::super(const block &block) +{ + auto it = block.attr.find("super"); + return it == block.attr.end() ? "NULL" : "(bclass *)&" + it->second; +} + +std::string block_builder::name(const block &block) +{ + auto it = block.attr.find("name"); + return it == block.attr.end() ? block.name : it->second; +} + +std::string block_builder::init(const block &block) +{ + auto it = block.attr.find("init"); + return it == block.attr.end() ? "NULL" : it->second; +} + +void block_builder::writefile(const std::string &filename, const std::string &text) +{ + std::string pathname(filename); + std::string otext("#include \"be_constobj.h\"\n\n" + text); + + std::ostringstream buf; + std::ifstream fin(pathname); + buf << fin.rdbuf(); + if (buf.str() != otext) { + std::ofstream fout; + fout.open(pathname, std::ios::out); + fout << otext; + fout.close(); + } +} + +void block_builder::dumpfile(const std::string &path) +{ + std::string s = block_tostring(m_block); + auto it = m_block.attr.find("file"); + std::string &name = it != m_block.attr.end() ? it->second : m_block.name; + writefile(path + "/be_fixed_" + name + ".h", s); +} + +const std::vector& block_builder::strtab() const +{ + return m_strtab; +} diff --git a/lib/libesp32/Berry/tools/coc/block_builder.h b/lib/libesp32/Berry/tools/coc/block_builder.h new file mode 100755 index 000000000..7eb82bd3e --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/block_builder.h @@ -0,0 +1,49 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#ifndef __BLOCK_BUILDER_H +#define __BLOCK_BUILDER_H + +#include +#include +#include +#include "object_block.h" + +class macro_table; +class object_block; + +class block_builder { +public: + block_builder(const object_block *object, const macro_table *macro); + void dumpfile(const std::string &path); + const std::vector& strtab() const; + +private: + struct block { + std::string type; + std::string name; + std::map attr; + std::map data; + }; + + std::string block_tostring(const block &block); + std::string class_tostring(const block &block); + std::string vartab_tostring(const block &block); + std::string module_tostring(const block &block); + std::string map_tostring(const block &block, const std::string &name, bool local = false); + std::string scope(const block &block); + std::string super(const block &block); + std::string name(const block &block); + std::string init(const block &block); + void writefile(const std::string &filename, const std::string &text); + +private: + block m_block; + std::vector m_strtab; +}; + +#endif // !__BLOCK_BUILDER_H diff --git a/lib/libesp32/Berry/tools/coc/coc_parser.cpp b/lib/libesp32/Berry/tools/coc/coc_parser.cpp new file mode 100644 index 000000000..f1e86ecb5 --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/coc_parser.cpp @@ -0,0 +1,189 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#include "coc_parser.h" +#include + +static inline int _isalnum(int c) +{ + return isalnum(c) || c == '_'; +} + +coc_parser::coc_parser(const std::string &text) +{ + m_ptr = text.c_str(); + while (*m_ptr) { + switch (*m_ptr) { + case '@': + parse_object(); + break; + case 'b': + scan_const_string(); + break; + default: + ++m_ptr; + } + } +} + +const std::vector& coc_parser::objects() const +{ + return m_objects; +} + +const std::vector& coc_parser::strtab() const +{ + return m_strtab; +} + +void coc_parser::scan_const_string() +{ + const char prefix[] = "be_const_str_"; + const size_t len = sizeof(prefix) - 1; + if (!strncmp(m_ptr, prefix, len)) { + m_ptr += len; + const char *p = m_ptr; + while (_isalnum(*m_ptr)) + ++m_ptr; + m_strtab.push_back(std::string(p, m_ptr - p)); + } else { + ++m_ptr; + } +} + +void coc_parser::skip_space() +{ + while (isspace(*m_ptr)) + ++m_ptr; +} + +bool coc_parser::parse_char_base(int c, bool necessary) +{ + bool res = *m_ptr == c; + if (!res && necessary) + throw "error"; + if (res) + ++m_ptr; + return res; +} + +bool coc_parser::parse_char(int c, bool necessary) +{ + skip_space(); + return parse_char_base(c, necessary); +} + +bool coc_parser::parse_char_continue(int c, bool necessary) +{ + int ch; + while (((ch = *m_ptr) == ' ') || ch == '\t') + ++m_ptr; + return parse_char_base(c, necessary); +} + +std::string coc_parser::parse_word() +{ + skip_space(); + const char *p = m_ptr; + if (_isalnum(*m_ptr)) { + while (_isalnum(*(++m_ptr))); + return std::string(p, m_ptr - p); + } + throw "error"; +} + +std::string coc_parser::parse_tocomma() +{ + int c; + skip_space(); + const char *p = m_ptr; + while (((c = *m_ptr) != ',') && !isspace(c)) + ++m_ptr; + if (p == m_ptr) + throw "error"; + return std::string(p, m_ptr - p); +} + +std::string coc_parser::parse_tonewline() +{ + int c; + skip_space(); + const char *p = m_ptr; + while (((c = *m_ptr) != '\r') && c != '\n') + ++m_ptr; + if (p == m_ptr) + throw "error"; + return std::string(p, m_ptr - p); +} + +void coc_parser::parse_object() +{ + const char begin_text[] = "@const_object_info_begin"; + const size_t begin_len = sizeof(begin_text) - 1; + if (!strncmp(m_ptr, begin_text, begin_len)) { + m_ptr += begin_len; + do { + object_block object; + parse_block(&object); + m_objects.push_back(object); + } while (!parse_char('@')); + const char end_text[] = "const_object_info_end"; + const size_t end_len = sizeof(end_text) - 1; + if (strncmp(m_ptr, end_text, end_len)) + throw "error"; + m_ptr += end_len; + } else { + ++m_ptr; + } +} + +void coc_parser::parse_block(object_block *object) +{ + object->type = parse_word(); + object->name = parse_word(); + parse_attr(object); + parse_body(object); +} + +void coc_parser::parse_attr(object_block *object) +{ + skip_char('('); + parse_attr_pair(object); + while (parse_char(',')) { + parse_attr_pair(object); + } + skip_char(')'); +} + +void coc_parser::parse_attr_pair(object_block *object) +{ + std::string key = parse_word(); + skip_char(':'); + std::string value = parse_word(); + object->attr[key] = value; +} + +void coc_parser::parse_body(object_block *object) +{ + skip_char('{'); + if (!parse_char('}')) { + do { + parse_body_item(object); + } while (!parse_char('}')); + } +} + +void coc_parser::parse_body_item(object_block *object) +{ + object_block::data_value value; + std::string key = parse_tocomma(); + parse_char_continue(',', true); + value.value = parse_tocomma(); + if (parse_char_continue(',')) + value.depend = parse_tonewline(); + object->data[key] = value; +} diff --git a/lib/libesp32/Berry/tools/coc/coc_parser.h b/lib/libesp32/Berry/tools/coc/coc_parser.h new file mode 100644 index 000000000..b17a68a67 --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/coc_parser.h @@ -0,0 +1,46 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#ifndef __COC_PARSER_H +#define __COC_PARSER_H + +#include +#include +#include "object_block.h" + +class coc_parser { +public: + coc_parser(const std::string &text); + const std::vector& objects() const; + const std::vector& strtab() const; + +private: + void scan_const_string(); + void skip_space(); + void skip_char(int c) { + parse_char(c, true); + } + bool parse_char_base(int c, bool necessary); + bool parse_char(int c, bool necessary = false); + bool parse_char_continue(int c, bool necessary = false); + std::string parse_word(); + std::string parse_tocomma(); + std::string parse_tonewline(); + void parse_object(); + void parse_block(object_block *object); + void parse_attr(object_block *object); + void parse_attr_pair(object_block *object); + void parse_body(object_block *object); + void parse_body_item(object_block *object); + +private: + const char *m_ptr; + std::vector m_objects; + std::vector m_strtab; +}; + +#endif // !__COC_PARSER_H diff --git a/lib/libesp32/Berry/tools/coc/coc_string.cpp b/lib/libesp32/Berry/tools/coc/coc_string.cpp new file mode 100644 index 000000000..1ae9384ac --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/coc_string.cpp @@ -0,0 +1,48 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#include "coc_string.h" +#include + +namespace coc { + +uint32_t hashcode(const std::string &string) +{ + size_t len = string.size(); + const char *str = string.data(); + uint32_t hash = 2166136261u; + while (len--) + hash = (hash ^ (unsigned char)*str++) * 16777619u; + return hash; +} + +std::string escape_operator(const std::string &string) +{ + int c = string[0]; + if (string == "..") + return "opt_connect"; + if (c == '.') + return "dot_" + string.substr(1); + if (isalpha(c) || c == '_') + return string; + const static std::map tab = { + { "+", "opt_add" }, { "-", "opt_sub" }, + { "*", "opt_mul" }, { "/", "opt_div" }, + { "%", "opt_mod" }, { "&", "opt_and" }, + { "^", "opt_xor" }, { "|", "opt_or" }, + { "<", "opt_lt" }, { ">", "opt_gt" }, + { "<=", "opt_le" }, { ">=", "opt_ge" }, + { "==", "opt_eq" }, { "!=", "opt_neq" }, + { "<<", "opt_shl" }, { ">>", "opt_shr" }, + { "-*", "opt_neg" }, { "~", "opt_flip" }, + { "()", "opt_call" } + }; + auto it = tab.find(string); + return it != tab.end() ? it->second : string; +} + +} diff --git a/lib/libesp32/Berry/tools/coc/coc_string.h b/lib/libesp32/Berry/tools/coc/coc_string.h new file mode 100644 index 000000000..5fb63ce2c --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/coc_string.h @@ -0,0 +1,18 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#ifndef __COC_STRING_H +#define __COC_STRING_H + +#include + +namespace coc { + uint32_t hashcode(const std::string &string); + std::string escape_operator(const std::string &string); +} + +#endif diff --git a/lib/libesp32/Berry/tools/coc/hash_map.cpp b/lib/libesp32/Berry/tools/coc/hash_map.cpp new file mode 100755 index 000000000..988b8a03a --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/hash_map.cpp @@ -0,0 +1,161 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#include "hash_map.h" +#include "coc_string.h" + +#define is_empty(entry) ((entry).next == NODE_EMPTY) + +hash_map::hash_map() +{ + resize(2); +} + +hash_map::hash_map(std::map map) +{ + resize(2); + for (auto it : map) { + insert(it.first, it.second); + } +} + +hash_map::~hash_map() +{ +} + +void hash_map::resize(size_t size) +{ + entry_table bucket = m_bucket; + m_bucket.resize(size); + /* set all slot to empty */ + for (int i = 0; i < size; ++i) { + m_bucket[i].next = NODE_EMPTY; + } + m_lastfree = size - 1; + for (auto slot : bucket) { + if (!is_empty(slot)) { + insert_p(slot.key, slot.value); + } + } +} + +hash_map::entry* hash_map::findprev(entry *list, entry *slot) +{ + int next; + entry *prev = list; + for (;;) { + next = prev->next; + if (next == NODE_NULL || &m_bucket[next] == slot) { + break; + } + prev = &m_bucket[next]; + } + if (next == NODE_NULL) { + return NULL; + } + return prev; +} + +int hash_map::nextfree() +{ + while (m_lastfree >= 0) { + if (is_empty(m_bucket[m_lastfree])) { + return int(m_lastfree); + } + --m_lastfree; + } + return -1; +} + +hash_map::entry hash_map::find(const std::string &key) +{ + uint32_t hash = coc::hashcode(key); + entry null, *slot = &m_bucket[hash % m_bucket.size()]; + if (is_empty(*slot)) { + return null; + } + while (slot->key != key) { + if (slot->next == NODE_NULL) { + return null; + } + slot = &m_bucket[slot->next]; + } + return *slot; +} + +void hash_map::insert_p(const std::string &key, const std::string value) +{ + entry *slot = &m_bucket[coc::hashcode(key) % m_bucket.size()]; + if (is_empty(*slot)) { /* empty slot */ + slot->next = NODE_NULL; + } else { + int newidx = nextfree(); + /* get the main-slot index */ + entry *mainslot = &m_bucket[coc::hashcode(slot->key) % m_bucket.size()]; + entry *newslot = &m_bucket[newidx]; /* get a free slot index */ + if (mainslot == slot) { /* old is main slot */ + newslot->next = mainslot->next; + mainslot->next = newidx; + slot = newslot; + } else { /* link to list */ + entry *prev = findprev(mainslot, slot); + prev->next = newidx; /* link the previous node */ + *newslot = *slot; /* copy to new slot */ + slot->next = NODE_NULL; + } + } + slot->key = key; + slot->value = value; +} + +void hash_map::insert(const std::string &key, const std::string value) +{ + entry slot = find(key); + if (slot.next == NODE_EMPTY) { /* new entry */ + if (m_count >= m_bucket.size()) { + resize(m_bucket.size() * 2); + } + insert_p(key, value); + ++m_count; + } +} + +hash_map::entry hash_map::entry_modify(entry entry, int *var_count) +{ + entry.key = coc::escape_operator(entry.key); + if (entry.value == "var") { + entry.value = "be_const_int(" + + std::to_string(*var_count) + ")"; + ++(*var_count); + } else { + entry.value = "be_const_" + entry.value; + } + return entry; +} + +hash_map::entry_table hash_map::entry_list() +{ + entry_table list; + int var_count = 0; + + resize(m_count); + for (auto it : m_bucket) { + list.push_back(entry_modify(it, &var_count)); + } + return list; +} + +int hash_map::var_count() +{ + int count = 0; + + resize(m_count); + for (auto it : m_bucket) { + count += it.value == "var" ? 1 : 0; + } + return count; +} diff --git a/lib/libesp32/Berry/tools/coc/hash_map.h b/lib/libesp32/Berry/tools/coc/hash_map.h new file mode 100755 index 000000000..c1aca3e5b --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/hash_map.h @@ -0,0 +1,47 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#ifndef __HASH_MAP +#define __HASH_MAP + +#include +#include +#include + +#define NODE_EMPTY -2 +#define NODE_NULL -1 + +class hash_map { +public: + struct entry { + std::string key; + std::string value; + int next = NODE_EMPTY; + }; + typedef std::vector entry_table; + + hash_map(); + hash_map(std::map map); + ~hash_map(); + void insert(const std::string &key, const std::string value); + hash_map::entry find(const std::string &key); + entry_table entry_list(); + int var_count(); + +private: + int nextfree(); + hash_map::entry* findprev(entry *list, entry *slot); + void resize(size_t size); + void insert_p(const std::string &key, const std::string value); + hash_map::entry entry_modify(entry entry, int *var_count); + +private: + size_t m_count = 0, m_lastfree = 0; + entry_table m_bucket; +}; + +#endif // !__HASH_MAP diff --git a/lib/libesp32/Berry/tools/coc/macro_table.cpp b/lib/libesp32/Berry/tools/coc/macro_table.cpp new file mode 100644 index 000000000..ea6d7bea7 --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/macro_table.cpp @@ -0,0 +1,59 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#include "macro_table.h" +#include +#include +#include + +std::string macro_table::readfile(const std::string &filename) +{ + std::ifstream in(filename); + std::ostringstream tmp; + tmp << in.rdbuf(); + return tmp.str(); +} + +int macro_table::parse_value(std::string str) +{ + if (!str.length()) { + return 1; /* defined a macro name but no content, considered true */ + } + if (!(str[0] >= '0' && str[0] <= '9')) { + return 1; + } + return atoi(str.c_str()); +} + +void macro_table::scan_file(const std::string &filename) +{ + std::string str(readfile(filename)); + std::regex reg("(?:\\n|$)\\s*#define\\s+(\\w+)[ \\t]+(\\w+)"); + std::sregex_iterator it(str.begin(), str.end(), reg); + std::sregex_iterator end; + while (it != end) { + m_map[it->str(1)] = parse_value(it->str(2)); + ++it; + } +} + +bool macro_table::query(const std::string &str) const +{ + std::regex reg("(!?)(\\w+)"); + std::match_results res; + if (regex_match(str, res, reg)) { + auto it = m_map.find(res[2]); + int value = it == m_map.end() ? 0 : it->second; + return res[1] == "!" ? value == 0 : value != 0; + } + return 0; +} + +std::map macro_table::table() const +{ + return m_map; +} diff --git a/lib/libesp32/Berry/tools/coc/macro_table.h b/lib/libesp32/Berry/tools/coc/macro_table.h new file mode 100644 index 000000000..8999f63e6 --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/macro_table.h @@ -0,0 +1,30 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#ifndef __MACRO_TABLE_H +#define __MACRO_TABLE_H + +#include +#include +#include + +class macro_table { +public: + macro_table() {} + void scan_file(const std::string &filename); + bool query(const std::string &str) const; + std::map table() const; + +private: + std::string readfile(const std::string &filename); + int parse_value(std::string str); + +private: + std::map m_map; +}; + +#endif diff --git a/lib/libesp32/Berry/tools/coc/main.cpp b/lib/libesp32/Berry/tools/coc/main.cpp new file mode 100755 index 000000000..0b876ba65 --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/main.cpp @@ -0,0 +1,141 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#include "main.h" +#include "block_builder.h" +#include "coc_parser.h" +#include "macro_table.h" +#include "str_build.h" +#include +#include + +void builder::parse_all(const std::string &filename) +{ + size_t pos = filename.find_last_of("."); + std::string ext = pos < filename.size() ? filename.substr(pos) : ""; + if (ext == ".c" || ext == ".cc" || ext == ".cpp") { + std::string text = readfile(filename); + coc_parser parser(text); + push_strtab(parser.strtab()); + for (auto object : parser.objects()) { + block_builder builder(&object, m_macro); + push_strtab(builder.strtab()); + builder.dumpfile(m_output); + } + } +} + +void builder::push_strtab(const std::vector &list) +{ + for (auto s : list) + m_strmap[s] = 0; +} + +std::string builder::readfile(const std::string &filename) +{ + std::ifstream in(filename); + std::ostringstream tmp; + tmp << in.rdbuf(); + return tmp.str(); +} + +#ifndef _MSC_VER +#include +#include +#include +#else +#include +#include +#endif + +#ifndef _MSC_VER +void builder::scandir(const std::string &srcpath) +{ + DIR *dp; + struct dirent *ep; + dp = opendir(srcpath.data()); + if (dp != NULL) { + while ((ep = readdir(dp)) != NULL) { + std::string fname(ep->d_name); + parse_all(srcpath + "/" + fname); + } + closedir(dp); + } +} +#else +void builder::scandir(const std::string &srcpath) +{ + HANDLE find; + WIN32_FIND_DATA data; + find = FindFirstFile((srcpath + "/*").data(), &data); + if (find != INVALID_HANDLE_VALUE) { + do { + std::string fname(data.cFileName); + parse_all(srcpath + "/" + fname); + } while (FindNextFile(find, &data) != 0); + FindClose(find); + } +} +#endif + +void builder::build() +{ + for (auto it : m_input) { + scandir(it); + } + str_build sb(m_strmap); + sb.build(m_output); +} + +builder::builder(int argc, char **argv) +{ + m_state = Input; + for (int i = 1; i < argc; ++i) { + add_arg(argv[i]); + } + m_macro = new macro_table(); + for (auto it : m_config) { + m_macro->scan_file(it); + } +} + +builder::~builder() +{ + delete m_macro; +} + +void builder::add_arg(const std::string &arg) +{ + if (arg == "-i") { + m_state = Input; + } else if (arg == "-o") { + m_state = Output; + } else if (arg == "-c") { + m_state = Config; + } else { + switch (m_state) { + case Output: + m_output = arg; + break; + case Config: + m_config.push_back(arg); + break; + case Input: + default: + m_input.push_back(arg); + break; + } + m_state = Input; + } +} + +int main(int argc, char *argv[]) +{ + builder arg(argc, argv); + arg.build(); + return 0; +} diff --git a/lib/libesp32/Berry/tools/coc/main.h b/lib/libesp32/Berry/tools/coc/main.h new file mode 100644 index 000000000..bba65d533 --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/main.h @@ -0,0 +1,45 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#ifndef __MAIN_H +#define __MAIN_H + +#include +#include +#include + +class macro_table; + +class builder { +public: + builder(int argc, char **argv); + ~builder(); + void build(); + +private: + void push_strtab(const std::vector& list); + void add_arg(const std::string& arg); + std::string info_block(const std::string &text); + void parse_all(const std::string &filename); + void scandir(const std::string &srcpath); + std::string readfile(const std::string &filename); + +private: + enum arg_state { + Input, + Output, + Config + }; + std::string m_output; + std::vector m_input; + std::vector m_config; + arg_state m_state; + macro_table *m_macro; + std::map m_strmap; +}; + +#endif diff --git a/lib/libesp32/Berry/tools/coc/object_block.h b/lib/libesp32/Berry/tools/coc/object_block.h new file mode 100644 index 000000000..474545457 --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/object_block.h @@ -0,0 +1,25 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#ifndef __OBJECT_BLOCK_H +#define __OBJECT_BLOCK_H + +#include +#include + +struct object_block { + struct data_value { + std::string value; + std::string depend; + }; + std::string type; + std::string name; + std::map attr; + std::map data; +}; + +#endif diff --git a/lib/libesp32/Berry/tools/coc/str_build.cpp b/lib/libesp32/Berry/tools/coc/str_build.cpp new file mode 100644 index 000000000..affd5016e --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/str_build.cpp @@ -0,0 +1,129 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#include "str_build.h" +#include "coc_string.h" +#include +#include + +str_build::str_build(std::map map) +{ + size_t size = map.size() / 2; + m_count = map.size(); + m_hashtable.resize(size < 4 ? 4 : size); + for (auto it : map) { + make_ceil(it.first, it.second); + } + keywords(); +} + +str_build::~str_build() +{ +} + +void str_build::build(const std::string &path) +{ + std::string prefix(path + "/be_const_strtab"); + writefile(prefix + "_def.h", build_table_def()); + writefile(prefix + ".h", build_table_ext()); +} + +void str_build::keywords() +{ + const int opif = 50; /* note the definition in be_lexer.h */ + const static std::map tab = { + { "if", opif}, { "elif", opif + 1 }, + { "else", opif + 2 }, { "while", opif + 3 }, + { "for", opif + 4 }, { "def", opif + 5 }, + { "end", opif + 6 }, { "class", opif + 7 }, + { "break", opif + 8 }, { "continue", opif + 9 }, + { "return", opif + 10 }, { "true", opif + 11 }, + { "false", opif + 12 }, { "nil", opif + 13 }, + { "var", opif + 14 }, { "do", opif + 15 }, + { "import", opif + 16 }, { "as", opif + 17 }, + { "try", opif + 18 }, { "except", opif + 19 }, + { "raise", opif + 20 } + }; + for (auto it : tab) { + make_ceil(it.first, it.second); + } +} + +void str_build::make_ceil(const std::string &string, int extra) +{ + str_info info; + info.hash = coc::hashcode(string); + info.str = string; + info.extra = extra; + m_hashtable[info.hash % m_hashtable.size()].push_back(info); +} + +void str_build::writefile(const std::string &filename, const std::string &text) +{ + std::ostringstream buf; + std::ifstream fin(filename); + buf << fin.rdbuf(); + if (buf.str() != text) { + std::ofstream fout; + fout.open(filename, std::ios::out); + fout << text; + fout.close(); + } +} + +std::string str_build::build_table_def() +{ + std::ostringstream ostr; + for (auto bucket : m_hashtable) { + size_t size = bucket.size(); + for (size_t i = 0; i < size; ++i) { + str_info info = bucket[i]; + std::string node = coc::escape_operator(info.str); + std::string next = i < size - 1 ? + "&be_const_str_" + coc::escape_operator(bucket[i + 1].str) : + "NULL"; + ostr << "be_define_const_str(" + << node << ", \"" << info.str << "\", " + << info.hash << "u, " << info.extra << ", " + << info.str.size() << ", " << next << ");" + << std::endl; + } + } + ostr << std::endl; + ostr << "static const bstring* const m_string_table[] = {" << std::endl; + size_t size = m_hashtable.size(); + for (size_t i = 0; i < size; ++i) { + auto bucket = m_hashtable[i]; + if (bucket.size()) { + ostr << " (const bstring *)&be_const_str_" + << coc::escape_operator(bucket[0].str); + } else { + ostr << " NULL"; + } + ostr << (i < size - 1 ? "," : "") << std::endl; + } + ostr << "};" << std::endl << std::endl; + ostr << + "static const struct bconststrtab m_const_string_table = {\n" + " .size = " << size << ",\n" << + " .count = " << m_count << ",\n" << + " .table = m_string_table\n" << + "};" << std::endl; + return ostr.str(); +} + +std::string str_build::build_table_ext() +{ + std::ostringstream ostr; + for (auto bucket : m_hashtable) { + for (auto info : bucket) { + ostr << "extern const bcstring be_const_str_" + << coc::escape_operator(info.str) << ";" << std::endl; + } + } + return ostr.str(); +} diff --git a/lib/libesp32/Berry/tools/coc/str_build.h b/lib/libesp32/Berry/tools/coc/str_build.h new file mode 100644 index 000000000..3a3527409 --- /dev/null +++ b/lib/libesp32/Berry/tools/coc/str_build.h @@ -0,0 +1,39 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#ifndef __BUILD_MAP_H +#define __BUILD_MAP_H + +#include +#include +#include + +class str_build +{ +public: + str_build(std::map map); + ~str_build(); + void build(const std::string &path); + +private: + void keywords(); + void make_ceil(const std::string &string, int extra = 0); + std::string build_table_def(); + std::string build_table_ext(); + void writefile(const std::string &filename, const std::string &text); + +private: + struct str_info { + uint32_t hash; + std::string str; + int extra; + }; + size_t m_count; + std::vector< std::vector > m_hashtable; +}; + +#endif diff --git a/lib/libesp32/Berry/tools/grammar/berry.bytecode b/lib/libesp32/Berry/tools/grammar/berry.bytecode new file mode 100755 index 000000000..9e150635d --- /dev/null +++ b/lib/libesp32/Berry/tools/grammar/berry.bytecode @@ -0,0 +1,96 @@ +------------------------------------------------------------------------------- +-- the Berry's bytecode file structure (version 1) +-- +-- description +-- +-- a double dash ('--') start a line comment. +-- a: n means that the size of entity 'a' is 'n' bytes. +-- 'a: .n means that the size of entity 'a' is 'n' bits. +-- a: +-- b means that the entity 'a' is realized by the 'b' structure. +-- a: +-- b +-- c 'b' and 'c' are arranged in a compact order (one byte alignment). +-- [a] means that structure 'a' can be repeated 0 to any times. +-- [a](b) means that structure 'a' can be repeated 'b' times. +-- a | b means that the entity can be implemented by structure 'a' or 'b'. +-- a -> b is equivalent to 'a: +-- b'. +-- only the first entity is a file entity (the root). +------------------------------------------------------------------------------- + +bytecode_file: -- little endian + header + global_desc + main_function + +header: 8 + magic_number: 3 -- 0xbecdfe (berry code file) + version: 1 -- update with file structure definition + integer_size: .1 + float_size: .1 + -- reserved space + +main_function -> function + +global_desc: + builtin_count: 4 + global_count: 4 + global_name -> [ + string + ](global_count) + +function: + information: + function_name: + string + source: + string + argc: 1 -- arguments count + nstack: 1 -- number of stack size by this function + extra: 2 -- extra data + bytecode: + code_size: 4 + code_array -> [ -- bytecode array + instruction: 4 + ](code_size) + constant_table: + constant_count: 4 + [constant_value](constant_count) + proto_table: + proto_count: 4 + [function](proto_count) + upval_table: + upval_count: 1 + upvals -> [ + instack: 1 + index: 1 + ](upval_count) + debug_info: + -- reserved + +constant_value: + type: 1 -- type of value + integer | float | string | class + +string: + string_size: 2 + byte_array: string_size + +class: + class_name: + string + member_count: 4 -- number of member variables + method_count: 4 -- number of method + method_table -> [ + string -- method name + function -- method function body + ](method_count) + member_index_table -> [ + string -- member name + ](member_count) + +nil: 1 +boolean: 1 +integer: 4 or 8 +float: 4 or 8 diff --git a/lib/libesp32/Berry/tools/grammar/berry.ebnf b/lib/libesp32/Berry/tools/grammar/berry.ebnf new file mode 100644 index 000000000..dedf72a90 --- /dev/null +++ b/lib/libesp32/Berry/tools/grammar/berry.ebnf @@ -0,0 +1,45 @@ +(* program define *) +program = block; +(* block define *) +block = {statement}; +(* statement define *) +statement = class_stmt | func_stmt | var_stmt | if_stmt | while_stmt | + for_stmt | break_stmt | return_stmt | expr_stmt | import_stmt | + try_stmt | throw_stmt | ';'; +if_stmt = 'if' expr block {'elif' expr block} ['else' block] 'end'; +while_stmt = 'while' expr block 'end'; +for_stmt = 'for' ID ':' expr block 'end'; +break_stmt = 'break' | 'continue'; +return_stmt = 'return' [expr]; +(* function define statement *) +func_stmt = 'def' ID func_body; +func_body = '(' [arg_field {',' arg_field}] ')' block 'end'; +arg_field = ['*'] ID; +(* class define statement *) +class_stmt = 'class' ID [':' ID] class_block 'end'; +class_block = {'var' ID {',' ID} | func_stmt}; +import_stmt = 'import' (ID (['as' ID] | {',' ID}) | STRING 'as' ID); +(* exceptional handling statement *) +try_stmt = 'try' block except_block {except_block} 'end'; +except_block = except_stmt block; +except_stmt = 'except' (expr {',' expr} | '..') ['as' ID [',' ID]]; +throw_stmt = 'raise' expr [',' expr]; +(* variable define statement *) +var_stmt = 'var' ID ['=' expr] {',' ID ['=' expr]}; +(* expression define *) +expr_stmt = expr [assign_op expr]; +expr = suffix_expr | unop expr | expr binop expr | cond_expr; +cond_expr = expr '?' expr ':' expr; (* conditional expression *) +assign_op = '=' | '+=' | '-=' | '*=' | '/=' | + '%=' | '&=' | '|=' | '^=' | '<<=' | '>>='; +binop = '..' | '<' | '<=' | '==' | '!=' | '>' | '>=' | '||' | '&&' | + '<<' | '>>' | '&' | '|' | '^' | '+' | '-' | '*' | '/' | '%'; +unop = '-' | '!' | '~'; +suffix_expr = primary_expr {call_expr | ('.' ID) | '[' expr ']'}; +primary_expr = '(' expr ')' | simple_expr | list_expr | map_expr | anon_func | lambda_expr; +simple_expr = INTEGER | REAL | STRING | ID | 'true' | 'false' | 'nil'; +call_expr = '(' [expr {',' expr}] ')'; +list_expr = '[' {expr ','} [expr] ']'; +map_expr = '{' {expr ':' expr ','} [expr ':' expr] '}'; +anon_func = 'def' func_body; (* anonymous function *) +lambda_expr = '/' [arg_field {',' arg_field}] | {arg_field}] '->' expr; diff --git a/lib/libesp32/Berry/tools/grammar/const_obj.ebnf b/lib/libesp32/Berry/tools/grammar/const_obj.ebnf new file mode 100755 index 000000000..6c38a4262 --- /dev/null +++ b/lib/libesp32/Berry/tools/grammar/const_obj.ebnf @@ -0,0 +1,11 @@ +block = type name ['(' {attributes} ')'] '{' {data_fields} '}'; +type = 'map' | 'class' | 'module' | 'vartab'; + +attributes = name ':' name [',']; +data_fields = data_name ',' data_value [':' depend_macro] '\n'; + +(* regular expression *) +name = [_a-zA-Z]\w*; +data_name = [\._a-zA-Z]\w*; +data_value = [\w\()]+; +depend_macro = [_a-zA-Z]\w*; diff --git a/lib/libesp32/Berry/tools/grammar/json.ebnf b/lib/libesp32/Berry/tools/grammar/json.ebnf new file mode 100644 index 000000000..47c317193 --- /dev/null +++ b/lib/libesp32/Berry/tools/grammar/json.ebnf @@ -0,0 +1,5 @@ +json = value; +value = object | array | + string | number | 'true' | 'false' | 'null'; +object = '{' [ string ':' value ] { ',' string ':' value } '}'; +array = '[' [json] { ',' json } ']'; diff --git a/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/.vsixmanifest b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/.vsixmanifest new file mode 100755 index 000000000..e14b7eabc --- /dev/null +++ b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/.vsixmanifest @@ -0,0 +1,34 @@ + + + + + Embedded Script + none + berry,Embedded Script,__ext_.berry + Languages + Public + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/CHANGELOG.md b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/CHANGELOG.md new file mode 100755 index 000000000..6f51bbcca --- /dev/null +++ b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/CHANGELOG.md @@ -0,0 +1,7 @@ +# Change Log +All notable changes to the "none" extension will be documented in this file. + +Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. + +## [Unreleased] +- Initial release \ No newline at end of file diff --git a/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/README.md b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/README.md new file mode 100755 index 000000000..e69de29bb diff --git a/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/berry-configuration.json b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/berry-configuration.json new file mode 100755 index 000000000..4be01969f --- /dev/null +++ b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/berry-configuration.json @@ -0,0 +1,32 @@ +{ + "comments": { + // symbol used for single line comment. Remove this entry if your language does not support line comments + "lineComment": "#", + "blockComment": [ "#-", "-#" ] + }, + // symbols used as brackets + "brackets": [ + ["[", "]"], + ["(", ")"], + ["{", "}"] + ], + // symbols that are auto closed when typing + "autoClosingPairs": [ + ["[", "]"], + ["(", ")"], + ["{", "}"], + ["\"", "\""], + ["'", "'"] + ], + // symbols that that can be used to surround a selection + "surroundingPairs": [ + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ["'", "'"] + ], + "indentationRules": { + "increaseIndentPattern": "(^((\\s*(class|while|for|if|elif|else|try|except))|(.*\\bdef))\\b((?!\\b(end)\\b).)*)$", + "decreaseIndentPattern": "^\\s*((\\b(elif|else|except|end)\\b)|(\\)))" + } +} \ No newline at end of file diff --git a/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/berry-icon.png b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/berry-icon.png new file mode 100644 index 000000000..2869d5552 Binary files /dev/null and b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/berry-icon.png differ diff --git a/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/package.json b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/package.json new file mode 100755 index 000000000..8faf7e245 --- /dev/null +++ b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/package.json @@ -0,0 +1,52 @@ +{ + "name": "berry", + "displayName": "Berry Script Language", + "description": "A small embedded script language.", + "version": "0.1.0", + "icon": "berry-icon.png", + "publisher": "skiars", + "engines": { + "vscode": "^1.15.1" + }, + "categories": [ + "Programming Languages" + ], + "contributes": { + "languages": [ + { + "id": "berry", + "aliases": [ + "Berry", + "berry" + ], + "extensions": [ + ".be" + ], + "configuration": "./berry-configuration.json" + }, + { + "id": "berry-bytecode", + "aliases": [ + "Berry Bytecode", + "berry bytecode" + ], + "extensions": [ + "berry.bytecode" + ] + } + ], + "grammars": [ + { + "language": "berry", + "scopeName": "source.berry", + "path": "./syntaxes/berry.json" + }, + { + "language": "berry-bytecode", + "scopeName": "source.berry.bytecode", + "path": "./syntaxes/bytecode.json" + } + ] + }, + "__metadata": null +} \ No newline at end of file diff --git a/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/syntaxes/berry.json b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/syntaxes/berry.json new file mode 100755 index 000000000..1cd1d7cfd --- /dev/null +++ b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/syntaxes/berry.json @@ -0,0 +1,109 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "Berry", + "patterns": [ + { + "include": "#controls" + }, + { + "include": "#strings" + }, + { + "include": "#comment-block" + }, + { + "include": "#comments" + }, + { + "include": "#keywords" + }, + { + "include": "#function" + }, + { + "include": "#member" + }, + { + "include": "#identifier" + }, + { + "include": "#number" + }, + { + "include": "#operator" + } + ], + "repository": { + "controls": { + "patterns": [{ + "name": "keyword.control.berry", + "match": "\\b(if|elif|else|for|while|do|end|break|continue|return|try|except|raise)\\b" + }] + }, + "strings": { + "patterns": [ + { + "name": "string.quoted.double.berry", + "match": "\"(\\\\.|[^\"])*\"" + }, + { + "name": "string.quoted.single.berry", + "match": "'(\\\\.|[^'])*'" + } + ] + }, + "comment-block": { + "name": "comment.berry", + "begin": "\\#\\-", + "end": "\\-#", + "patterns": [{}] + }, + "comments": { + "name": "comment.line.berry", + "begin": "\\#", + "end": "\\n", + "patterns": [{}] + }, + "keywords": { + "patterns": [{ + "name": "keyword.berry", + "match": "\\b(var|def|class|true|false|nil|self|super|import|as)\\b" + }] + }, + "identifier": { + "patterns": [{ + "name": "identifier.berry", + "match": "\\b[_A-Za-z]\\w+\\b" + }] + }, + "number": { + "patterns": [{ + "name": "constant.numeric.berry", + "match": "0x[a-fA-F0-9]+|\\d+|(\\d+\\.?|\\.\\d)\\d*([eE][+-]?\\d+)?" + }] + }, + "operator": { + "patterns": [{ + "name": "keyword.operator.berry", + "match": "\\(|\\)|\\[|\\]|\\.|-|\\!|~|\\*|/|%|\\+|&|\\^|\\||<|>|=|:" + }] + }, + "member": { + "patterns": [{ + "match": "\\.([a-zA-Z_][a-zA-Z0-9_]*)", + "captures": { + "0": { + "name": "entity.other.attribute-name.berry" + } + } + }] + }, + "function": { + "patterns": [{ + "name": "entity.name.function.berry", + "match": "\\b([a-zA-Z_][a-zA-Z0-9_]*(?=\\s*\\())" + }] + } + }, + "scopeName": "source.berry" +} \ No newline at end of file diff --git a/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/syntaxes/bytecode.json b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/syntaxes/bytecode.json new file mode 100755 index 000000000..4bd10a843 --- /dev/null +++ b/lib/libesp32/Berry/tools/plugins/vscode/skiars.berry-0.1.0/syntaxes/bytecode.json @@ -0,0 +1,58 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "Berry", + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#keywords" + }, + { + "include": "#number" + }, + { + "include": "#operator" + }, + { + "include": "#entity" + } + ], + "repository": { + "comments": { + "name": "comment.line.berry.bytecode", + "begin": "\\--", + "end": "\\n", + "patterns": [{}] + }, + "keywords": { + "patterns": [{ + "name": "keyword.berry.bytecode", + "match": "or" + }] + }, + "number": { + "patterns": [{ + "name": "constant.numeric.berry.bytecode", + "match": "\\b((0x)?[0-9]+)\\b" + }] + }, + "operator": { + "patterns": [ + { + "name": "keyword.operator.berry.bytecode", + "match": "\\(|\\)|:|\\[|\\]|\\||->" + } + ] + }, + "entity": { + "patterns": [ + { + "name": "entity.name.function.berry", + "match": "^\\s*\\w+(?=\\s*(:|->))" + } + ] + } + }, + "scopeName": "source.berry.bytecode" +} \ No newline at end of file diff --git a/lib/libesp32_epdiy/src/epd4in7.cpp b/lib/libesp32_epdiy/src/epd4in7.cpp index 93a9f859d..4f041b473 100644 --- a/lib/libesp32_epdiy/src/epd4in7.cpp +++ b/lib/libesp32_epdiy/src/epd4in7.cpp @@ -44,10 +44,14 @@ extern uint8_t *buffer; -int temperature; +int temperature = 25; EpdiyHighlevelState hl; +uint16_t Epd47::GetColorFromIndex(uint8_t index) { + return index & 0xf; +} + Epd47::Epd47(int16_t dwidth, int16_t dheight) : Renderer(dwidth, dheight) { width = dwidth; height = dheight; @@ -63,11 +67,27 @@ int32_t Epd47::Init(void) { void Epd47::DisplayInit(int8_t p, int8_t size, int8_t rot, int8_t font) { - if (p == DISPLAY_INIT_FULL) { + + if (p == DISPLAY_INIT_MODE) { epd_poweron(); epd_clear(); epd_poweroff(); } + if (p == DISPLAY_INIT_FULL) { + memset(hl.back_fb, 0xff, width * height / 2); + epd_poweron(); + epd_clear(); + epd_hl_update_screen(&hl, MODE_GC16, temperature); + epd_poweroff(); + return; + } + if (p == DISPLAY_INIT_PARTIAL) { + memset(hl.back_fb, 0xff, width * height / 2); + epd_poweron(); + epd_hl_update_screen(&hl, MODE_GL16, temperature); + epd_poweroff(); + return; + } setRotation(rot); setTextWrap(false); cp437(true); @@ -94,6 +114,7 @@ void Epd47::fillScreen(uint16_t color) { void Epd47::drawPixel(int16_t x, int16_t y, uint16_t color) { uint16_t xp = x; uint16_t yp = y; +uint8_t *buf_ptr; switch (getRotation()) { case 1: @@ -107,14 +128,13 @@ uint16_t yp = y; case 3: _swap(xp, yp); yp = height - yp - 1; + break; } - uint32_t maxsize = width * height / 2; - uint8_t *buf_ptr = &buffer[yp * width / 2 + xp / 2]; - if ((uint32_t)buf_ptr >= (uint32_t)buffer + maxsize) { - return; - } + if (xp >= width) return; + if (yp >= height) return; + buf_ptr = &buffer[yp * width / 2 + xp / 2]; if (xp % 2) { *buf_ptr = (*buf_ptr & 0x0F) | (color << 4); diff --git a/lib/libesp32_epdiy/src/epd4in7.h b/lib/libesp32_epdiy/src/epd4in7.h index 86717e7f3..79a3081bb 100644 --- a/lib/libesp32_epdiy/src/epd4in7.h +++ b/lib/libesp32_epdiy/src/epd4in7.h @@ -51,6 +51,7 @@ public: void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); void pushColors(uint16_t *data, uint16_t len, boolean first); + uint16_t GetColorFromIndex(uint8_t index); private: uint16_t width; uint16_t height; diff --git a/pio-tools/override_copy.py b/pio-tools/override_copy.py index 1cb6c991b..5318f9169 100644 --- a/pio-tools/override_copy.py +++ b/pio-tools/override_copy.py @@ -7,3 +7,9 @@ if os.path.isfile("tasmota/user_config_override.h"): print ("*** use provided user_config_override.h as planned ***") else: shutil.copy("tasmota/user_config_override_sample.h", "tasmota/user_config_override.h") + +# copy platformio_override_sample.ini to platformio_override.ini +if os.path.isfile("platformio_override.ini"): + print ("*** use provided platformio_override.ini as planned ***") +else: + shutil.copy("platformio_override_sample.ini", "platformio_override.ini") diff --git a/platformio.ini b/platformio.ini index 2bd850f94..9468f5102 100644 --- a/platformio.ini +++ b/platformio.ini @@ -6,49 +6,9 @@ ; ; Please visit documentation for the other options and examples ; http://docs.platformio.org/en/stable/projectconf.html - - -; *** Tasmota build variant selection -[build_envs] -default_envs = -; *** Uncomment by deleting ";" in the line(s) below to select version(s) -; tasmota -; tasmota-ircustom -; tasmota-minimal -; tasmota-lite -; tasmota-knx -; tasmota-sensors -; tasmota-display -; tasmota-zbbridge -; tasmota-ir -; tasmota-AF -; tasmota-BG -; tasmota-BR -; tasmota-CN -; tasmota-CZ -; tasmota-DE -; tasmota-ES -; tasmota-FR -; tasmota-FY -; tasmota-GR -; tasmota-HE -; tasmota-HU -; tasmota-IT -; tasmota-KO -; tasmota-NL -; tasmota-PL -; tasmota-PT -; tasmota-RO -; tasmota-RU -; tasmota-SE -; tasmota-SK -; tasmota-TR -; tasmota-TW -; tasmota-UK -; tasmota-VN -; -; *** Selection for Tasmota ESP32 is done in platformio_tasmota32.ini ; +; ********************************************************************* +; *** Selection of Tasmota build variant is done with VSC ; *** alternatively can be done in: platformio_override.ini ; *** See example: platformio_override_sample.ini ; ********************************************************************* @@ -63,7 +23,6 @@ extra_configs = platformio_tasmota32.ini platformio_tasmota_env.ini platformio_tasmota_env32.ini platformio_override.ini -default_envs = ${build_envs.default_envs} [common] framework = arduino diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 05814bc69..9821e2e97 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -175,7 +175,7 @@ build_flags = ${common32.build_flags} extends = env:tasmota32_base board = esp32s2 board_build.flash_mode = qio -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/arduino-esp32/releases/download/s2-1.0.5-rc6/esp32-s2-1.0.5-rc6.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/arduino-esp32/releases/download/esp32-2.0.0-pre/esp32-2.0.0-pre.zip platformio/tool-mklittlefs @ ~1.203.200522 platformio/tool-esptoolpy @ ~1.30000.0 build_unflags = ${esp32_defaults.build_unflags} @@ -185,6 +185,16 @@ lib_ignore = Micro-RTSP ESP32 Ethernet +; *** EXPERIMENTAL Tasmota version for Arduino ESP32 IDF4.4. Linking not working. +[env:tasmota32idf4] +extends = env:tasmota32_base +platform = https://github.com/Jason2866/platform-espressif32.git#feature/arduino-idf-v4.4 +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/arduino-esp32/releases/download/esp32-2.0.0-pre/esp32-2.0.0-pre.zip + platformio/tool-mklittlefs @ ~1.203.200522 +build_unflags = ${esp32_defaults.build_unflags} +build_flags = ${esp32_defaults.build_flags} + ;-DESP32_STAGE=true + ; *** Debug version used for PlatformIO Home Project Inspection [env:tasmota-debug] build_type = debug diff --git a/platformio_tasmota32.ini b/platformio_tasmota32.ini index de1e9f08f..abf1d0199 100644 --- a/platformio_tasmota32.ini +++ b/platformio_tasmota32.ini @@ -1,45 +1,6 @@ ; *** BETA ESP32 Tasmota version *** ; *** expect the unexpected. Some features not working!!! *** -[platformio] - -; *** Tasmota build variant selection -default_envs = ${build_envs.default_envs} -; *** Uncomment by deleting ";" in the line(s) below to select version(s) -; tasmota32 -; tasmota32-bluetooth -; tasmota32-webcam -; tasmota32-odroidgo -; tasmota32-core2 -; tasmota32-display -; tasmota32-ir -; tasmota32-ircustom -; tasmota32-AF -; tasmota32-BG -; tasmota32-BR -; tasmota32-CN -; tasmota32-CZ -; tasmota32-DE -; tasmota32-ES -; tasmota32-FR -; tasmota32-FY -; tasmota32-GR -; tasmota32-HE -; tasmota32-HU -; tasmota32-IT -; tasmota32-KO -; tasmota32-NL -; tasmota32-PL -; tasmota32-PT -; tasmota32-RO -; tasmota32-RU -; tasmota32-SE -; tasmota32-SK -; tasmota32-TR -; tasmota32-TW -; tasmota32-UK -; tasmota32-VN - [common32] platform = ${core32.platform} platform_packages = ${core32.platform_packages} diff --git a/tasmota/displaydesc/ILI9341_desc.txt b/tasmota/displaydesc/ILI9341_desc.txt new file mode 100644 index 000000000..6aab1b1c5 --- /dev/null +++ b/tasmota/displaydesc/ILI9341_desc.txt @@ -0,0 +1,50 @@ +; name,xs,ys,bpp,interface, spi_nr cs, sclk,mosi,dc, bp ,reset,miso,spi_speed +:H +ILI9341,240,320,16,SPI,1,*,*,*,*,*,*,*,40000000 +; splash settings, font, size, fgcol, bgcol, x,y +:S +2,1,1,0,40,20 +; initialyze +:I +EF,3,03,80,02 +CF,3,00,C1,30 +ED,4,64,03,12,81 +E8,3,85,00,78 +CB,5,39,2C,00,34,02 +F7,1,20 +EA,2,00,00 +C0,1,23 +C1,1,10 +C5,2,3e,28 +C7,1,86 +36,1,48 +37,1,00 +3A,1,55 +B1,2,00,18 +B6,3,08,82,27 +F2,1,00 +26,1,01 +E0,0F,0F,31,2B,0C,0E,08,4E,F1,37,07,10,03,0E,09,00 +E1,0F,00,0E,14,03,11,07,31,C1,48,08,0F,0C,31,36,0F +11,80 +29,80 +; off +:o +28 +; on +:O +29 +; set adress window +:A +2A,2B,2C +; rotation +:0 +48 +:1 +28 +:2 +88 +:3 +E8 +# + diff --git a/tasmota/displaydesc/SH1106_desc.txt b/tasmota/displaydesc/SH1106_desc.txt new file mode 100644 index 000000000..954cb3740 --- /dev/null +++ b/tasmota/displaydesc/SH1106_desc.txt @@ -0,0 +1,31 @@ +; name,xs,ys,bpp,interface, address, scl,sda,reset +:H +SH1106,128,64,1,I2C,3c,*,*,* +; splash settings, font, size, fgcol, bgcol, x,y +:S +0,1,1,0,40,20 +; init register settings +:I +AE +D5,80 +A8,3f +D3,00 +40 +8D,14 +20,00 +A1 +C8 +DA,12 +81,CF +D9F1 +DB,40 +A4 +A6 +AF +; switch display off +:o +AE +; switch display on +:O +AF +# \ No newline at end of file diff --git a/tasmota/i18n.h b/tasmota/i18n.h index 05f6d3ca2..c435348a8 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -306,6 +306,7 @@ #define D_WCFG_7_WIFIMANAGER_RESET_ONLY "ManagerRst" #define D_CMND_DEVICENAME "DeviceName" #define D_CMND_FRIENDLYNAME "FriendlyName" +#define D_CMND_FN "FN" #define D_CMND_SWITCHMODE "SwitchMode" #define D_CMND_INTERLOCK "Interlock" #define D_CMND_TELEPERIOD "TelePeriod" @@ -420,6 +421,7 @@ #define D_CMND_VOLTAGESET "VoltageSet" #define D_CMND_CURRENTSET "CurrentSet" #define D_CMND_FREQUENCYSET "FrequencySet" +#define D_CMND_ENERGYCONFIG "EnergyConfig" #define D_CMND_MAXPOWER "MaxPower" #define D_CMND_MAXPOWERHOLD "MaxPowerHold" #define D_CMND_MAXPOWERWINDOW "MaxPowerWindow" @@ -813,8 +815,6 @@ const float kSpeedConversionFactor[] = {1, // none #ifdef USE_WEBSERVER // {s} = , {m} = , {e} = const char HTTP_SNS_F_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%*_f " D_UNIT_DEGREE "%c{e}"; -//const char HTTP_SNS_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%s " D_UNIT_DEGREE "%c{e}"; - const char HTTP_SNS_HUM[] PROGMEM = "{s}%s " D_HUMIDITY "{m}%s " D_UNIT_PERCENT "{e}"; const char HTTP_SNS_DEW[] PROGMEM = "{s}%s " D_DEWPOINT "{m}%s " D_UNIT_DEGREE "%c{e}"; const char HTTP_SNS_PRESSURE[] PROGMEM = "{s}%s " D_PRESSURE "{m}%s " "%s{e}"; @@ -830,6 +830,7 @@ const char HTTP_SNS_RANGE_CHR[] PROGMEM = "{s}%s " D_RANGE "{ const char HTTP_SNS_RANGE[] PROGMEM = "{s}%s " D_RANGE "{m}%d" "{e}"; const char HTTP_SNS_DISTANCE[] PROGMEM = "{s}%s " D_DISTANCE "{m}%d " D_UNIT_MILLIMETER "{e}"; const char HTTP_SNS_DISTANCE_CM[] PROGMEM = "{s}%s " D_DISTANCE "{m}%s " D_UNIT_CENTIMETER "{e}"; +const char HTTP_SNS_HALL_EFFECT[] PROGMEM = "{s}%s " D_HALL_EFFECT "{m}%d" "{e}"; const char HTTP_SNS_VOLTAGE[] PROGMEM = "{s}" D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}"; const char HTTP_SNS_CURRENT[] PROGMEM = "{s}" D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}"; const char HTTP_SNS_POWER[] PROGMEM = "{s}" D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}"; diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h index 989e5636d..297ca7de0 100644 --- a/tasmota/language/af_AF.h +++ b/tasmota/language/af_AF.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSId" -#define D_AP1_PASSWORD "AP1 Wagwoord" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "AP2 Wagwoord" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi Wagwoord" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "MQTT-parameters" #define D_CLIENT "Kliënt" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Bestuur lêerstelsel" #define D_FS_SIZE "Grootte" #define D_FS_FREE "Vry" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "versterking:" diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index 0dfbe2b13..589503792 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSId" -#define D_AP1_PASSWORD "AP1 Парола" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "AP2 Парола" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi Парола" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "Параметри на MQTT" #define D_CLIENT "Клиент" @@ -809,7 +818,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -915,6 +924,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "усилване:" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index 91929e163..9694301ee 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSID" -#define D_AP1_PASSWORD "Heslo AP1" -#define D_AP2_SSID "AP2 SSID" -#define D_AP2_PASSWORD "Heslo AP2" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "Heslo WiFi" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "Nastavení MQTT" #define D_CLIENT "Klient" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index a6bb7e8a6..2625ceaf2 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -291,9 +291,18 @@ #define D_WPA_PSK "WPA-PSK" #define D_WPA2_PSK "WPA2-PSK" #define D_AP1_SSID "WLAN 1 - SSID" -#define D_AP1_PASSWORD "WLAN 1 - Passwort" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" #define D_AP2_SSID "WLAN 2 - SSID" -#define D_AP2_PASSWORD "WLAN 2 - Passwort" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WLAN - Passwort" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "MQTT-Einstellungen" #define D_CLIENT "client" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Puls" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Verwalte Dateisystem" #define D_FS_SIZE "Größe" #define D_FS_FREE "Frei" +#define D_NEW_FILE "neue-datei.txt" +#define D_CREATE_NEW_FILE "Neue Datei erstellen und bearbeiten" +#define D_EDIT_FILE "Datei bearbeiten" //xsns_67_as3935.ino #define D_AS3935_GAIN "Umgebung:" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index 9b694ad22..27e4b332b 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSId" -#define D_AP1_PASSWORD "AP1 Κωδικός" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "AP2 Κωδικός" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi Κωδικός" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "Παράμετροι MQTT" #define D_CLIENT "Πελάτης" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 54c33fec0..b592fc826 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v9.3.1.1 + * Updated until v9.3.1.2 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSId" -#define D_AP1_PASSWORD "AP1 Password" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "AP2 Password" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi Password" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "MQTT parameters" #define D_CLIENT "Client" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index 74ec56458..acc823221 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "SSId AP1" -#define D_AP1_PASSWORD "Clave AP1" -#define D_AP2_SSID "SSId AP2" -#define D_AP2_PASSWORD "Clave AP2" +#define D_AP1_SSID "Red WiFi" +#define D_AP1_SSID_HELP "Escriba o Seleccione su Red WiFi" +#define D_AP2_SSID "Red WiFi Alternativa" +#define D_AP2_SSID_HELP "Escriba el nombre de la Red WiFi Alternativa" +#define D_AP_PASSWORD "Clave WiFi" +#define D_AP_PASSWORD_HELP "Escriba la clave de WiFi" +#define D_SELECT_YOUR_WIFI_NETWORK "Seleccione su Red WiFi" +#define D_SHOW_MORE_WIFI_NETWORKS "Buscar todas las Redes WiFi" +#define D_SHOW_MORE_OPTIONS "Mas Opciones" +#define D_CHECK_CREDENTIALS "Por favor, revise la clave" +#define D_SUCCESSFUL_WIFI_CONNECTION "Conexión WiFi Existosa" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Ahora puede cerrar esta ventana" +#define D_REDIRECTING_TO_NEW_IP "Redireccionando a la nueva dirección IP" #define D_MQTT_PARAMETERS "Parámetros MQTT" #define D_CLIENT "Cliente" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "Cruce por cero" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Explorar Archivos" #define D_FS_SIZE "Tamaño" #define D_FS_FREE "Libre" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "Ganancia:" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index 8d5772871..aa74db5dd 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSID" -#define D_AP1_PASSWORD "Mot de passe AP1" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "Mot de passe AP2" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "Mot de passe" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "Paramètres MQTT" #define D_CLIENT "Client" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -915,6 +924,9 @@ #define D_MANAGE_FILE_SYSTEM "Gestion du Système de Fichier" #define D_FS_SIZE "Taille" #define D_FS_FREE "Libre" +#define D_NEW_FILE "nouveau-fichier.txt" +#define D_CREATE_NEW_FILE "Créer and modifier un nouveau fichier" +#define D_EDIT_FILE "Modification de fichier" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/fy_NL.h b/tasmota/language/fy_NL.h index 594a67785..d76bf3fb9 100644 --- a/tasmota/language/fy_NL.h +++ b/tasmota/language/fy_NL.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSId" -#define D_AP1_PASSWORD "AP1 Wachtwurd" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "AP2 Wachtwurd" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi Wachtwurd" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "MQTT parameters" #define D_CLIENT "Client" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Bestânbehearder" #define D_FS_SIZE "Grutte" #define D_FS_FREE "Frij" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index ce16e050f..7d360e060 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSId" -#define D_AP1_PASSWORD "AP1 Password" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "AP2 Password" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi Password" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "MQTT פרמטרים" #define D_CLIENT "לקוח" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index 905bb4cb4..eb6f6b41b 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSID" -#define D_AP1_PASSWORD "AP1 megosztott kulcs" -#define D_AP2_SSID "AP2 SSID" -#define D_AP2_PASSWORD "AP2 megosztott kulcs" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi megosztott kulcs" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "MQTT paraméterek" #define D_CLIENT "Kliens" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Fájlrendszer kezelése" #define D_FS_SIZE "Méret" #define D_FS_FREE "Szabad" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "nyereség:" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index e35a9a2e8..b1831c489 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -1,7 +1,7 @@ /* it-IT.h - localization for Italian - Italy for Tasmota - Copyright (C) 2021 Gennaro Tortone, Antonio Fragola, Bovirus and Adrian Scillato + Copyright (C) 2021 Gennaro Tortone, Antonio Fragola, bovirus and Adrian Scillato This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Last update - 9.3.1.2 (27.03.2021) + * Updated until v9.3.1.2 - Last update 11.04.2021 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 - SSID" -#define D_AP1_PASSWORD "AP1 - Password" -#define D_AP2_SSID "AP2 - SSID" -#define D_AP2_PASSWORD "AP2 - Password" +#define D_AP1_SSID "Rete WiFi" +#define D_AP1_SSID_HELP "Digita o Seleziona la tua Rete WiFi" +#define D_AP2_SSID "Rete WiFi 2" +#define D_AP2_SSID_HELP "Digita la tua Rete WiFi Alternativa" +#define D_AP_PASSWORD "Password WiFi" +#define D_AP_PASSWORD_HELP "Inserisci la tua Password WiFi" +#define D_SELECT_YOUR_WIFI_NETWORK "Seleziona la tua Rete WiFi" +#define D_SHOW_MORE_WIFI_NETWORKS "Cerca tutte le Reti WiFi" +#define D_SHOW_MORE_OPTIONS "Più Opzioni" +#define D_CHECK_CREDENTIALS "Per favore, controlla le tue Credenziali" +#define D_SUCCESSFUL_WIFI_CONNECTION "Connessione WiFi riuscita" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Adesso puoi chiudere questa finestra" +#define D_REDIRECTING_TO_NEW_IP "Reindirizzamento al nuovo indirizzo IP del dispositivo" #define D_MQTT_PARAMETERS "Parametri MQTT" #define D_CLIENT "Client" @@ -648,9 +657,9 @@ #define D_SENSOR_TM1638_CLK "TM1638 - CLK" #define D_SENSOR_TM1638_DIO "TM1638 - DIO" #define D_SENSOR_TM1638_STB "TM1638 - STB" -#define D_SENSOR_MAX7219_DIN "MAX7219 - DIN" +#define D_SENSOR_MAX7219_DIN "MAX7219 - DIN" #define D_SENSOR_MAX7219_CS "MAX7219 - CS" -#define D_SENSOR_MAX7219_CLK "MAX7219 - CLK" +#define D_SENSOR_MAX7219_CLK "MAX7219 - CLK" #define D_SENSOR_HX711_SCK "HX711 - SCK" #define D_SENSOR_HX711_DAT "HX711 - DAT" #define D_SENSOR_FTC532 "FTC532" @@ -806,57 +815,57 @@ #define D_SENSOR_NEOPOOL_TX "NeoPool - TX" #define D_SENSOR_NEOPOOL_RX "NeoPool - RX" #define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" -#define D_SENSOR_TFMINIPLUS_TX "TFmini+ - TX" -#define D_SENSOR_TFMINIPLUS_RX "TFmini+ - RX" +#define D_SENSOR_TFMINIPLUS_TX "TFmini+ - TX" +#define D_SENSOR_TFMINIPLUS_RX "TFmini+ - RX" #define D_SENSOR_ZEROCROSS "Impulsi ZC" #define D_SENSOR_HALLEFFECT "Effetto hall" - +#define D_SENSOR_EPD_DATA "EPD - Dati" // Units -#define D_UNIT_AMPERE "A" -#define D_UNIT_CELSIUS "C" -#define D_UNIT_CENTIMETER "cm" -#define D_UNIT_DEGREE "°" -#define D_UNIT_FAHRENHEIT "F" -#define D_UNIT_HERTZ "Hz" -#define D_UNIT_HOUR "o" -#define D_UNIT_GALLONS "gal" -#define D_UNIT_GALLONS_PER_MIN "g/m" -#define D_UNIT_INCREMENTS "inc" -#define D_UNIT_KELVIN "K" -#define D_UNIT_KILOMETER "km" -#define D_UNIT_KILOGRAM "kg" -#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h" -#define D_UNIT_KILOOHM "kΩ" -#define D_UNIT_KILOWATTHOUR "kWh" -#define D_UNIT_LITERS "L" -#define D_UNIT_LITERS_PER_MIN "L/m" -#define D_UNIT_LUX "lx" +#define D_UNIT_AMPERE "A" +#define D_UNIT_CELSIUS "C" +#define D_UNIT_CENTIMETER "cm" +#define D_UNIT_DEGREE "°" +#define D_UNIT_FAHRENHEIT "F" +#define D_UNIT_HERTZ "Hz" +#define D_UNIT_HOUR "o" +#define D_UNIT_GALLONS "gal" +#define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KELVIN "K" +#define D_UNIT_KILOMETER "km" +#define D_UNIT_KILOGRAM "kg" +#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h" +#define D_UNIT_KILOOHM "kΩ" +#define D_UNIT_KILOWATTHOUR "kWh" +#define D_UNIT_LITERS "L" +#define D_UNIT_LITERS_PER_MIN "L/m" +#define D_UNIT_LUX "lx" #define D_UNIT_MICROGRAM_PER_CUBIC_METER "µg/m³" -#define D_UNIT_MICROMETER "µm" -#define D_UNIT_MICROSECOND "µs" -#define D_UNIT_MICROSIEMENS_PER_CM "µS/cm" -#define D_UNIT_MILLIAMPERE "mA" -#define D_UNIT_MILLILITERS "ml" -#define D_UNIT_MILLIMETER "mm" -#define D_UNIT_MILLIMETER_MERCURY "mmHg" -#define D_UNIT_MILLISECOND "ms" -#define D_UNIT_MILLIVOLT "mV" -#define D_UNIT_MINUTE "Min" -#define D_UNIT_PARTS_PER_BILLION "ppb" -#define D_UNIT_PARTS_PER_DECILITER "ppd" -#define D_UNIT_PARTS_PER_MILLION "ppm" -#define D_UNIT_MILIGRAMS_PER_LITER "mg/L" -#define D_UNIT_PERCENT "%%" -#define D_UNIT_PRESSURE "hPa" -#define D_UNIT_SECOND "sec" -#define D_UNIT_SECTORS "settori" -#define D_UNIT_VA "VA" -#define D_UNIT_VAR "VAr" -#define D_UNIT_VOLT "V" -#define D_UNIT_WATT "W" -#define D_UNIT_WATTHOUR "Wh" -#define D_UNIT_WATT_METER_QUADRAT "W/m²" +#define D_UNIT_MICROMETER "µm" +#define D_UNIT_MICROSECOND "µs" +#define D_UNIT_MICROSIEMENS_PER_CM "µS/cm" +#define D_UNIT_MILLIAMPERE "mA" +#define D_UNIT_MILLILITERS "ml" +#define D_UNIT_MILLIMETER "mm" +#define D_UNIT_MILLIMETER_MERCURY "mmHg" +#define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" +#define D_UNIT_MINUTE "Min" +#define D_UNIT_PARTS_PER_BILLION "ppb" +#define D_UNIT_PARTS_PER_DECILITER "ppd" +#define D_UNIT_PARTS_PER_MILLION "ppm" +#define D_UNIT_MILIGRAMS_PER_LITER "mg/L" +#define D_UNIT_PERCENT "%%" +#define D_UNIT_PRESSURE "hPa" +#define D_UNIT_SECOND "sec" +#define D_UNIT_SECTORS "settori" +#define D_UNIT_VA "VA" +#define D_UNIT_VAR "VAr" +#define D_UNIT_VOLT "V" +#define D_UNIT_WATT "W" +#define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" #define D_NEW_ADDRESS "Imposta indirizzo a" #define D_OUT_OF_RANGE "Fuori intervallo" @@ -916,35 +925,38 @@ #define D_MANAGE_FILE_SYSTEM "Gestione File system" #define D_FS_SIZE "Dimensione" #define D_FS_FREE "Liberi" +#define D_NEW_FILE "nuovofile.txt" +#define D_CREATE_NEW_FILE "Crea e modifica nuovo file" +#define D_EDIT_FILE "Modifica file" //xsns_67_as3935.ino -#define D_AS3935_GAIN "guadagno:" -#define D_AS3935_ENERGY "energia:" -#define D_AS3935_DISTANCE "distanza:" +#define D_AS3935_GAIN "guadagno:" +#define D_AS3935_ENERGY "energia:" +#define D_AS3935_DISTANCE "distanza:" #define D_AS3935_DISTURBER "disturbatore:" -#define D_AS3935_VRMS "µVrms:" -#define D_AS3935_APRX "appross.:" -#define D_AS3935_AWAY "lontano" -#define D_AS3935_LIGHT "illuminazione" -#define D_AS3935_OUT "illuminazione fuori intervallo" -#define D_AS3935_NOT "distanza non determinata" -#define D_AS3935_ABOVE "illuminazione ambientale" -#define D_AS3935_NOISE "rilevato rumore" -#define D_AS3935_DISTDET "rilevato disturbatore" -#define D_AS3935_INTNOEV "Interrupt senza evento!" -#define D_AS3935_FLICKER "Flicker PIN IRQ!" -#define D_AS3935_POWEROFF "Spegnimento" -#define D_AS3935_NOMESS "in ascolto..." -#define D_AS3935_ON "ON" -#define D_AS3935_OFF "OFF" -#define D_AS3935_INDOORS "Interno" -#define D_AS3935_OUTDOORS "Esterno" -#define D_AS3935_CAL_FAIL "calibrazione fallita" -#define D_AS3935_CAL_OK "calibrazione impostata a:" +#define D_AS3935_VRMS "µVrms:" +#define D_AS3935_APRX "appross.:" +#define D_AS3935_AWAY "lontano" +#define D_AS3935_LIGHT "illuminazione" +#define D_AS3935_OUT "illuminazione fuori intervallo" +#define D_AS3935_NOT "distanza non determinata" +#define D_AS3935_ABOVE "illuminazione ambientale" +#define D_AS3935_NOISE "rilevato rumore" +#define D_AS3935_DISTDET "rilevato disturbatore" +#define D_AS3935_INTNOEV "Interrupt senza evento!" +#define D_AS3935_FLICKER "Flicker PIN IRQ!" +#define D_AS3935_POWEROFF "Spegnimento" +#define D_AS3935_NOMESS "in ascolto..." +#define D_AS3935_ON "ON" +#define D_AS3935_OFF "OFF" +#define D_AS3935_INDOORS "Interno" +#define D_AS3935_OUTDOORS "Esterno" +#define D_AS3935_CAL_FAIL "calibrazione fallita" +#define D_AS3935_CAL_OK "calibrazione impostata a:" //xsns_68_opentherm.ino -#define D_SENSOR_BOILER_OT_RX "OpenTherm - RX" -#define D_SENSOR_BOILER_OT_TX "OpenTherm - TX" +#define D_SENSOR_BOILER_OT_RX "OpenTherm - RX" +#define D_SENSOR_BOILER_OT_TX "OpenTherm - TX" // xnrg_15_teleinfo Denky (Teleinfo) #define D_CONTRACT "Contratto" @@ -956,41 +968,41 @@ #define D_MAX_CURRENT "Corrente max" // xsns_79_as608.ino -#define D_FP_ENROLL_PLACEFINGER "Appoggia impronta" -#define D_FP_ENROLL_REMOVEFINGER "Rimuovi impronta" -#define D_FP_ENROLL_PLACESAMEFINGER "Appoggia di nuovo stessa impronta" -#define D_FP_ENROLL_RETRY "Errore quindi riprova" -#define D_FP_ENROLL_RESTART "Riavvia" -#define D_FP_ENROLL_ERROR "Errore" -#define D_FP_ENROLL_RESET "Ripristina" -#define D_FP_ENROLL_ACTIVE "Attivo" -#define D_FP_ENROLL_INACTIVE "Non attivo" +#define D_FP_ENROLL_PLACEFINGER "Appoggia impronta" +#define D_FP_ENROLL_REMOVEFINGER "Rimuovi impronta" +#define D_FP_ENROLL_PLACESAMEFINGER "Appoggia di nuovo stessa impronta" +#define D_FP_ENROLL_RETRY "Errore quindi riprova" +#define D_FP_ENROLL_RESTART "Riavvia" +#define D_FP_ENROLL_ERROR "Errore" +#define D_FP_ENROLL_RESET "Ripristina" +#define D_FP_ENROLL_ACTIVE "Attivo" +#define D_FP_ENROLL_INACTIVE "Non attivo" // Indexed by Adafruit_Fingerprint.h defines -#define D_FP_PACKETRECIEVEERR "Errore comunicazione" // 0x01 Error when receiving data package -#define D_FP_NOFINGER "" // 0x02 No finger on the sensor -#define D_FP_IMAGEFAIL "Errore immagine" // 0x03 Failed to enroll the finger -#define D_FP_IMAGEMESS "Immmagine troppo danneggiata" // 0x06 Failed to generate character file due to overly disorderly fingerprint image -#define D_FP_FEATUREFAIL "Impronta troppo piccola" // 0x07 Failed to generate character file due to the lack of character point or small fingerprint image -#define D_FP_NOMATCH "Nessuna corrispondenza" // 0x08 Finger doesn't match -#define D_FP_NOTFOUND "Corrispondenza non trovata" // 0x09 Failed to find matching finger -#define D_FP_ENROLLMISMATCH "L'impronta non corrisponde" // 0x0A Failed to combine the character files -#define D_FP_BADLOCATION "Locazione errata" // 0x0B Addressed PageID is beyond the finger library -#define D_FP_DBRANGEFAIL "Errore intervallo DB" // 0x0C Error when reading template from library or invalid template -#define D_FP_UPLOADFEATUREFAIL "Errore funzione upload" // 0x0D Error when uploading template -#define D_FP_PACKETRESPONSEFAIL "Errore risposta pacchetto" // 0x0E Module failed to receive the following data packages -#define D_FP_UPLOADFAIL "Errore upload" // 0x0F Error when uploading image -#define D_FP_DELETEFAIL "Errore eliminazione" // 0x10 Failed to delete the template -#define D_FP_DBCLEARFAIL "Errore azzeramento DB" // 0x11 Failed to clear finger library -#define D_FP_PASSFAIL "Errore password" // 0x13 Find whether the fingerprint passed or failed -#define D_FP_INVALIDIMAGE "Immagine non valida" // 0x15 Failed to generate image because of lac of valid primary image -#define D_FP_FLASHERR "Errore scrittura flash" // 0x18 Error when writing flash -#define D_FP_INVALIDREG "Numero non valido" // 0x1A Invalid register number -#define D_FP_ADDRCODE "Codice indirizzo" // 0x20 Address code -#define D_FP_PASSVERIFY "Password verificata" // 0x21 Verify the fingerprint passed -#define D_FP_UNKNOWNERROR "Errore" // Any other error +#define D_FP_PACKETRECIEVEERR "Errore comunicazione" // 0x01 Error when receiving data package +#define D_FP_NOFINGER "" // 0x02 No finger on the sensor +#define D_FP_IMAGEFAIL "Errore immagine" // 0x03 Failed to enroll the finger +#define D_FP_IMAGEMESS "Immmagine troppo danneggiata" // 0x06 Failed to generate character file due to overly disorderly fingerprint image +#define D_FP_FEATUREFAIL "Impronta troppo piccola" // 0x07 Failed to generate character file due to the lack of character point or small fingerprint image +#define D_FP_NOMATCH "Nessuna corrispondenza" // 0x08 Finger doesn't match +#define D_FP_NOTFOUND "Corrispondenza non trovata" // 0x09 Failed to find matching finger +#define D_FP_ENROLLMISMATCH "L'impronta non corrisponde" // 0x0A Failed to combine the character files +#define D_FP_BADLOCATION "Locazione errata" // 0x0B Addressed PageID is beyond the finger library +#define D_FP_DBRANGEFAIL "Errore intervallo DB" // 0x0C Error when reading template from library or invalid template +#define D_FP_UPLOADFEATUREFAIL "Errore funzione upload" // 0x0D Error when uploading template +#define D_FP_PACKETRESPONSEFAIL "Errore risposta pacchetto" // 0x0E Module failed to receive the following data packages +#define D_FP_UPLOADFAIL "Errore upload" // 0x0F Error when uploading image +#define D_FP_DELETEFAIL "Errore eliminazione" // 0x10 Failed to delete the template +#define D_FP_DBCLEARFAIL "Errore azzeramento DB" // 0x11 Failed to clear finger library +#define D_FP_PASSFAIL "Errore password" // 0x13 Find whether the fingerprint passed or failed +#define D_FP_INVALIDIMAGE "Immagine non valida" // 0x15 Failed to generate image because of lac of valid primary image +#define D_FP_FLASHERR "Errore scrittura flash" // 0x18 Error when writing flash +#define D_FP_INVALIDREG "Numero non valido" // 0x1A Invalid register number +#define D_FP_ADDRCODE "Codice indirizzo" // 0x20 Address code +#define D_FP_PASSVERIFY "Password verificata" // 0x21 Verify the fingerprint passed +#define D_FP_UNKNOWNERROR "Errore" // Any other error // xsns_83_neopool.ino -#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names +#define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names #define D_NEOPOOL_MACH_HIDROLIFE "Hidrolife (giallo)" #define D_NEOPOOL_MACH_AQUASCENIC "Aquascenic (blu)" #define D_NEOPOOL_MACH_OXILIFE "Oxilife (verde)" @@ -1037,7 +1049,7 @@ #define D_NEOPOOL_LOW "Bassa" #define D_NEOPOOL_FLOW1 "FL1" #define D_NEOPOOL_FLOW2 "FL2" -#define D_NEOPOOL_PH_HIGH "troppo alto" // ph Alarms +#define D_NEOPOOL_PH_HIGH "troppo alto" // ph Alarms #define D_NEOPOOL_PH_LOW "troppo basso" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "tempo pompa superato" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index 74e3caddc..9cce3e4ad 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSId" -#define D_AP1_PASSWORD "AP1 비밀번호" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "AP2 비밀번호" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi 비밀번호" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "MQTT 설정" #define D_CLIENT "클라이언트" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index 618990ea2..7917a6dd7 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSId" -#define D_AP1_PASSWORD "AP1 Wachtwoord" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "AP2 Wachtwoord" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi Wachtwoord" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "MQTT parameters" #define D_CLIENT "Client" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Bestandsbeheer" #define D_FS_SIZE "Grootte" #define D_FS_FREE "Vrij" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 8db1978fa..ee345765b 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "Nazwa 1" -#define D_AP1_PASSWORD "Hasło 1" +#define D_AP1_SSID "Nazwa" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" #define D_AP2_SSID "Nazwa 2" -#define D_AP2_PASSWORD "Hasło 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "Hasło" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "Parametry MQTT" #define D_CLIENT "Klient" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Menadżer plików" #define D_FS_SIZE "Rozmiar" #define D_FS_FREE "Wolne" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "wejście:" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index e95c48a9b..3be3dbc04 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v9.3.1.1 + * Updated until v9.3.1.2 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSId" -#define D_AP1_PASSWORD "Senha AP1" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "Senha AP2" +#define D_AP1_SSID "Rede WiFi" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "Rede WiFi 2" +#define D_AP2_SSID_HELP "Digite ou selecione sua rede WiFi" +#define D_AP_PASSWORD "Senha do WiFi" +#define D_AP_PASSWORD_HELP "Digite sua Senha WiFi" +#define D_SELECT_YOUR_WIFI_NETWORK "Selecione sua Rede WiFi" +#define D_SHOW_MORE_WIFI_NETWORKS "Procure todas as Redes WiFi" +#define D_SHOW_MORE_OPTIONS "Mais Opções" +#define D_CHECK_CREDENTIALS "Por favor, verifique suas credenciais" +#define D_SUCCESSFUL_WIFI_CONNECTION "Conexão WiFi bem-sucedida" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Agora você pode fechar esta janela" +#define D_REDIRECTING_TO_NEW_IP "Redirecionando para o novo endereço IP do dispositivo" #define D_MQTT_PARAMETERS "Parâmetros MQTT" #define D_CLIENT "Cliente" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index fbc55ab05..245532523 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v9.3.1.1 + * Updated until v9.3.1.2 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "SSId do AP1" -#define D_AP1_PASSWORD "Palavra Chave do AP1" -#define D_AP2_SSID "SSId do AP2" -#define D_AP2_PASSWORD "Palavra Chave do AP2" +#define D_AP1_SSID "Rede WiFi" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "Rede WiFi 2" +#define D_AP2_SSID_HELP "Digite ou selecione sua rede WiFi" +#define D_AP_PASSWORD "Palavra Chave do WiFi" +#define D_AP_PASSWORD_HELP "Digite sua Palavra Chave do WiFi" +#define D_SELECT_YOUR_WIFI_NETWORK "Selecione sua Rede WiFi" +#define D_SHOW_MORE_WIFI_NETWORKS "Procure todas as Redes WiFi" +#define D_SHOW_MORE_OPTIONS "Mais Opções" +#define D_CHECK_CREDENTIALS "Por favor, verifique suas credenciais" +#define D_SUCCESSFUL_WIFI_CONNECTION "Conexão WiFi bem-sucedida" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Agora você pode fechar esta janela" +#define D_REDIRECTING_TO_NEW_IP "Redirecionando para o novo endereço IP do dispositivo" #define D_MQTT_PARAMETERS "Parametros MQTT" #define D_CLIENT "Cliente" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index 19d1c59e8..6c62d0c98 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSId" -#define D_AP1_PASSWORD "Parolă AP1" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "Parolă AP2" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "Parolă WiFi" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "parametri MQTT" #define D_CLIENT "Client" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index 7549ce1bb..4ef363376 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSId" -#define D_AP1_PASSWORD "AP1 Пароль" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "AP2 Пароль" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi Пароль" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "Параметры MQTT" #define D_CLIENT "Клиент" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "А" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index ab6bf0649..6570bccdd 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSID" -#define D_AP1_PASSWORD "Heslo AP1" -#define D_AP2_SSID "AP2 SSID" -#define D_AP2_PASSWORD "Heslo AP2" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "Heslo WiFi" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "Nastavenia MQTT" #define D_CLIENT "Klient" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index 5ebdfcd4b..c195d4735 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSId" -#define D_AP1_PASSWORD "AP1 lösenord" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "AP2 lösenord" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi lösenord" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "MQTT-parameterar" #define D_CLIENT "Klient" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 2b1660f05..8064479c7 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 Adı (SSId)" -#define D_AP1_PASSWORD "AP1 Parolası" -#define D_AP2_SSID "AP2 SSId" -#define D_AP2_PASSWORD "AP2 Parolası" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi Parolası" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "MQTT parametreleri" #define D_CLIENT "İstemci" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index 816ea4381..2f18836f1 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 SSID" -#define D_AP1_PASSWORD "AP1 гасло" -#define D_AP2_SSID "AP2 SSID" -#define D_AP2_PASSWORD "AP2 гасло" +#define D_AP1_SSID "WiFi Network" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi Network 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi гасло" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "Параметри MQTT" #define D_CLIENT "Клієнт" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "А" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index 993dce616..5b0c3a247 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "Tên mạng wifi 1" -#define D_AP1_PASSWORD "Mật khẩu mạng wifi 1" -#define D_AP2_SSID "Tên mạng wifi 2" -#define D_AP2_PASSWORD "Mật khẩu mạng wifi 2" +#define D_AP1_SSID "Tên mạng WiFi" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "Tên mạng WiFi 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "Mật khẩu mạng WiFi" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "Thông số MQTT" #define D_CLIENT "Client" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "A" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "khuếch đại:" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index c7f21781f..22580ed43 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -1,7 +1,7 @@ /* zh-CN.h - localization for Chinese (Simplified) - China for Tasmota - Copyright (C) 2021 Killadm + Copyright (C) 2021 Killadm, Haoyu This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -63,7 +63,7 @@ #define D_BRIGHTLIGHT "亮" #define D_BSSID "BSSId" #define D_BUTTON "按钮" -#define D_BY "汉化: killadm 作者:" // Written by me +#define D_BY "作者:" // Written by me #define D_BYTES "大小:" #define D_CELSIUS "摄氏" #define D_CHANNEL "频道" @@ -187,9 +187,9 @@ #define D_UV_INDEX_2 "中" #define D_UV_INDEX_3 "高" #define D_UV_INDEX_4 "危险" -#define D_UV_INDEX_5 "BurnL1/2" -#define D_UV_INDEX_6 "BurnL3" -#define D_UV_INDEX_7 "OoR" +#define D_UV_INDEX_5 "一/二度烧伤" +#define D_UV_INDEX_6 "三度烧伤" +#define D_UV_INDEX_7 "超出范围" #define D_UV_LEVEL "紫外线水平" #define D_UV_POWER "紫外线功率 " #define D_VERSION "版本" @@ -200,7 +200,7 @@ #define D_WEB_SERVER "Web Server" // tasmota.ino -#define D_WARNING_MINIMAL_VERSION "警告:精简固件不支持配置持久化保存" +#define D_WARNING_MINIMAL_VERSION "警告:精简固件不支持持久保存设置" #define D_LEVEL_10 "level 1-0" #define D_LEVEL_01 "level 0-1" #define D_SERIAL_LOGGING_DISABLED "串口日志已禁用" @@ -238,7 +238,7 @@ #define D_ERASED_SECTOR "擦除扇区" // webserver.ino -#define D_NOSCRIPT "Tasmota要求浏览器支持 JavaScript" +#define D_NOSCRIPT "Tasmota 要求浏览器支持 JavaScript" #define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "当前是精简版固件
请升级" #define D_WEBSERVER_ACTIVE_ON "Web 服务器地址:" #define D_WITH_IP_ADDRESS "IP 地址:" @@ -247,12 +247,12 @@ #define D_REDIRECTED "重定向到认证页面" #define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "Wifimanager 设置无线操作模式" #define D_WIFIMANAGER_SET_ACCESSPOINT "Wifimanager 设置接入点" -#define D_TRYING_TO_CONNECT "尝试将设备连接到网络" +#define D_TRYING_TO_CONNECT "设备正在尝试连接网络" -#define D_RESTART_IN "重启需要" +#define D_RESTART_IN "重启倒计时" #define D_SECONDS "秒" -#define D_DEVICE_WILL_RESTART "设备将在几秒钟内重启" -#define D_BUTTON_TOGGLE "状态切换" +#define D_DEVICE_WILL_RESTART "设备将在几秒钟后重启" +#define D_BUTTON_TOGGLE "开/关" #define D_CONFIGURATION "设置" #define D_INFORMATION "信息" #define D_FIRMWARE_UPGRADE "固件升级" @@ -260,9 +260,9 @@ #define D_CONFIRM_RESTART "确认重启" #define D_CONFIGURE_MODULE "模块设置" -#define D_CONFIGURE_WIFI "WiFi设置" -#define D_CONFIGURE_MQTT "MQTT设置" -#define D_CONFIGURE_DOMOTICZ "Domoticz设置" +#define D_CONFIGURE_WIFI "WiFi 设置" +#define D_CONFIGURE_MQTT "MQTT 设置" +#define D_CONFIGURE_DOMOTICZ "Domoticz 设置" #define D_CONFIGURE_LOGGING "日志设置" #define D_CONFIGURE_OTHER "其他设置" #define D_CONFIRM_RESET_CONFIGURATION "确认重置配置" @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "AP1 名称" -#define D_AP1_PASSWORD "AP1 密码" -#define D_AP2_SSID "AP2 名称" -#define D_AP2_PASSWORD "AP2 密码" +#define D_AP1_SSID "WiFi 名称" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" +#define D_AP2_SSID "WiFi 名称 2" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "WiFi 密码" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "MQTT 设置" #define D_CLIENT "客户端" @@ -314,10 +323,10 @@ #define D_ACTIVATE "启用" #define D_DEVICE_NAME "Device Name" #define D_WEB_ADMIN_PASSWORD "WEB 管理密码" -#define D_MQTT_ENABLE "启用MQTT" +#define D_MQTT_ENABLE "启用 MQTT" #define D_MQTT_TLS_ENABLE "MQTT TLS" #define D_FRIENDLY_NAME "昵称" -#define D_BELKIN_WEMO "贝尔金 WeMo" +#define D_BELKIN_WEMO "Belkin WeMo" #define D_HUE_BRIDGE "飞利浦 Hue 网桥" #define D_SINGLE_DEVICE "单设备" #define D_MULTI_DEVICE "多设备" @@ -463,30 +472,30 @@ #define D_KNX_RX_SCENE "KNX SCENE RX" // xdrv_23_zigbee -#define D_ZIGBEE_PERMITJOIN_ACTIVE "Devices allowed to join" +#define D_ZIGBEE_PERMITJOIN_ACTIVE "允许设备连入" #define D_ZIGBEE_MAPPING_TITLE "Tasmota Zigbee Mapping" -#define D_ZIGBEE_NOT_STARTED "Zigbee not started" +#define D_ZIGBEE_NOT_STARTED "Zigbee 未启动" #define D_ZIGBEE_MAPPING_IN_PROGRESS_SEC "Mapping in progress (%d s. remaining)" #define D_ZIGBEE_MAPPING_NOT_PRESENT "No mapping" #define D_ZIGBEE_MAP_REFRESH "Zigbee Map Refresh" #define D_ZIGBEE_MAP "Zigbee Map" -#define D_ZIGBEE_PERMITJOIN "Zigbee Permit Join" -#define D_ZIGBEE_GENERATE_KEY "generating random Zigbee network key" -#define D_ZIGBEE_UNKNOWN_DEVICE "Unknown device" -#define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Unknown attribute" -#define D_ZIGBEE_INVALID_PARAM "Invalid parameter" -#define D_ZIGBEE_MISSING_PARAM "Missing parameters" -#define D_ZIGBEE_UNKNWON_ATTRIBUTE "Unknown attribute name (ignored): %s" -#define D_ZIGBEE_TOO_MANY_CLUSTERS "No more than one cluster id per command" -#define D_ZIGBEE_WRONG_DELIMITER "Wrong delimiter for payload" -#define D_ZIGBEE_UNRECOGNIZED_COMMAND "Unrecognized zigbee command: %s" -#define D_ZIGBEE_TOO_MANY_COMMANDS "Only 1 command allowed (%d)" -#define D_ZIGBEE_NO_ATTRIBUTE "No attribute in list" -#define D_ZIGBEE_UNSUPPORTED_ATTRIBUTE_TYPE "Unsupported attribute type" -#define D_ZIGBEE_JSON_REQUIRED "Config requires JSON objects" +#define D_ZIGBEE_PERMITJOIN "Zigbee 允许连入" +#define D_ZIGBEE_GENERATE_KEY "正在生成 Zigbee 网络随机秘钥" +#define D_ZIGBEE_UNKNOWN_DEVICE "未知设备" +#define D_ZIGBEE_UNKNOWN_ATTRIBUTE "未知属性" +#define D_ZIGBEE_INVALID_PARAM "参数无效" +#define D_ZIGBEE_MISSING_PARAM "缺失参数" +#define D_ZIGBEE_UNKNWON_ATTRIBUTE "未知属性名称: %s , 忽略" +#define D_ZIGBEE_TOO_MANY_CLUSTERS "每个命令不应有多个簇 ID" +#define D_ZIGBEE_WRONG_DELIMITER "消息体分隔符错误" +#define D_ZIGBEE_UNRECOGNIZED_COMMAND "无法识别的 Zigbee 命令: %s" +#define D_ZIGBEE_TOO_MANY_COMMANDS "只允许一个命令 (%d)" +#define D_ZIGBEE_NO_ATTRIBUTE "列表中没有属性" +#define D_ZIGBEE_UNSUPPORTED_ATTRIBUTE_TYPE "不支持的属性类型" +#define D_ZIGBEE_JSON_REQUIRED "配置需要 JSON 对象" #define D_ZIGBEE_RESET_1_OR_2 "1 or 2 to reset" -#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address" -#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'" +#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "找到 ZBBridge EEPROM, 地址:" +#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "正在随机化 Zigbee 参数, 请通过 'ZbConfig' 检查" // xdrv_03_energy.ino #define D_ENERGY_TODAY "今日用电量" @@ -551,7 +560,7 @@ #define D_RESET_HX711 "秤重置" #define D_CONFIGURE_HX711 "秤配置" #define D_HX711_PARAMETERS "秤参数" -#define D_ITEM_WEIGHT "物品中粮" +#define D_ITEM_WEIGHT "物品重量" #define D_REFERENCE_WEIGHT "参考重量" #define D_CALIBRATE "校准" #define D_CALIBRATION "校准" @@ -810,53 +819,53 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units -#define D_UNIT_AMPERE "安" +#define D_UNIT_AMPERE "A" #define D_UNIT_CELSIUS "C" #define D_UNIT_CENTIMETER "厘米" #define D_UNIT_DEGREE "°" #define D_UNIT_FAHRENHEIT "F" -#define D_UNIT_HERTZ "赫兹" -#define D_UNIT_HOUR "时" +#define D_UNIT_HERTZ "Hz" +#define D_UNIT_HOUR "小时" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" #define D_UNIT_KILOMETER "km" -#define D_UNIT_KILOGRAM "千克" -#define D_UNIT_KILOMETER_PER_HOUR "公里/时" // or "km/h" -#define D_UNIT_KILOOHM "千欧" -#define D_UNIT_KILOWATTHOUR "千瓦时" +#define D_UNIT_KILOGRAM "kg" +#define D_UNIT_KILOMETER_PER_HOUR "km/h" // or "km/h" +#define D_UNIT_KILOOHM "kΩ" +#define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LITERS "L" #define D_UNIT_LITERS_PER_MIN "L/m" -#define D_UNIT_LUX "勒克斯" -#define D_UNIT_MICROGRAM_PER_CUBIC_METER "微克/立方米" -#define D_UNIT_MICROMETER "微米" -#define D_UNIT_MICROSECOND "微秒" +#define D_UNIT_LUX "lx" +#define D_UNIT_MICROGRAM_PER_CUBIC_METER "µg/m³" +#define D_UNIT_MICROMETER "µm" +#define D_UNIT_MICROSECOND "µs" #define D_UNIT_MICROSIEMENS_PER_CM "µS/cm" -#define D_UNIT_MILLIAMPERE "毫安" +#define D_UNIT_MILLIAMPERE "mA" #define D_UNIT_MILLILITERS "ml" -#define D_UNIT_MILLIMETER "毫米" -#define D_UNIT_MILLIMETER_MERCURY "毫米汞柱" -#define D_UNIT_MILLISECOND "毫秒" +#define D_UNIT_MILLIMETER "mm" +#define D_UNIT_MILLIMETER_MERCURY "mmHg" +#define D_UNIT_MILLISECOND "ms" #define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "分" #define D_UNIT_PARTS_PER_BILLION "ppb" -#define D_UNIT_PARTS_PER_DECILITER "每分升" +#define D_UNIT_PARTS_PER_DECILITER "ppd" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_MILIGRAMS_PER_LITER "mg/L" #define D_UNIT_PERCENT "%%" -#define D_UNIT_PRESSURE "百帕" +#define D_UNIT_PRESSURE "hPa" #define D_UNIT_SECOND "秒" #define D_UNIT_SECTORS "扇区" -#define D_UNIT_VA "伏安" -#define D_UNIT_VAR "无功伏安" -#define D_UNIT_VOLT "伏" -#define D_UNIT_WATT "瓦" -#define D_UNIT_WATTHOUR "瓦时" -#define D_UNIT_WATT_METER_QUADRAT "瓦/平米" +#define D_UNIT_VA "VA" +#define D_UNIT_VAR "VAr" +#define D_UNIT_VOLT "V" +#define D_UNIT_WATT "W" +#define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" #define D_NEW_ADDRESS "Setting address to" #define D_OUT_OF_RANGE "Out of Range" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 3af05b2cd..c84fe4607 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -290,10 +290,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "存取點1 SSID" -#define D_AP1_PASSWORD "存取點1 密碼" +#define D_AP1_SSID "存取點 SSID" +#define D_AP1_SSID_HELP "Type or Select your WiFi Network" #define D_AP2_SSID "存取點2 SSID" -#define D_AP2_PASSWORD "存取點2 密碼" +#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP_PASSWORD "存取點 密碼" +#define D_AP_PASSWORD_HELP "Enter your WiFi Password" +#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" +#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" +#define D_SHOW_MORE_OPTIONS "More Options" +#define D_CHECK_CREDENTIALS "Please, check your credentials" +#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" +#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" #define D_MQTT_PARAMETERS "MQTT設定" #define D_CLIENT "客戶端" @@ -810,7 +819,7 @@ #define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" - +#define D_SENSOR_EPD_DATA "EPD Data" // Units #define D_UNIT_AMPERE "安培" @@ -916,6 +925,9 @@ #define D_MANAGE_FILE_SYSTEM "Manage File system" #define D_FS_SIZE "Size" #define D_FS_FREE "Free" +#define D_NEW_FILE "newfile.txt" +#define D_CREATE_NEW_FILE "Create and edit new file" +#define D_EDIT_FILE "Edit File" //xsns_67_as3935.ino #define D_AS3935_GAIN "gain:" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index f2af992f8..f30354df0 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -396,11 +396,14 @@ #define DOMOTICZ_OUT_TOPIC "domoticz/out" // Domoticz Output Topic // -- MQTT - Home Assistant Discovery ------------- -#define USE_HOME_ASSISTANT // Enable Home Assistant Discovery Support (+4.1k code, +6 bytes mem) +#define USE_HOME_ASSISTANT // Enable Home Assistant Discovery Support (+12k code, +6 bytes mem) #define HOME_ASSISTANT_DISCOVERY_PREFIX "homeassistant" // Home Assistant discovery prefix #define HOME_ASSISTANT_LWT_TOPIC "homeassistant/status" // home Assistant Birth and Last Will Topic (default = homeassistant/status) #define HOME_ASSISTANT_LWT_SUBSCRIBE true // Subscribe to Home Assistant Birth and Last Will Topic (default = true) +// -- MQTT - Tasmota Discovery --------------------- +//#define USE_TASMOTA_DISCOVERY // Enable Tasmota Discovery support (+2k code) + // -- MQTT - TLS - AWS IoT ------------------------ // Using TLS starting with version v6.5.0.16 compilation will only work using Core 2.4.2 and 2.5.2. No longer supported: 2.3.0 //#define USE_MQTT_TLS // Use TLS for MQTT connection (+34.5k code, +7.0k mem and +4.8k additional during connection handshake) @@ -897,7 +900,6 @@ // #define ETH_CLKMODE 0 // [EthClockMode] 0 = ETH_CLOCK_GPIO0_IN, 1 = ETH_CLOCK_GPIO0_OUT, 2 = ETH_CLOCK_GPIO16_OUT, 3 = ETH_CLOCK_GPIO17_OUT #define USE_ADC // Add support for ADC on GPIO32 to GPIO39 -#define USE_HALLEFFECT // Add support for internal Hall Effcet sensor connected to GPIO36 and GPIO39 //#define USE_SPI // Add support for hardware SPI //#define USE_MI_ESP32 // Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash) diff --git a/tasmota/settings.h b/tasmota/settings.h index 7d254e6d3..9e8b31d26 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -121,13 +121,13 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t zerocross_dimmer : 1; // bit 17 (v8.3.1.4) - SetOption99 - (PWM Dimmer) Enable zerocross dimmer (1) uint32_t remove_zbreceived : 1; // bit 18 (v8.3.1.7) - SetOption100 - (Zigbee) Remove ZbReceived form JSON message (1) uint32_t zb_index_ep : 1; // bit 19 (v8.3.1.7) - SetOption101 - (Zigbee) Add the source endpoint as suffix to attributes, ex `Power3` (1) instead of `Power` (0) if sent from endpoint 3 - uint32_t teleinfo_baudrate : 1; // bit 20 (v8.4.0.1) - SetOption102 - (Teleinfo) Set Baud rate for Teleinfo communication to 1200 (0) or 9600 (1) + uint32_t obsolete1 : 1; // bit 20 (v9.3.1.3) - SetOption102 - teleinfo_baudrate Obsolete Teleinfo config has now a dedicated bit field uint32_t mqtt_tls : 1; // bit 21 (v8.4.0.1) - SetOption103 - (MQTT TLS) Enable TLS mode (1) (requires TLS version) uint32_t mqtt_no_retain : 1; // bit 22 (v8.4.0.1) - SetOption104 - (MQTT) No Retain (1) - disable all MQTT retained messages, some brokers don't support it: AWS IoT, Losant uint32_t white_blend_mode : 1; // bit 23 (v8.4.0.1) - SetOption105 - (Light) White Blend Mode (1) - used to be `RGBWWTable` last value `0`, now deprecated in favor of this option uint32_t virtual_ct : 1; // bit 24 (v8.4.0.1) - SetOption106 - (Light) Virtual CT (1) - Creates a virtual White ColorTemp for RGBW lights uint32_t virtual_ct_cw : 1; // bit 25 (v8.4.0.1) - SetOption107 - (Light) Virtual CT Channel (1) - signals whether the hardware white is cold CW (true) or warm WW (false) - uint32_t teleinfo_rawdata : 1; // bit 26 (v8.4.0.2) - SetOption108 - (Teleinfo) Enable Teleinfo + Tasmota Energy device (0) or Teleinfo raw data only (1) + uint32_t obsolete2 : 1; // bit 26 (v9.3.1.3) - SetOption108 - teleinfo_rawdata Obsolete Teleinfo config has now a dedicated bit field uint32_t alexa_gen_1 : 1; // bit 27 (v8.4.0.3) - SetOption109 - (Alexa) Gen1 mode (1) - if you only have Echo Dot 2nd gen devices uint32_t zb_disable_autobind : 1; // bit 28 (v8.5.0.1) - SetOption110 - (Zigbee) Disable auto-config (1) when pairing new devices uint32_t buzzer_freq_mode : 1; // bit 29 (v8.5.0.1) - SetOption111 - (Buzzer) Use frequency output (1) for buzzer pin instead of on/off signal (0) @@ -313,6 +313,20 @@ typedef union { }; } As3935Param; +typedef union { + uint32_t data; + struct { + uint32_t raw_skip : 8; // raw frame to skip when sending raw data (set to 2 means send 1 frame, then skip 2, ...) + uint32_t raw_report_changed : 1; // Report only changed values in raw frames (only valid if raw_skip=0) + uint32_t raw_send : 1; // Enable sending also real time raw data over MQTT + uint32_t raw_limit : 1; // Limit raw data to minimal relevant fields (the ones moving quickly) + uint32_t mode_standard : 1; // Set Linky Standard Mode (9600 bps stream) else legacy (1200 bps) + uint32_t spare4_1 : 4; // Keep some spares for future uses + uint32_t spare8_1 : 8; // Keep some spares for future uses + uint32_t spare8_2 : 8; // Keep some spares for future uses + }; +} TeleinfoCfg; + typedef struct { uint32_t usage1_kWhtotal; uint32_t usage2_kWhtotal; @@ -643,10 +657,11 @@ struct { uint16_t shd_warmup_brightness; // F5C uint8_t shd_warmup_time; // F5E - uint8_t free_f5e[72]; // F5E - Decrement if adding new Setting variables just above and below + uint8_t free_f5f[69]; // F5F - Decrement if adding new Setting variables just above and below // Only 32 bit boundary variables below + TeleinfoCfg teleinfo; // FA4 uint64_t rf_protocol_mask; // FA8 uint8_t device_group_tie[4]; // FB0 SysBitfield5 flag5; // FB4 diff --git a/tasmota/settings.ino b/tasmota/settings.ino index 11f835592..9b52b867e 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -750,7 +750,11 @@ void SettingsDefaultSet2(void) { SettingsUpdateText(SET_FRIENDLYNAME2, PSTR(FRIENDLY_NAME"2")); SettingsUpdateText(SET_FRIENDLYNAME3, PSTR(FRIENDLY_NAME"3")); SettingsUpdateText(SET_FRIENDLYNAME4, PSTR(FRIENDLY_NAME"4")); + #ifdef DEVICE_NAME + SettingsUpdateText(SET_DEVICENAME, PSTR(DEVICE_NAME)); + #else SettingsUpdateText(SET_DEVICENAME, SettingsText(SET_FRIENDLYNAME1)); + #endif SettingsUpdateText(SET_OTAURL, PSTR(OTA_URL)); // Power diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index c8b13f2f0..a701203de 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -26,7 +26,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix D_CMND_BUTTONDEBOUNCE "|" D_CMND_SWITCHDEBOUNCE "|" D_CMND_SYSLOG "|" D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_SERIALBUFFER "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALCONFIG "|" 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_DEVICENAME "|" D_CMND_FN "|" 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_LEDPWM_ON "|" D_CMND_LEDPWM_OFF "|" D_CMND_LEDPWM_MODE "|" D_CMND_WIFIPOWER "|" D_CMND_TEMPOFFSET "|" D_CMND_HUMOFFSET "|" D_CMND_SPEEDUNIT "|" D_CMND_GLOBAL_TEMP "|" D_CMND_GLOBAL_HUM"|" D_CMND_SWITCHTEXT "|" #ifdef USE_I2C @@ -54,7 +54,7 @@ void (* const TasmotaCommand[])(void) PROGMEM = { &CmndButtonDebounce, &CmndSwitchDebounce, &CmndSyslog, &CmndLoghost, &CmndLogport, &CmndSerialBuffer, &CmndSerialSend, &CmndBaudrate, &CmndSerialConfig, &CmndSerialDelimiter, &CmndIpAddress, &CmndNtpServer, &CmndAp, &CmndSsid, &CmndPassword, &CmndHostname, &CmndWifiConfig, - &CmndDevicename, &CmndFriendlyname, &CmndSwitchMode, &CmndInterlock, &CmndTeleperiod, &CmndReset, &CmndTime, &CmndTimezone, &CmndTimeStd, + &CmndDevicename, &CmndFriendlyname, &CmndFriendlyname, &CmndSwitchMode, &CmndInterlock, &CmndTeleperiod, &CmndReset, &CmndTime, &CmndTimezone, &CmndTimeStd, &CmndTimeDst, &CmndAltitude, &CmndLedPower, &CmndLedState, &CmndLedMask, &CmndLedPwmOn, &CmndLedPwmOff, &CmndLedPwmMode, &CmndWifiPower, &CmndTempOffset, &CmndHumOffset, &CmndSpeedUnit, &CmndGlobalTemp, &CmndGlobalHum, &CmndSwitchText, #ifdef USE_I2C @@ -237,7 +237,7 @@ void CommandHandler(char* topicBuf, char* dataBuf, uint32_t data_len) type[i] = '\0'; } - AddLog(LOG_LEVEL_DEBUG, PSTR("CMD: " D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " \"%s\", " D_DATA " \"%s\""), grpflg, index, type, dataBuf); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("CMD: " D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " \"%s\", " D_DATA " \"%s\""), grpflg, index, type, dataBuf); if (type != nullptr) { Response_P(PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_ERROR "\"}")); @@ -317,9 +317,14 @@ void CommandHandler(char* topicBuf, char* dataBuf, uint32_t data_len) /********************************************************************************************/ -void CmndBacklog(void) -{ +void CmndBacklog(void) { + // Backlog command1;command2;.. Execute commands in sequence with a delay in between set with SetOption34 + // Backlog0 command1;command2;.. Execute commands in sequence with no delay + if (XdrvMailbox.data_len) { + if (0 == XdrvMailbox.index) { + TasmotaGlobal.backlog_nodelay = true; + } #ifdef SUPPORT_IF_STATEMENT char *blcommand = strtok(XdrvMailbox.data, ";"); @@ -970,11 +975,16 @@ void CmndSetoptionBase(bool indexed) { TasmotaGlobal.stop_flash_rotate = XdrvMailbox.payload; SettingsSave(2); } - #ifdef USE_HOME_ASSISTANT +#ifdef USE_HOME_ASSISTANT if ((19 == pindex) || (30 == pindex)) { HAssDiscover(); // Delayed execution to provide enough resources during hass_discovery or hass_light } - #endif // USE_HOME_ASSISTANT +#endif // USE_HOME_ASSISTANT +#ifdef USE_TASMOTA_DISCOVERY + if (19 == pindex) { + TasRediscover(); + } +#endif // USE_TASMOTA_DISCOVERY } else if (3 == ptype) { // SetOption50 .. 81 bitWrite(Settings.flag3.data, pindex, XdrvMailbox.payload); @@ -1652,14 +1662,23 @@ void CmndSsid(void) void CmndPassword(void) { - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) { + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 4)) { + bool show_asterisk = (XdrvMailbox.index > 2); + if (show_asterisk) { + XdrvMailbox.index -= 2; + } if ((XdrvMailbox.data_len > 4) || (SC_CLEAR == Shortcut()) || (SC_DEFAULT == Shortcut())) { SettingsUpdateText(SET_STAPWD1 + XdrvMailbox.index -1, (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? (1 == XdrvMailbox.index) ? STA_PASS1 : STA_PASS2 : XdrvMailbox.data); Settings.sta_active = XdrvMailbox.index -1; TasmotaGlobal.restart_flag = 2; - ResponseCmndIdxChar(SettingsText(SET_STAPWD1 + XdrvMailbox.index -1)); + if (!show_asterisk) { + ResponseCmndIdxChar(SettingsText(SET_STAPWD1 + XdrvMailbox.index -1)); + } } else { + show_asterisk = true; + } + if (show_asterisk) { Response_P(S_JSON_COMMAND_INDEX_ASTERISK, XdrvMailbox.command, XdrvMailbox.index); } } @@ -1703,6 +1722,7 @@ void CmndDevicename(void) void CmndFriendlyname(void) { + snprintf_P(XdrvMailbox.command, CMDSZ, PSTR(D_CMND_FRIENDLYNAME)); // Rename result shortcut command FN to FriendlyName if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_FRIENDLYNAMES)) { if (!XdrvMailbox.usridx && !XdrvMailbox.data_len) { ResponseCmndAll(SET_FRIENDLYNAME1, MAX_FRIENDLYNAMES); diff --git a/tasmota/support_esp.ino b/tasmota/support_esp.ino index 65dd3871c..a1a469b96 100644 --- a/tasmota/support_esp.ino +++ b/tasmota/support_esp.ino @@ -457,7 +457,6 @@ uint8_t* FlashDirectAccess(void) { return data; } - void *special_malloc(uint32_t size) { if (psramFound()) { return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); @@ -473,6 +472,10 @@ void *special_realloc(void *ptr, size_t size) { } } +float CpuTemperature(void) { + return ConvertTemp(temperatureRead()); +} + #endif // ESP32 /*********************************************************************************************\ diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index 3cd84d00f..8051e4eb8 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -737,9 +737,7 @@ void ResponseAppendFeatures(void) #ifdef USE_BERRY feature8 |= 0x00000008; // xdrv_52_9_berry.ino #endif -#ifdef USE_HALLEFFECT - feature8 |= 0x00000010; // xsns_87_esp32_halleffect.ino -#endif +// feature8 |= 0x00000010; #if defined(USE_ENERGY_SENSOR) && defined(USE_ENERGY_DUMMY) feature8 |= 0x00000020; #endif diff --git a/tasmota/support_network.ino b/tasmota/support_network.ino index 242c03121..c033b0fdc 100644 --- a/tasmota/support_network.ino +++ b/tasmota/support_network.ino @@ -127,3 +127,9 @@ String NetworkMacAddress(void) { #endif return WiFi.macAddress(); } + +String NetworkUniqueId(void) { + String unique_id = WiFi.macAddress(); + unique_id.replace(":", ""); // Full 12 chars MAC address as ID + return unique_id; +} diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 078d32b8c..dab8dffc0 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -43,8 +43,7 @@ char* Format(char* output, const char* input_p, int size) snprintf_P(tmp, size, PSTR("%s%c0%dd"), output, '%', digits); snprintf_P(output, size, tmp, ESP_getChipId() & 0x1fff); // %04d - short chip ID in dec, like in hostname } else { - String mac_address = WiFi.macAddress(); - mac_address.replace(":", ""); + String mac_address = NetworkUniqueId(); if (digits > 12) { digits = 12; } String mac_part = mac_address.substring(12 - digits); snprintf_P(output, size, PSTR("%s%s"), output, mac_part.c_str()); // %01X .. %12X - mac address in hex @@ -122,9 +121,7 @@ char* GetTopic_P(char *stopic, uint32_t prefix, char *topic, const char* subtopi fulltopic.replace(FPSTR(MQTT_TOKEN_TOPIC), (const __FlashStringHelper *)topic); fulltopic.replace(F("%hostname%"), TasmotaGlobal.hostname); - String token_id = WiFi.macAddress(); - token_id.replace(":", ""); - fulltopic.replace(F("%id%"), token_id); + fulltopic.replace(F("%id%"), NetworkUniqueId()); } fulltopic.replace(F("#"), ""); fulltopic.replace(F("//"), "/"); @@ -889,7 +886,7 @@ void PerformEverySecond(void) Settings.last_module = Settings.module; #ifdef USE_DEEPSLEEP - if (!(DeepSleepEnabled() && !Settings.flag3.bootcount_update)) { + if (!(DeepSleepEnabled() && !Settings.flag3.bootcount_update)) { // SetOption76 - (Deepsleep) Enable incrementing bootcount (1) when deepsleep is enabled #endif Settings.bootcount++; // Moved to here to stop flash writes during start-up AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BOOT_COUNT " %d"), Settings.bootcount); @@ -1308,7 +1305,7 @@ void Every250mSeconds(void) if (Settings.webserver) { #ifdef ESP8266 - StartWebserver(Settings.webserver, WiFi.localIP()); + if (!WifiIsInManagerMode()) { StartWebserver(Settings.webserver, WiFi.localIP()); } #endif // ESP8266 #ifdef ESP32 #ifdef USE_ETHERNET diff --git a/tasmota/support_wifi.ino b/tasmota/support_wifi.ino index 804070103..e85374eda 100644 --- a/tasmota/support_wifi.ino +++ b/tasmota/support_wifi.ino @@ -106,7 +106,6 @@ void WifiConfig(uint8_t type) } #ifdef USE_WEBSERVER else if (WIFI_MANAGER == Wifi.config_type || WIFI_MANAGER_RESET_ONLY == Wifi.config_type) { - AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_WCFG_2_WIFIMANAGER " " D_ACTIVE_FOR_3_MINUTES)); WifiManagerBegin(WIFI_MANAGER_RESET_ONLY == Wifi.config_type); } #endif // USE_WEBSERVER diff --git a/tasmota/tasmota.h b/tasmota/tasmota.h index f270e5cef..c9d58fd05 100644 --- a/tasmota/tasmota.h +++ b/tasmota/tasmota.h @@ -234,7 +234,7 @@ const uint32_t LOOP_SLEEP_DELAY = 50; // Lowest number of milliseconds to #define KNX_ENERGY_POWER 21 #define KNX_ENERGY_POWERFACTOR 22 #define KNX_ENERGY_DAILY 23 -#define KNX_ENERGY_START 24 +#define KNX_ENERGY_YESTERDAY 24 #define KNX_ENERGY_TOTAL 25 #define KNX_SLOT1 26 #define KNX_SLOT2 27 diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 59735a55f..55272c584 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -98,6 +98,8 @@ * Global variables \*********************************************************************************************/ +const uint32_t VERSION_MARKER[] PROGMEM = { 0x5AA55AA5, 0xFFFFFFFF, 0xA55AA55A }; + WiFiUDP PortUdp; // UDP Syslog and Alexa struct { @@ -141,6 +143,7 @@ struct { bool rule_teleperiod; // Process rule based on teleperiod data using prefix TELE- bool serial_local; // Handle serial locally bool fallback_topic_flag; // Use Topic or FallbackTopic + bool backlog_nodelay; // Execute all backlog commands with no delay bool backlog_mutex; // Command backlog pending bool stop_flash_rotate; // Allow flash configuration rotation bool blinkstate; // LED state @@ -363,6 +366,8 @@ void setup(void) { AddLog(LOG_LEVEL_INFO, PSTR(D_WARNING_MINIMAL_VERSION)); #endif // FIRMWARE_MINIMAL + memcpy_P(TasmotaGlobal.mqtt_data, VERSION_MARKER, 1); // Dummy for compiler saving VERSION_MARKER + #ifdef USE_ARDUINO_OTA ArduinoOTAInit(); #endif // USE_ARDUINO_OTA @@ -398,16 +403,19 @@ void BacklogLoop(void) { if (!nodelay_detected) { ExecuteCommand((char*)cmd.c_str(), SRC_BACKLOG); } - if (nodelay) { + if (nodelay || TasmotaGlobal.backlog_nodelay) { TasmotaGlobal.backlog_timer = millis(); // Reset backlog_timer which has been set by ExecuteCommand (CommandHandler) } TasmotaGlobal.backlog_mutex = false; } + if (BACKLOG_EMPTY) { + TasmotaGlobal.backlog_nodelay = false; + } } } void SleepDelay(uint32_t mseconds) { - if (mseconds) { + if (!TasmotaGlobal.backlog_nodelay && mseconds) { uint32_t wait = millis() + mseconds; while (!TimeReached(wait) && !Serial.available()) { // We need to service serial buffer ASAP as otherwise we get uart buffer overrun delay(1); diff --git a/tasmota/tasmota_configurations_ESP32.h b/tasmota/tasmota_configurations_ESP32.h index 8d7295ce4..ef568017d 100644 --- a/tasmota/tasmota_configurations_ESP32.h +++ b/tasmota/tasmota_configurations_ESP32.h @@ -187,7 +187,6 @@ #define USE_LIGHT_PALETTE // Add support for color palette (+0k9 code) -#define USE_HALLEFFECT // Add support for internal Hall Effcet sensor connected to GPIO36 and GPIO39 #define USE_DS18x20 // Add support for DS18x20 sensors with id sort, single scan and read retry (+1k3 code) #define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram) diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index ae4741ff8..74940db07 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -160,6 +160,7 @@ enum UserSelectablePins { GPIO_ZEROCROSS, #ifdef ESP32 GPIO_HALLEFFECT, + GPIO_EPD_DATA, // Base connection EPD driver #endif GPIO_SENSOR_END }; @@ -168,14 +169,14 @@ enum ProgramSelectablePins { GPIO_USER, // User configurable needs to be 2047 GPIO_MAX }; -#define MAX_OPTIONS_A 2 // Increase if more bits are used from GpioOptionABits +#define MAX_OPTIONS_A 3 // Increase if more bits are used from GpioOptionABits typedef union { // Restricted by MISRA-C Rule 18.4 but so useful... uint32_t data; // Allow bit manipulation using SetOption struct { // GPIO Option_A1 .. Option_A32 uint32_t pwm1_input : 1; // bit 0 (v9.2.0.1) - Option_A1 - (Light) Change PWM1 to input on power off and no fade running (1) uint32_t dummy_energy : 1; // bit 1 (v9.3.1.2) - Option_A2 - (Energy) Enable dummy values - uint32_t spare02 : 1; // bit 2 + uint32_t udisplay_driver : 1; // bit 2 (v9.3.1.2) - Option_A3 - (Display) Universal display driver uint32_t spare03 : 1; // bit 3 uint32_t spare04 : 1; // bit 4 uint32_t spare05 : 1; // bit 5 @@ -341,6 +342,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_ZEROCROSS "|" #ifdef ESP32 D_SENSOR_HALLEFFECT "|" + D_SENSOR_EPD_DATA "|" #endif ; @@ -470,6 +472,9 @@ const uint16_t kGpioNiceList[] PROGMEM = { #endif // USE_DISPLAY_TM1637 AGPIO(GPIO_BACKLIGHT), // Display backlight control AGPIO(GPIO_OLED_RESET), // OLED Display Reset +#ifdef ESP32 + AGPIO(GPIO_EPD_DATA), // Base connection EPD driver +#endif #endif // USE_DISPLAY #ifdef USE_MAX31865 diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 5b6797f57..342fd3f97 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -25,15 +25,28 @@ * Based on source by AlexT (https://github.com/tzapu) \*********************************************************************************************/ -#define XDRV_01 1 +#define XDRV_01 1 // Enable below demo feature only if defines USE_UNISHOX_COMPRESSION and USE_SCRIPT_WEB_DISPLAY are disabled //#define USE_WEB_SSE #ifndef WIFI_SOFT_AP_CHANNEL -#define WIFI_SOFT_AP_CHANNEL 1 // Soft Access Point Channel number between 1 and 11 as used by WifiManager web GUI +#define WIFI_SOFT_AP_CHANNEL 1 // Soft Access Point Channel number between 1 and 11 as used by WifiManager web GUI #endif +#ifndef MAX_WIFI_NETWORKS_TO_SHOW +#define MAX_WIFI_NETWORKS_TO_SHOW 3 // Maximum number of Wifi Networks to show in the Wifi Configuration Menu BEFORE clicking on Show More Networks. +#endif + +#ifndef RESTART_AFTER_INITIAL_WIFI_CONFIG +#define RESTART_AFTER_INITIAL_WIFI_CONFIG true // Restart Tasmota after initial Wifi Config of a blank device +#endif // If disabled, Tasmota will keep both the wifi AP and the wifi connection to the router + // but only until next restart. +#ifndef AFTER_INITIAL_WIFI_CONFIG_GO_TO_NEW_IP // If RESTART_AFTER_INITIAL_WIFI_CONFIG and AFTER_INITIAL_WIFI_CONFIG_GO_TO_NEW_IP are true, +#define AFTER_INITIAL_WIFI_CONFIG_GO_TO_NEW_IP true // the user will be redirected to the new IP of Tasmota (in the new Network). +#endif // If the first is true, but this is false, the device will restart but the user will see + // a window telling that the WiFi Configuration was Ok and that the window can be closed. + const uint16_t CHUNKED_BUFFER_SIZE = (MESSZ / 2) - 100; // Chunk buffer size (should be smaller than half mqtt_data size = MESSZ) const uint16_t HTTP_REFRESH_TIME = 2345; // milliseconds @@ -95,13 +108,23 @@ const char HTTP_SCRIPT_COUNTER[] PROGMEM = #include "./html_uncompressed/HTTP_SCRIPT_ROOT_PART2.h" #endif - const char HTTP_SCRIPT_WIFI[] PROGMEM = "function c(l){" "eb('s1').value=l.innerText||l.textContent;" "eb('p1').focus();" "}"; +const char HTTP_SCRIPT_HIDE[] PROGMEM = + "function hidBtns() {" + "eb('butmo').style.display='none';" + "eb('butmod').style.display='none';" + "eb('but0').style.display='block';" + "eb('but1').style.display='block';" + "eb('but13').style.display='block';" + "eb('but0d').style.display='block';" + "eb('but13d').style.display='block';" + "}"; + const char HTTP_SCRIPT_RELOAD_TIME[] PROGMEM = "setTimeout(function(){location.href='.';},%d);"; @@ -111,14 +134,11 @@ const char HTTP_SCRIPT_RELOAD_TIME[] PROGMEM = #include "./html_uncompressed/HTTP_SCRIPT_CONSOL.h" #endif - const char HTTP_MODULE_TEMPLATE_REPLACE_INDEX[] PROGMEM = "}2%d'>%s (%d)}3"; // }2 and }3 are used in below os.replace const char HTTP_MODULE_TEMPLATE_REPLACE_NO_INDEX[] PROGMEM = "}2%d'>%s}3"; // }2 and }3 are used in below os.replace - - #ifdef USE_UNISHOX_COMPRESSION #include "./html_compressed/HTTP_SCRIPT_MODULE_TEMPLATE.h" #include "./html_compressed/HTTP_SCRIPT_TEMPLATE.h" @@ -127,7 +147,6 @@ const char HTTP_MODULE_TEMPLATE_REPLACE_NO_INDEX[] PROGMEM = #include "./html_uncompressed/HTTP_SCRIPT_TEMPLATE.h" #endif - const char HTTP_SCRIPT_TEMPLATE2[] PROGMEM = "j=0;" "for(i=0;i<" STR(MAX_USER_PINS) ";i++){" // Supports 13 GPIOs @@ -175,7 +194,6 @@ const char HTTP_SCRIPT_INFO_END[] PROGMEM = "}" "wl(i);"; - #ifdef USE_UNISHOX_COMPRESSION #include "./html_compressed/HTTP_HEAD_LAST_SCRIPT.h" #include "./html_compressed/HTTP_HEAD_STYLE1.h" @@ -186,7 +204,6 @@ const char HTTP_SCRIPT_INFO_END[] PROGMEM = #include "./html_uncompressed/HTTP_HEAD_STYLE2.h" #endif - #ifdef USE_ZIGBEE // Styles used for Zigbee Web UI // Battery icon from https://css.gg/battery @@ -259,13 +276,16 @@ const char HTTP_FORM_MODULE[] PROGMEM = "

" D_MODULE_TYPE " (%s)

" "
"; -const char HTTP_FORM_WIFI[] PROGMEM = +const char HTTP_FORM_WIFI_PART1[] PROGMEM = "
 " D_WIFI_PARAMETERS " " "
" - "

" D_AP1_SSID " (" STA_SSID1 ")

" // Need \" instead of ' to be able to use ' in text (#8489) - "


" - "

" D_AP2_SSID " (" STA_SSID2 ")

" - "


" + "

" D_AP1_SSID "%s

" // Need \" instead of ' to be able to use ' in text (#8489) + "


" + "

" D_AP2_SSID " (" STA_SSID2 ")

" + "


" "

" D_HOSTNAME " (%s)

" "

" D_CORS_DOMAIN "

"; @@ -366,6 +386,7 @@ const char kUploadErrors[] PROGMEM = const uint16_t DNS_PORT = 53; enum HttpOptions {HTTP_OFF, HTTP_USER, HTTP_ADMIN, HTTP_MANAGER, HTTP_MANAGER_RESET_ONLY}; +enum WifiTestOptions {WIFI_NOT_TESTING, WIFI_TESTING, WIFI_TEST_FINISHED_SUCCESSFUL, WIFI_TEST_FINISHED_BAD}; DNSServer *DnsServer; ESP8266WebServer *Webserver; @@ -380,6 +401,11 @@ struct WEB { uint8_t config_xor_on_set = CONFIG_FILE_XOR; bool upload_services_stopped = false; bool reset_web_log_flag = false; // Reset web console log + bool initial_config = false; + uint8_t wifiTest = WIFI_NOT_TESTING; + uint8_t wifi_test_counter = 0; + uint16_t save_data_counter = 0; + uint8_t old_wificonfig = WIFI_MANAGER; } Web; // Helper function to avoid code duplication (saves 4k Flash) @@ -403,13 +429,16 @@ void ShowWebSource(uint32_t source) } } -void ExecuteWebCommand(char* svalue, uint32_t source) -{ +void ExecuteWebCommand(char* svalue, uint32_t source) { ShowWebSource(source); TasmotaGlobal.last_source = source; ExecuteCommand(svalue, SRC_IGNORE); } +void ExecuteWebCommand(char* svalue) { + ExecuteWebCommand(svalue, SRC_WEBGUI); +} + // replace the series of `Webserver->on()` with a table in PROGMEM typedef struct WebServerDispatch_t { char uri[3]; // the prefix "/" is added automatically @@ -494,8 +523,8 @@ void StartWebserver(int type, IPAddress ipweb) NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", (uint32_t)ipweb); #endif // LWIP_IPV6 = 1 TasmotaGlobal.rules_flag.http_init = 1; + Web.state = type; } - if (type) { Web.state = type; } } void StopWebserver(void) @@ -510,6 +539,7 @@ void StopWebserver(void) void WifiManagerBegin(bool reset_only) { // setup AP + if (!Web.initial_config) { AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_WCFG_2_WIFIMANAGER " " D_ACTIVE_FOR_3_MINUTES)); } if (!TasmotaGlobal.global_state.wifi_down) { // WiFi.mode(WIFI_AP_STA); WifiSetMode(WIFI_AP_STA); @@ -520,7 +550,7 @@ void WifiManagerBegin(bool reset_only) AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_WIFIMANAGER_SET_ACCESSPOINT)); } - StopWebserver(); + //StopWebserver(); DnsServer = new DNSServer(); @@ -714,7 +744,7 @@ void WSContentStart_P(const char* title) void WSContentSendStyle_P(const char* formatP, ...) { - if (WifiIsInManagerMode()) { + if ( WifiIsInManagerMode() && (!Web.initial_config) ) { if (WifiConfigCounter()) { WSContentSend_P(HTTP_SCRIPT_COUNTER); } @@ -750,8 +780,14 @@ void WSContentSendStyle_P(const char* formatP, ...) WebColor(COL_TEXT_WARNING), #endif WebColor(COL_TITLE), - ModuleName().c_str(), SettingsText(SET_DEVICENAME)); - if (Settings.flag3.gui_hostname_ip) { // SetOption53 - Show hostanme and IP address in GUI main menu + (Web.initial_config) ? "" : ModuleName().c_str(), SettingsText(SET_DEVICENAME)); + + // SetOption53 - Show hostname and IP address in GUI main menu +#if (RESTART_AFTER_INITIAL_WIFI_CONFIG) + if (Settings.flag3.gui_hostname_ip) { +#else + if ( Settings.flag3.gui_hostname_ip || ( (WiFi.getMode() == WIFI_AP_STA) && (!Web.initial_config) ) ) { +#endif bool lip = (static_cast(WiFi.localIP()) != 0); bool sip = (static_cast(WiFi.softAPIP()) != 0); WSContentSend_P(PSTR("

%s%s (%s%s%s)

"), // tasmota.local (192.168.2.12, 192.168.4.1) @@ -769,29 +805,31 @@ void WSContentSendStyle(void) WSContentSendStyle_P(nullptr); } -void WSContentButton(uint32_t title_index) +void WSContentButton(uint32_t title_index, bool show=true) { char action[4]; char title[100]; // Large to accomodate UTF-16 as used by Russian + WSContentSend_P(PSTR("

"), - GetTextIndexed(action, sizeof(action), title_index, kButtonAction), + WSContentSend_P(PSTR(" onsubmit='return confirm(\"%s\");'>

"), GetTextIndexed(confirm, sizeof(confirm), title_index, kButtonConfirm), (!title_index) ? PSTR("rst") : PSTR("non"), GetTextIndexed(title, sizeof(title), title_index, kButtonTitle)); } else { - WSContentSend_P(PSTR("

"), - GetTextIndexed(action, sizeof(action), title_index, kButtonAction), + WSContentSend_P(PSTR(">

"), GetTextIndexed(title, sizeof(title), title_index, kButtonTitle)); } } -void WSContentSpaceButton(uint32_t title_index) +void WSContentSpaceButton(uint32_t title_index, bool show=true) { - WSContentSend_P(PSTR("
")); // 5px padding - WSContentButton(title_index); + WSContentSend_P(PSTR("
"),title_index, show ? "block":"none"); // 5px padding + WSContentButton(title_index, show); } void WSContentSend_Temp(const char *types, float f_temperature) { @@ -818,7 +856,7 @@ void WSContentEnd(void) void WSContentStop(void) { - if (WifiIsInManagerMode()) { + if ( WifiIsInManagerMode() && (!Web.initial_config) ) { if (WifiConfigCounter()) { WSContentSend_P(HTTP_COUNTER); } @@ -833,31 +871,53 @@ void WebRestart(uint32_t type) { // type 0 = restart // type 1 = restart after config change - // type 2 = restart after config change with possible ip address change too - AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_RESTART)); - + // type 2 = Checking WiFi Connection - no restart, only refresh page. + // type 3 = restart after WiFi Connection Test Successful bool reset_only = (HTTP_MANAGER_RESET_ONLY == Web.state); WSContentStart_P((type) ? PSTR(D_SAVE_CONFIGURATION) : PSTR(D_RESTART), !reset_only); - WSContentSend_P(HTTP_SCRIPT_RELOAD_TIME, HTTP_RESTART_RECONNECT_TIME); +#if ((RESTART_AFTER_INITIAL_WIFI_CONFIG) && (AFTER_INITIAL_WIFI_CONFIG_GO_TO_NEW_IP)) + // In case of type 3 (New network has been configured) go to the new device's IP in the new Network + if (3 == type) { + WSContentSend_P("setTimeout(function(){location.href='http://%_I';},%d);", + (uint32_t)WiFi.localIP(), + HTTP_RESTART_RECONNECT_TIME + ); + } else { + WSContentSend_P(HTTP_SCRIPT_RELOAD_TIME, HTTP_RESTART_RECONNECT_TIME); + } +#else + // In case of type 3 (New network has been configured) do not refresh the page. Just halt. + // The IP of the device while was in AP mode, won't be the new IP of the newly configured Network. + if (!(3 == type)) { WSContentSend_P(HTTP_SCRIPT_RELOAD_TIME, HTTP_RESTART_RECONNECT_TIME); } +#endif WSContentSendStyle(); if (type) { - WSContentSend_P(PSTR("
" D_CONFIGURATION_SAVED "
")); - if (2 == type) { - WSContentSend_P(PSTR("
" D_TRYING_TO_CONNECT "
")); + if (!(3 == type)) { + WSContentSend_P(PSTR("
%s

"), (type==2) ? PSTR(D_TRYING_TO_CONNECT) : PSTR(D_CONFIGURATION_SAVED) ); + } else { +#if (AFTER_INITIAL_WIFI_CONFIG_GO_TO_NEW_IP) + WSContentSend_P(PSTR("
" D_SUCCESSFUL_WIFI_CONNECTION "

" D_REDIRECTING_TO_NEW_IP "

"), WebColor(COL_TEXT_SUCCESS) ); +#else + WSContentSend_P(PSTR("
" D_SUCCESSFUL_WIFI_CONNECTION "

" D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "

"), WebColor(COL_TEXT_SUCCESS) ); +#endif } - WSContentSend_P(PSTR("
")); } - WSContentSend_P(HTTP_MSG_RSTRT); - if (HTTP_MANAGER == Web.state || reset_only) { - Web.state = HTTP_ADMIN; - } else { - WSContentSpaceButton(BUTTON_MAIN); + if (type<2) { + WSContentSend_P(HTTP_MSG_RSTRT); + if (HTTP_MANAGER == Web.state || reset_only) { + Web.state = HTTP_ADMIN; + } else { + WSContentSpaceButton(BUTTON_MAIN); + } } WSContentStop(); - ShowWebSource(SRC_WEBGUI); - TasmotaGlobal.restart_flag = 2; + if (!(2 == type)) { + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_RESTART)); + ShowWebSource(SRC_WEBGUI); + TasmotaGlobal.restart_flag = 2; + } } /*********************************************************************************************/ @@ -916,6 +976,10 @@ void HandleRoot(void) HandleWifiLogin(); } else { if (!strlen(SettingsText(SET_WEBPWD)) || (((Webserver->arg(F("USER1")) == WEB_USERNAME ) && (Webserver->arg(F("PASS1")) == SettingsText(SET_WEBPWD) )) || HTTP_MANAGER_RESET_ONLY == Web.state)) { + if (!Web.initial_config) { + Web.initial_config = !strlen(SettingsText(SET_STASSID1)); + if (Web.initial_config) { AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP "Blank Device - Initial Configuration")); } + } HandleWifiConfiguration(); } else { // wrong user and pass @@ -1168,7 +1232,7 @@ bool HandleRootStatusRefresh(void) int32_t ShutterWebButton; if (ShutterWebButton = IsShutterWebButton(device)) { snprintf_P(svalue, sizeof(svalue), PSTR("ShutterPosition%d %s"), abs(ShutterWebButton), (ShutterWebButton>0) ? PSTR(D_CMND_SHUTTER_STOPOPEN) : PSTR(D_CMND_SHUTTER_STOPCLOSE)); - ExecuteWebCommand(svalue, SRC_WEBGUI); + ExecuteWebCommand(svalue); } else { #endif // USE_SHUTTER ExecuteCommandPower(device, POWER_TOGGLE, SRC_IGNORE); @@ -1186,12 +1250,12 @@ bool HandleRootStatusRefresh(void) WebGetArg(PSTR("d0"), tmp, sizeof(tmp)); // 0 - 100 Dimmer value if (strlen(tmp)) { snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_DIMMER " %s"), tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); + ExecuteWebCommand(svalue); } WebGetArg(PSTR("w0"), tmp, sizeof(tmp)); // 0 - 100 White value if (strlen(tmp)) { snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_WHITE " %s"), tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); + ExecuteWebCommand(svalue); } uint32_t light_device = LightDevice(); // Channel number offset uint32_t pwm_channels = (TasmotaGlobal.light_type & 7) > LST_MAX ? LST_MAX : (TasmotaGlobal.light_type & 7); @@ -1200,23 +1264,23 @@ bool HandleRootStatusRefresh(void) WebGetArg(webindex, tmp, sizeof(tmp)); // 0 - 100 percent if (strlen(tmp)) { snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_CHANNEL "%d %s"), j +light_device, tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); + ExecuteWebCommand(svalue); } } WebGetArg(PSTR("t0"), tmp, sizeof(tmp)); // 153 - 500 Color temperature if (strlen(tmp)) { snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_COLORTEMPERATURE " %s"), tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); + ExecuteWebCommand(svalue); } WebGetArg(PSTR("h0"), tmp, sizeof(tmp)); // 0 - 359 Hue value if (strlen(tmp)) { snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_HSBCOLOR "1 %s"), tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); + ExecuteWebCommand(svalue); } WebGetArg(PSTR("n0"), tmp, sizeof(tmp)); // 0 - 99 Saturation value if (strlen(tmp)) { snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_HSBCOLOR "2 %s"), tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); + ExecuteWebCommand(svalue); } #endif // USE_LIGHT #ifdef USE_SHUTTER @@ -1225,7 +1289,7 @@ bool HandleRootStatusRefresh(void) WebGetArg(webindex, tmp, sizeof(tmp)); // 0 - 100 percent if (strlen(tmp)) { snprintf_P(svalue, sizeof(svalue), PSTR("ShutterPosition%d %s"), j, tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); + ExecuteWebCommand(svalue); } } #endif // USE_SHUTTER @@ -1233,19 +1297,19 @@ bool HandleRootStatusRefresh(void) WebGetArg(PSTR("k"), tmp, sizeof(tmp)); // 1 - 16 Pre defined RF keys if (strlen(tmp)) { snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_RFKEY "%s"), tmp); - ExecuteWebCommand(svalue, SRC_WEBGUI); + ExecuteWebCommand(svalue); } #endif // USE_SONOFF_RF #ifdef USE_ZIGBEE WebGetArg(PSTR("zbj"), tmp, sizeof(tmp)); if (strlen(tmp)) { snprintf_P(svalue, sizeof(svalue), PSTR("ZbPermitJoin")); - ExecuteWebCommand(svalue, SRC_WEBGUI); + ExecuteWebCommand(svalue); } WebGetArg(PSTR("zbr"), tmp, sizeof(tmp)); if (strlen(tmp)) { snprintf_P(svalue, sizeof(svalue), PSTR("ZbMap")); - ExecuteWebCommand(svalue, SRC_WEBGUI); + ExecuteWebCommand(svalue); } #endif // USE_ZIGBEE @@ -1400,8 +1464,7 @@ void WSContentSendAdcNiceList(uint32_t option) { /*-------------------------------------------------------------------------------------------*/ -void HandleTemplateConfiguration(void) -{ +void HandleTemplateConfiguration(void) { if (!HttpCheckPriviledgedAccess()) { return; } if (Webserver->hasArg(F("save"))) { @@ -1501,40 +1564,38 @@ uint16_t WebGetGpioArg(uint32_t i) { return gpio; } -void TemplateSaveSettings(void) -{ - char tmp[TOPSZ]; // WebGetArg NAME and GPIO/BASE/FLAG byte value - char svalue[300]; // Template command string +void TemplateSaveSettings(void) { + char tmp[TOPSZ]; // WebGetArg NAME and GPIO/BASE/FLAG byte value + char command[300]; // Template command string - WebGetArg(PSTR("s1"), tmp, sizeof(tmp)); // NAME - snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_TEMPLATE " {\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), tmp); + WebGetArg(PSTR("s1"), tmp, sizeof(tmp)); // NAME + snprintf_P(command, sizeof(command), PSTR(D_CMND_TEMPLATE " {\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), tmp); uint32_t j = 0; for (uint32_t i = 0; i < nitems(Settings.user_template.gp.io); i++) { if (6 == i) { j = 9; } if (8 == i) { j = 12; } - snprintf_P(svalue, sizeof(svalue), PSTR("%s%s%d"), svalue, (i>0)?",":"", WebGetGpioArg(j)); + snprintf_P(command, sizeof(command), PSTR("%s%s%d"), command, (i>0)?",":"", WebGetGpioArg(j)); j++; } uint32_t flag = 0; - char webindex[5]; // WebGetArg name + char webindex[5]; // WebGetArg name for (uint32_t i = 0; i < GPIO_FLAG_USED; i++) { snprintf_P(webindex, sizeof(webindex), PSTR("c%d"), i); - uint32_t state = Webserver->hasArg(webindex) << i; // FLAG + uint32_t state = Webserver->hasArg(webindex) << i; // FLAG flag += state; } - WebGetArg(PSTR("g99"), tmp, sizeof(tmp)); // BASE + WebGetArg(PSTR("g99"), tmp, sizeof(tmp)); // BASE uint32_t base = atoi(tmp) +1; - snprintf_P(svalue, sizeof(svalue), PSTR("%s],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"), svalue, flag, base); - ExecuteWebCommand(svalue, SRC_WEBGUI); + snprintf_P(command, sizeof(command), PSTR("%s],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"), command, flag, base); + ExecuteWebCommand(command); } /*-------------------------------------------------------------------------------------------*/ -void HandleModuleConfiguration(void) -{ +void HandleModuleConfiguration(void) { if (!HttpCheckPriviledgedAccess()) { return; } if (Webserver->hasArg(F("save"))) { @@ -1600,30 +1661,27 @@ void HandleModuleConfiguration(void) WSContentStop(); } -void ModuleSaveSettings(void) -{ +void ModuleSaveSettings(void) { char tmp[8]; // WebGetArg numbers only - - WebGetArg(PSTR("g99"), tmp, sizeof(tmp)); + WebGetArg(PSTR("g99"), tmp, sizeof(tmp)); // Module uint32_t new_module = (!strlen(tmp)) ? MODULE : atoi(tmp); Settings.last_module = Settings.module; Settings.module = new_module; SetModuleType(); myio template_gp; TemplateGpios(&template_gp); - String gpios = ""; for (uint32_t i = 0; i < nitems(template_gp.io); i++) { if (Settings.last_module != new_module) { Settings.my_gp.io[i] = GPIO_NONE; } else { if (ValidGPIO(i, template_gp.io[i])) { - Settings.my_gp.io[i] = WebGetGpioArg(i); - gpios += F(", IO"); gpios += String(i); gpios += F(" "); gpios += String(Settings.my_gp.io[i]); + Settings.my_gp.io[i] = WebGetGpioArg(i); // Gpio } } } - - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), ModuleName().c_str(), gpios.c_str()); + char command[32]; + snprintf_P(command, sizeof(command), PSTR(D_CMND_BACKLOG "0 " D_CMND_MODULE ";" D_CMND_GPIO)); + ExecuteWebCommand(command); } /*-------------------------------------------------------------------------------------------*/ @@ -1647,31 +1705,80 @@ String HtmlEscape(const String unescaped) { return result; } -// Indexed by enum wl_enc_type in file wl_definitions.h starting from -1 -const char kEncryptionType[] PROGMEM = "|||" D_WPA_PSK "||" D_WPA2_PSK "|" D_WEP "||" D_NONE "|" D_AUTO; +void HandleWifiConfiguration(void) { + char tmp[TOPSZ]; // Max length is currently 150 -void HandleWifiConfiguration(void) -{ if (!HttpCheckPriviledgedAccess(!WifiIsInManagerMode())) { return; } AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_CONFIGURE_WIFI)); if (Webserver->hasArg(F("save")) && HTTP_MANAGER_RESET_ONLY != Web.state) { - WifiSaveSettings(); - WebRestart(2); + if ( WifiIsInManagerMode() ) { + // Test WIFI Connection to Router + // As Tasmota is in this case in AP mode, a STA connection can be established too at the same time + Web.wifi_test_counter = 9; // seconds to test user's proposed AP + Web.wifiTest = WIFI_TESTING; + + Web.save_data_counter = TasmotaGlobal.save_data_counter; + TasmotaGlobal.save_data_counter = 0; // Stop auto saving data - Updating Settings + Settings.save_data = 0; + + Web.old_wificonfig = TasmotaGlobal.wifi_state_flag; + Settings.sta_config = WIFI_MANAGER; + TasmotaGlobal.wifi_state_flag = Settings.sta_config; + + TasmotaGlobal.sleep = 0; // Disable sleep + TasmotaGlobal.restart_flag = 0; // No restart + TasmotaGlobal.ota_state_flag = 0; // No OTA +// TasmotaGlobal.blinks = 0; // Disable blinks initiated by WifiManager + + WebGetArg(PSTR("s1"), tmp, sizeof(tmp)); // SSID1 + SettingsUpdateText(SET_STASSID1, tmp); + WebGetArg(PSTR("p1"), tmp, sizeof(tmp)); // PASSWORD1 + SettingsUpdateText(SET_STAPWD1, tmp); + + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_CONNECTING_TO_AP " %s " D_AS " %s ..."), + SettingsText(SET_STASSID1), TasmotaGlobal.hostname); + + WiFi.begin(SettingsText(SET_STASSID1), SettingsText(SET_STAPWD1)); + + WebRestart(2); + } else { + // STATION MODE or MIXED + // Save the config and restart + WifiSaveSettings(); + WebRestart(1); + } return; } + if ( WIFI_TEST_FINISHED_SUCCESSFUL == Web.wifiTest ) { + Web.wifiTest = WIFI_NOT_TESTING; +#if (RESTART_AFTER_INITIAL_WIFI_CONFIG) + WebRestart(3); +#else + HandleRoot(); +#endif + } + WSContentStart_P(PSTR(D_CONFIGURE_WIFI), !WifiIsInManagerMode()); WSContentSend_P(HTTP_SCRIPT_WIFI); + if (WifiIsInManagerMode()) { WSContentSend_P(HTTP_SCRIPT_HIDE); } + if (WIFI_TESTING == Web.wifiTest) { WSContentSend_P(HTTP_SCRIPT_RELOAD_TIME, HTTP_RESTART_RECONNECT_TIME); } #ifdef USE_ENHANCED_GUI_WIFI_SCAN WSContentSendStyle_P(HTTP_HEAD_STYLE_SSI, WebColor(COL_TEXT)); #else WSContentSendStyle(); #endif // USE_ENHANCED_GUI_WIFI_SCAN + bool limitScannedNetworks = true; if (HTTP_MANAGER_RESET_ONLY != Web.state) { - if (Webserver->hasArg(F("scan"))) { + if (WIFI_TESTING == Web.wifiTest) { + limitScannedNetworks = false; + } else { + if (Webserver->hasArg(F("scan"))) { limitScannedNetworks = false; } + + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI "Scanning...")); #ifdef USE_EMULATION UdpDisconnect(); #endif // USE_EMULATION @@ -1681,7 +1788,7 @@ void HandleWifiConfiguration(void) if (0 == n) { AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_NO_NETWORKS_FOUND)); WSContentSend_P(PSTR(D_NO_NETWORKS_FOUND)); - WSContentSend_P(PSTR(". " D_REFRESH_TO_SCAN_AGAIN ".")); + limitScannedNetworks = false; // in order to show D_SCAN_FOR_WIFI_NETWORKS } else { //sort networks int indices[n]; @@ -1689,7 +1796,6 @@ void HandleWifiConfiguration(void) indices[i] = i; } - // RSSI SORT for (uint32_t i = 0; i < n; i++) { for (uint32_t j = i + 1; j < n; j++) { @@ -1699,44 +1805,65 @@ void HandleWifiConfiguration(void) } } + uint32_t networksToShow = n; + if ((limitScannedNetworks) && (networksToShow > MAX_WIFI_NETWORKS_TO_SHOW)) { networksToShow = MAX_WIFI_NETWORKS_TO_SHOW; } + + if (WifiIsInManagerMode()) { WSContentSend_P(PSTR("
" D_SELECT_YOUR_WIFI_NETWORK "

"), WebColor(COL_TEXT)); } + #ifdef USE_ENHANCED_GUI_WIFI_SCAN //display networks in page - for (uint32_t i = 0; i < n; i++) { + bool skipduplicated; + int ssid_showed = 0; + for (uint32_t i = 0; i < networksToShow; i++) { if (indices[i] < n) { int32_t rssi = WiFi.RSSI(indices[i]); String ssid = WiFi.SSID(indices[i]); DEBUG_CORE_LOG(PSTR(D_LOG_WIFI D_SSID " %s, " D_BSSID " %s, " D_CHANNEL " %d, " D_RSSI " %d"), ssid.c_str(), WiFi.BSSIDstr(indices[i]).c_str(), WiFi.channel(indices[i]), rssi); + String ssid_copy = ssid; + if (!ssid_copy.length()) { ssid_copy = F("no_name"); } // Print SSID - WSContentSend_P(PSTR("
%s
"), HtmlEscape(ssid).c_str()); - + if (!limitScannedNetworks) { + WSContentSend_P(PSTR("
%s
"), HtmlEscape(ssid_copy).c_str()); + } + skipduplicated = false; String nextSSID = ""; // Handle all APs with the same SSID for (uint32_t j = 0; j < n; j++) { if ((indices[j] < n) && ((nextSSID = WiFi.SSID(indices[j])) == ssid)) { - // Update RSSI / quality - rssi = WiFi.RSSI(indices[j]); - uint32_t rssi_as_quality = WifiGetRssiAsQuality(rssi); - uint32_t num_bars = changeUIntScale(rssi_as_quality, 0, 100, 0, 4); + if (!skipduplicated) { + // Update RSSI / quality + rssi = WiFi.RSSI(indices[j]); + uint32_t rssi_as_quality = WifiGetRssiAsQuality(rssi); + uint32_t num_bars = changeUIntScale(rssi_as_quality, 0, 100, 0, 4); - // Print item - WSContentSend_P(PSTR("
%s(%d)
"), - rssi, rssi_as_quality, - WiFi.BSSIDstr(indices[j]).c_str(), - WiFi.channel(indices[j]) - ); - // Print signal strength indicator - for (uint32_t k = 0; k < 4; ++k) { - WSContentSend_P(PSTR(""), k, (num_bars < k) ? PSTR(" o30") : PSTR("")); + WSContentSend_P(PSTR("
"), rssi, rssi_as_quality); + if (limitScannedNetworks) { + // Print SSID and item + WSContentSend_P(PSTR("%s
"), HtmlEscape(ssid_copy).c_str()); + ssid_showed++; + skipduplicated = true; // For the simplified page, just show 1 SSID if there are many Networks with the same + } else { + // Print item + WSContentSend_P(PSTR("%s(%d)
"), WiFi.BSSIDstr(indices[j]).c_str(), WiFi.channel(indices[j]) + ); + } + // Print signal strength indicator + for (uint32_t k = 0; k < 4; ++k) { + WSContentSend_P(PSTR(""), k, (num_bars < k) ? PSTR(" o30") : PSTR("")); + } + WSContentSend_P(PSTR("
")); + } else { + if (ssid_showed <= networksToShow ) { networksToShow++; } } - WSContentSend_P(PSTR("
")); - indices[j] = n; } delay(0); } - WSContentSend_P(PSTR("
")); + if (!limitScannedNetworks) { + WSContentSend_P(PSTR("
")); + } } } #else // No USE_ENHANCED_GUI_WIFI_SCAN @@ -1754,24 +1881,16 @@ void HandleWifiConfiguration(void) } //display networks in page - for (uint32_t i = 0; i < n; i++) { + for (uint32_t i = 0; i < networksToShow; i++) { if (-1 == indices[i]) { continue; } // skip dups int32_t rssi = WiFi.RSSI(indices[i]); DEBUG_CORE_LOG(PSTR(D_LOG_WIFI D_SSID " %s, " D_BSSID " %s, " D_CHANNEL " %d, " D_RSSI " %d"), WiFi.SSID(indices[i]).c_str(), WiFi.BSSIDstr(indices[i]).c_str(), WiFi.channel(indices[i]), rssi); int quality = WifiGetRssiAsQuality(rssi); -/* - int auth = WiFi.encryptionType(indices[i]); - char encryption[20]; - WSContentSend_P(PSTR("
%s (%d) %s %d%% (%d dBm)
"), - HtmlEscape(WiFi.SSID(indices[i])).c_str(), - WiFi.channel(indices[i]), - GetTextIndexed(encryption, sizeof(encryption), auth +1, kEncryptionType), - quality, rssi - ); -*/ + String ssid_copy = WiFi.SSID(indices[i]); + if (!ssid_copy.length()) { ssid_copy = F("no_name"); } WSContentSend_P(PSTR("
%s (%d) %d%% (%d dBm)
"), - HtmlEscape(WiFi.SSID(indices[i])).c_str(), + HtmlEscape(ssid_copy).c_str(), WiFi.channel(indices[i]), quality, rssi ); @@ -1782,54 +1901,69 @@ void HandleWifiConfiguration(void) WSContentSend_P(PSTR("
")); } - } else { - WSContentSend_P(PSTR("
")); } - // As WIFI_HOSTNAME may contain %s-%04d it cannot be part of HTTP_FORM_WIFI where it will exception - WSContentSend_P(HTTP_FORM_WIFI, SettingsText(SET_STASSID1), SettingsText(SET_STASSID2), WIFI_HOSTNAME, WIFI_HOSTNAME, SettingsText(SET_HOSTNAME), SettingsText(SET_CORS)); + WSContentSend_P(PSTR("
"), (limitScannedNetworks) ? PSTR(D_SHOW_MORE_WIFI_NETWORKS) : PSTR(D_SCAN_FOR_WIFI_NETWORKS)); + WSContentSend_P(HTTP_FORM_WIFI_PART1, (WifiIsInManagerMode()) ? "" : PSTR(" (" STA_SSID1 ")"), SettingsText(SET_STASSID1)); + if (WifiIsInManagerMode()) { + // As WIFI_HOSTNAME may contain %s-%04d it cannot be part of HTTP_FORM_WIFI where it will exception + WSContentSend_P(PSTR(">

")); + } else { + WSContentSend_P(HTTP_FORM_WIFI_PART2, SettingsText(SET_STASSID2), WIFI_HOSTNAME, WIFI_HOSTNAME, SettingsText(SET_HOSTNAME), SettingsText(SET_CORS)); + } + WSContentSend_P(HTTP_FORM_END); } if (WifiIsInManagerMode()) { #ifndef FIRMWARE_MINIMAL - WSContentSpaceButton(BUTTON_RESTORE); - WSContentButton(BUTTON_RESET_CONFIGURATION); + WSContentSend_P(PSTR("

"), WebColor(COL_TEXT_WARNING)); + if (WIFI_TESTING == Web.wifiTest) { + WSContentSend_P(PSTR(D_TRYING_TO_CONNECT "
%s

"), SettingsText(SET_STASSID1)); + } else if (WIFI_TEST_FINISHED_BAD == Web.wifiTest) { + WSContentSend_P(PSTR(D_CONNECT_FAILED_TO " %s
" D_CHECK_CREDENTIALS "
"), SettingsText(SET_STASSID1)); + } + // More Options Button + WSContentSend_P(PSTR("

"), + (WIFI_TEST_FINISHED_BAD == Web.wifiTest) ? "none" : Web.initial_config ? "block" : "none", Web.initial_config ? "block" : "none" + ); + WSContentSpaceButton(BUTTON_RESTORE, !Web.initial_config); + WSContentButton(BUTTON_RESET_CONFIGURATION, !Web.initial_config); #endif // FIRMWARE_MINIMAL - WSContentSpaceButton(BUTTON_RESTART); + WSContentSpaceButton(BUTTON_RESTART, !Web.initial_config); } else { WSContentSpaceButton(BUTTON_CONFIGURATION); } WSContentStop(); } -void WifiSaveSettings(void) -{ - char tmp[TOPSZ]; // Max length is currently 150 - - WebGetArg(PSTR("h"), tmp, sizeof(tmp)); - SettingsUpdateText(SET_HOSTNAME, (!strlen(tmp)) ? WIFI_HOSTNAME : tmp); - if (strchr(SettingsText(SET_HOSTNAME), '%') != nullptr) { - SettingsUpdateText(SET_HOSTNAME, WIFI_HOSTNAME); - } - WebGetArg(PSTR("c"), tmp, sizeof(tmp)); - SettingsUpdateText(SET_CORS, (!strlen(tmp)) ? CORS_DOMAIN : tmp); - WebGetArg(PSTR("s1"), tmp, sizeof(tmp)); - SettingsUpdateText(SET_STASSID1, (!strlen(tmp)) ? STA_SSID1 : tmp); - WebGetArg(PSTR("s2"), tmp, sizeof(tmp)); - SettingsUpdateText(SET_STASSID2, (!strlen(tmp)) ? STA_SSID2 : tmp); - WebGetArg(PSTR("p1"), tmp, sizeof(tmp)); - SettingsUpdateText(SET_STAPWD1, (!strlen(tmp)) ? "" : (strlen(tmp) < 5) ? SettingsText(SET_STAPWD1) : tmp); - WebGetArg(PSTR("p2"), tmp, sizeof(tmp)); - SettingsUpdateText(SET_STAPWD2, (!strlen(tmp)) ? "" : (strlen(tmp) < 5) ? SettingsText(SET_STAPWD2) : tmp); - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID "1 %s, " D_CMND_SSID "2 %s, " D_CMND_CORS " %s"), - SettingsText(SET_HOSTNAME), SettingsText(SET_STASSID1), SettingsText(SET_STASSID2), SettingsText(SET_CORS)); +void WifiSaveSettings(void) { + char tmp1[TOPSZ]; + WebGetArg(PSTR("h"), tmp1, sizeof(tmp1)); // Host name + char tmp2[TOPSZ]; + WebGetArg(PSTR("c"), tmp2, sizeof(tmp2)); // Cors domain + char tmp3[TOPSZ]; + WebGetArg(PSTR("s1"), tmp3, sizeof(tmp3)); // Ssid1 + char tmp4[TOPSZ]; + WebGetArg(PSTR("s2"), tmp4, sizeof(tmp4)); // Ssid2 + char tmp5[TOPSZ]; + WebGetArg(PSTR("p1"), tmp5, sizeof(tmp5)); // Password1 + char tmp6[TOPSZ]; + WebGetArg(PSTR("p2"), tmp6, sizeof(tmp6)); // Password2 + char command[300]; + snprintf_P(command, sizeof(command), PSTR(D_CMND_BACKLOG "0 " D_CMND_HOSTNAME " %s;" D_CMND_CORS " %s;" D_CMND_SSID "1 %s;" D_CMND_SSID "2 %s;" D_CMND_PASSWORD "3 %s;" D_CMND_PASSWORD "4 %s"), + (!strlen(tmp1)) ? "1" : tmp1, + (!strlen(tmp2)) ? "1" : tmp2, + (!strlen(tmp3)) ? "1" : tmp3, + (!strlen(tmp4)) ? "1" : tmp4, + (!strlen(tmp5)) ? "\"" : (strlen(tmp5) < 5) ? "" : tmp5, + (!strlen(tmp6)) ? "\"" : (strlen(tmp6) < 5) ? "" : tmp6); + ExecuteWebCommand(command); } /*-------------------------------------------------------------------------------------------*/ -void HandleLoggingConfiguration(void) -{ +void HandleLoggingConfiguration(void) { if (!HttpCheckPriviledgedAccess()) { return; } AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_CONFIGURE_LOGGING)); @@ -1866,35 +2000,36 @@ void HandleLoggingConfiguration(void) WSContentStop(); } -void LoggingSaveSettings(void) -{ - char tmp[TOPSZ]; // Max length is currently 33 - - WebGetArg(PSTR("l0"), tmp, sizeof(tmp)); - SetSeriallog((!strlen(tmp)) ? SERIAL_LOG_LEVEL : atoi(tmp)); - WebGetArg(PSTR("l1"), tmp, sizeof(tmp)); - Settings.weblog_level = (!strlen(tmp)) ? WEB_LOG_LEVEL : atoi(tmp); - WebGetArg(PSTR("l2"), tmp, sizeof(tmp)); - Settings.mqttlog_level = (!strlen(tmp)) ? MQTT_LOG_LEVEL : atoi(tmp); - WebGetArg(PSTR("l3"), tmp, sizeof(tmp)); - SetSyslog((!strlen(tmp)) ? SYS_LOG_LEVEL : atoi(tmp)); - WebGetArg(PSTR("lh"), tmp, sizeof(tmp)); - SettingsUpdateText(SET_SYSLOG_HOST, (!strlen(tmp)) ? SYS_LOG_HOST : tmp); - WebGetArg(PSTR("lp"), tmp, sizeof(tmp)); - Settings.syslog_port = (!strlen(tmp)) ? SYS_LOG_PORT : atoi(tmp); - WebGetArg(PSTR("lt"), tmp, sizeof(tmp)); - Settings.tele_period = (!strlen(tmp)) ? TELE_PERIOD : atoi(tmp); - if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) { - Settings.tele_period = 10; // Do not allow periods < 10 seconds - } - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_MQTTLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"), - Settings.seriallog_level, Settings.weblog_level, Settings.mqttlog_level, Settings.syslog_level, SettingsText(SET_SYSLOG_HOST), Settings.syslog_port, Settings.tele_period); +void LoggingSaveSettings(void) { + char tmp1[CMDSZ]; + WebGetArg(PSTR("l0"), tmp1, sizeof(tmp1)); // Serial log level + char tmp2[CMDSZ]; + WebGetArg(PSTR("l1"), tmp2, sizeof(tmp2)); // Web log level + char tmp3[CMDSZ]; + WebGetArg(PSTR("l2"), tmp3, sizeof(tmp3)); // Mqtt log level + char tmp4[CMDSZ]; + WebGetArg(PSTR("l3"), tmp4, sizeof(tmp4)); // Syslog level + char tmp5[TOPSZ]; + WebGetArg(PSTR("lh"), tmp5, sizeof(tmp5)); // Syslog host name + char tmp6[CMDSZ]; + WebGetArg(PSTR("lp"), tmp6, sizeof(tmp6)); // Syslog port number + char tmp7[CMDSZ]; + WebGetArg(PSTR("lt"), tmp7, sizeof(tmp7)); // Teleperiod + char command[200]; + snprintf_P(command, sizeof(command), PSTR(D_CMND_BACKLOG "0 " D_CMND_SERIALLOG " %s;" D_CMND_WEBLOG " %s;" D_CMND_MQTTLOG " %s;" D_CMND_SYSLOG " %s;" D_CMND_LOGHOST " %s;" D_CMND_LOGPORT " %s;" D_CMND_TELEPERIOD " %s"), + (!strlen(tmp1)) ? STR(SERIAL_LOG_LEVEL) : tmp1, + (!strlen(tmp2)) ? STR(WEB_LOG_LEVEL) : tmp2, + (!strlen(tmp3)) ? STR(MQTT_LOG_LEVEL) : tmp3, + (!strlen(tmp4)) ? STR(SYS_LOG_LEVEL) : tmp4, + (!strlen(tmp5)) ? SYS_LOG_HOST : tmp5, + (!strlen(tmp6)) ? STR(SYS_LOG_PORT) : tmp6, + (!strlen(tmp7)) ? STR(TELE_PERIOD) : tmp7); + ExecuteWebCommand(command); } /*-------------------------------------------------------------------------------------------*/ -void HandleOtherConfiguration(void) -{ +void HandleOtherConfiguration(void) { if (!HttpCheckPriviledgedAccess()) { return; } AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_CONFIGURE_OTHER)); @@ -1956,42 +2091,36 @@ void HandleOtherConfiguration(void) WSContentStop(); } -void OtherSaveSettings(void) -{ - char tmp[300]; // Needs to hold complete ESP32 template of minimal 230 chars - char webindex[5]; - char friendlyname[TOPSZ]; - char message[MAX_LOGSZ]; +void OtherSaveSettings(void) { + char tmp1[300]; // Needs to hold complete ESP32 template of minimal 230 chars + WebGetArg(PSTR("dn"), tmp1, sizeof(tmp1)); // Device name + char tmp2[TOPSZ]; + WebGetArg(PSTR("wp"), tmp2, sizeof(tmp2)); // Web password + char command[500]; + snprintf_P(command, sizeof(command), PSTR(D_CMND_BACKLOG "0 " D_CMND_WEBPASSWORD "2 %s;" D_CMND_SO "3 %d;" D_CMND_DEVICENAME " %s"), + (!strlen(tmp2)) ? "\"" : (strlen(tmp2) < 5) ? "" : tmp2, + Webserver->hasArg(F("b1")), // SetOption3 - Enable MQTT + (!strlen(tmp1)) ? "\"" : tmp1); + + char webindex[5]; + for (uint32_t i = 0; i < MAX_FRIENDLYNAMES; i++) { + snprintf_P(webindex, sizeof(webindex), PSTR("a%d"), i); + WebGetArg(webindex, tmp1, sizeof(tmp1)); // Friendly name 1 to 8 + snprintf_P(command, sizeof(command), PSTR("%s;" D_CMND_FN"%d %s"), command, i +1, (!strlen(tmp1)) ? "\"" : tmp1); + } - WebGetArg(PSTR("dn"), tmp, sizeof(tmp)); - SettingsUpdateText(SET_DEVICENAME, (!strlen(tmp)) ? "" : (!strcmp(tmp,"1")) ? SettingsText(SET_FRIENDLYNAME1) : tmp); - WebGetArg(PSTR("wp"), tmp, sizeof(tmp)); - SettingsUpdateText(SET_WEBPWD, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? SettingsText(SET_WEBPWD) : tmp); - Settings.flag.mqtt_enabled = Webserver->hasArg(F("b1")); // SetOption3 - Enable MQTT #ifdef USE_EMULATION - UdpDisconnect(); #if defined(USE_EMULATION_WEMO) || defined(USE_EMULATION_HUE) - WebGetArg(PSTR("b2"), tmp, sizeof(tmp)); - Settings.flag2.emulation = (!strlen(tmp)) ? 0 : atoi(tmp); + WebGetArg(PSTR("b2"), tmp1, sizeof(tmp1)); // Emulation + snprintf_P(command, sizeof(command), PSTR("%s;" D_CMND_EMULATION " %s"), command, (!strlen(tmp1)) ? "0" : tmp1); #endif // USE_EMULATION_WEMO || USE_EMULATION_HUE #endif // USE_EMULATION - snprintf_P(message, sizeof(message), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_DEVICENAME " %s, " D_CMND_FRIENDLYNAME), - GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation, SettingsText(SET_DEVICENAME)); - for (uint32_t i = 0; i < MAX_FRIENDLYNAMES; i++) { - snprintf_P(webindex, sizeof(webindex), PSTR("a%d"), i); - WebGetArg(webindex, tmp, sizeof(tmp)); - snprintf_P(friendlyname, sizeof(friendlyname), PSTR(FRIENDLY_NAME"%d"), i +1); - SettingsUpdateText(SET_FRIENDLYNAME1 +i, (!strlen(tmp)) ? (i) ? friendlyname : PSTR(FRIENDLY_NAME) : tmp); - snprintf_P(message, sizeof(message), PSTR("%s%s %s"), message, (i) ? "," : "", SettingsText(SET_FRIENDLYNAME1 +i)); - } - AddLogData(LOG_LEVEL_INFO, message); - - WebGetArg(PSTR("t1"), tmp, sizeof(tmp)); - if (strlen(tmp)) { // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255} - snprintf_P(message, sizeof(message), PSTR(D_CMND_BACKLOG " " D_CMND_TEMPLATE " %s%s"), tmp, (Webserver->hasArg(F("t2"))) ? PSTR("; " D_CMND_MODULE " 0") : ""); - ExecuteWebCommand(message, SRC_WEBGUI); + WebGetArg(PSTR("t1"), tmp1, sizeof(tmp1)); // Template + if (strlen(tmp1)) { // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255} + snprintf_P(command, sizeof(command), PSTR("%s;" D_CMND_TEMPLATE " %s%s"), command, tmp1, (Webserver->hasArg(F("t2"))) ? PSTR("; " D_CMND_MODULE " 0") : ""); } + ExecuteWebCommand(command); } /*-------------------------------------------------------------------------------------------*/ @@ -2053,7 +2182,7 @@ void HandleResetConfiguration(void) char command[CMDSZ]; snprintf_P(command, sizeof(command), PSTR(D_CMND_RESET " 1")); - ExecuteWebCommand(command, SRC_WEBGUI); + ExecuteWebCommand(command); } void HandleRestoreConfiguration(void) @@ -2298,7 +2427,7 @@ void HandleUpgradeFirmwareStart(void) { WebGetArg(PSTR("o"), otaurl, sizeof(otaurl)); if (strlen(otaurl)) { snprintf_P(command, sizeof(command), PSTR(D_CMND_OTAURL " %s"), otaurl); - ExecuteWebCommand(command, SRC_WEBGUI); + ExecuteWebCommand(command); } WSContentStart_P(PSTR(D_INFORMATION)); @@ -2310,7 +2439,7 @@ void HandleUpgradeFirmwareStart(void) { WSContentStop(); snprintf_P(command, sizeof(command), PSTR(D_CMND_UPGRADE " 1")); - ExecuteWebCommand(command, SRC_WEBGUI); + ExecuteWebCommand(command); } void HandleUploadDone(void) { @@ -3012,10 +3141,16 @@ void CmndWebServer(void) void CmndWebPassword(void) { + bool show_asterisk = (2 == XdrvMailbox.index); if (XdrvMailbox.data_len > 0) { SettingsUpdateText(SET_WEBPWD, (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? WEB_PASSWORD : XdrvMailbox.data); - ResponseCmndChar(SettingsText(SET_WEBPWD)); + if (!show_asterisk) { + ResponseCmndChar(SettingsText(SET_WEBPWD)); + } } else { + show_asterisk = true; + } + if (show_asterisk) { Response_P(S_JSON_COMMAND_ASTERISK, XdrvMailbox.command); } } @@ -3099,7 +3234,7 @@ void CmndWebButton(void) void CmndCors(void) { if (XdrvMailbox.data_len > 0) { - SettingsUpdateText(SET_CORS, (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? WEB_PASSWORD : XdrvMailbox.data); + SettingsUpdateText(SET_CORS, (SC_CLEAR == Shortcut()) ? "" : (SC_DEFAULT == Shortcut()) ? CORS_DOMAIN : XdrvMailbox.data); } ResponseCmndChar(SettingsText(SET_CORS)); } @@ -3119,6 +3254,47 @@ bool Xdrv01(uint8_t function) if (Settings.flag2.emulation) { PollUdp(); } #endif // USE_EMULATION break; + case FUNC_EVERY_SECOND: + if (Web.initial_config) { + Wifi.config_counter = 200; // Do not restart the device if it has SSId Blank + } + if (Web.wifi_test_counter) { + Web.wifi_test_counter--; + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_TRYING_TO_CONNECT " %s"), SettingsText(SET_STASSID1)); + if ( WifiCheck_hasIP(WiFi.localIP()) ) { // Got IP - Connection Established + Web.wifi_test_counter = 0; + Web.wifiTest = WIFI_TEST_FINISHED_SUCCESSFUL; + AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_CMND_SSID "1 %s: " D_CONNECTED " - " D_IP_ADDRESS " %_I"), SettingsText(SET_STASSID1), (uint32_t)WiFi.localIP()); +// TasmotaGlobal.blinks = 255; // Signal wifi connection with blinks + Settings.sta_config = Web.old_wificonfig; + TasmotaGlobal.wifi_state_flag = Settings.sta_config; + TasmotaGlobal.save_data_counter = Web.save_data_counter; + Settings.save_data = Web.save_data_counter; + SettingsSaveAll(); +#if (!RESTART_AFTER_INITIAL_WIFI_CONFIG) + Web.initial_config = false; + Web.state = HTTP_ADMIN; +#endif + } else if (!Web.wifi_test_counter) { // Test TimeOut + Web.wifi_test_counter = 0; + Web.wifiTest = WIFI_TEST_FINISHED_BAD; + switch (WiFi.status()) { + case WL_CONNECTED: + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_CONNECT_FAILED_NO_IP_ADDRESS)); + break; + case WL_NO_SSID_AVAIL: + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_CONNECT_FAILED_AP_NOT_REACHED)); + break; + case WL_CONNECT_FAILED: + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_CONNECT_FAILED_WRONG_PASSWORD)); + break; + default: // WL_IDLE_STATUS and WL_DISCONNECTED + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_CONNECT_FAILED_AP_TIMEOUT)); + } + int n = WiFi.scanNetworks(); // restart scan + } + } + break; case FUNC_COMMAND: result = DecodeCommand(kWebCommands, WebCommand); break; diff --git a/tasmota/xdrv_02_mqtt.ino b/tasmota/xdrv_02_mqtt.ino index 3a630e699..6f689bc70 100644 --- a/tasmota/xdrv_02_mqtt.ino +++ b/tasmota/xdrv_02_mqtt.ino @@ -551,28 +551,28 @@ void MqttConnected(void) { if (Mqtt.initial_connection_state) { if (ResetReason() != REASON_DEEP_SLEEP_AWAKE) { char stopic2[TOPSZ]; - Response_P(PSTR("{\"" D_CMND_MODULE "\":\"%s\",\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_FALLBACKTOPIC "\":\"%s\",\"" D_CMND_GROUPTOPIC "\":\"%s\"}"), + Response_P(PSTR("{\"Info1\":{\"" D_CMND_MODULE "\":\"%s\",\"" D_JSON_VERSION "\":\"%s%s\",\"" D_JSON_FALLBACKTOPIC "\":\"%s\",\"" D_CMND_GROUPTOPIC "\":\"%s\"}}"), ModuleName().c_str(), TasmotaGlobal.version, TasmotaGlobal.image_name, GetFallbackTopic_P(stopic, ""), GetGroupTopic_P(stopic2, "", SET_MQTT_GRP_TOPIC)); MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_INFO "1"), Settings.flag5.mqtt_info_retain); #ifdef USE_WEBSERVER if (Settings.webserver) { #if LWIP_IPV6 - Response_P(PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"IPv6Address\":\"%s\"}"), + Response_P(PSTR("{\"Info2\":{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"IPv6Address\":\"%s\"}}"), (2 == Settings.webserver) ? PSTR(D_ADMIN) : PSTR(D_USER), NetworkHostname(), NetworkAddress().toString().c_str(), WifiGetIPv6().c_str(), Settings.flag5.mqtt_info_retain); #else - Response_P(PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\"}"), + Response_P(PSTR("{\"Info2\":{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\"}}"), (2 == Settings.webserver) ? PSTR(D_ADMIN) : PSTR(D_USER), NetworkHostname(), NetworkAddress().toString().c_str(), Settings.flag5.mqtt_info_retain); #endif // LWIP_IPV6 = 1 MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_INFO "2"), Settings.flag5.mqtt_info_retain); } #endif // USE_WEBSERVER - Response_P(PSTR("{\"" D_JSON_RESTARTREASON "\":")); + Response_P(PSTR("{\"Info3\":{\"" D_JSON_RESTARTREASON "\":")); if (CrashFlag()) { CrashDump(); } else { ResponseAppend_P(PSTR("\"%s\""), GetResetReason().c_str()); } - ResponseJsonEnd(); + ResponseJsonEndEnd(); MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_INFO "3"), Settings.flag5.mqtt_info_retain); } diff --git a/tasmota/xdrv_03_energy.ino b/tasmota/xdrv_03_energy.ino index c88995590..b9697dfca 100644 --- a/tasmota/xdrv_03_energy.ino +++ b/tasmota/xdrv_03_energy.ino @@ -43,11 +43,11 @@ enum EnergyCommands { CMND_POWERCAL, CMND_VOLTAGECAL, CMND_CURRENTCAL, CMND_FREQUENCYCAL, - CMND_POWERSET, CMND_VOLTAGESET, CMND_CURRENTSET, CMND_FREQUENCYSET, CMND_MODULEADDRESS }; + CMND_POWERSET, CMND_VOLTAGESET, CMND_CURRENTSET, CMND_FREQUENCYSET, CMND_MODULEADDRESS, CMND_ENERGYCONFIG }; const char kEnergyCommands[] PROGMEM = "|" // No prefix D_CMND_POWERCAL "|" D_CMND_VOLTAGECAL "|" D_CMND_CURRENTCAL "|" D_CMND_FREQUENCYCAL "|" - D_CMND_POWERSET "|" D_CMND_VOLTAGESET "|" D_CMND_CURRENTSET "|" D_CMND_FREQUENCYSET "|" D_CMND_MODULEADDRESS "|" + D_CMND_POWERSET "|" D_CMND_VOLTAGESET "|" D_CMND_CURRENTSET "|" D_CMND_FREQUENCYSET "|" D_CMND_MODULEADDRESS "|" D_CMND_ENERGYCONFIG "|" #ifdef USE_ENERGY_MARGIN_DETECTION D_CMND_POWERDELTA "|" D_CMND_POWERLOW "|" D_CMND_POWERHIGH "|" D_CMND_VOLTAGELOW "|" D_CMND_VOLTAGEHIGH "|" D_CMND_CURRENTLOW "|" D_CMND_CURRENTHIGH "|" #ifdef USE_ENERGY_POWER_LIMIT @@ -56,11 +56,11 @@ const char kEnergyCommands[] PROGMEM = "|" // No prefix D_CMND_SAFEPOWER "|" D_CMND_SAFEPOWERHOLD "|" D_CMND_SAFEPOWERWINDOW "|" #endif // USE_ENERGY_POWER_LIMIT #endif // USE_ENERGY_MARGIN_DETECTION - D_CMND_ENERGYRESET "|" D_CMND_TARIFF ; + D_CMND_ENERGYRESET "|" D_CMND_TARIFF; void (* const EnergyCommand[])(void) PROGMEM = { &CmndPowerCal, &CmndVoltageCal, &CmndCurrentCal, &CmndFrequencyCal, - &CmndPowerSet, &CmndVoltageSet, &CmndCurrentSet, &CmndFrequencySet, &CmndModuleAddress, + &CmndPowerSet, &CmndVoltageSet, &CmndCurrentSet, &CmndFrequencySet, &CmndModuleAddress, &CmndEnergyConfig, #ifdef USE_ENERGY_MARGIN_DETECTION &CmndPowerDelta, &CmndPowerLow, &CmndPowerHigh, &CmndVoltageLow, &CmndVoltageHigh, &CmndCurrentLow, &CmndCurrentHigh, #ifdef USE_ENERGY_POWER_LIMIT @@ -69,7 +69,7 @@ void (* const EnergyCommand[])(void) PROGMEM = { &CmndSafePower, &CmndSafePowerHold, &CmndSafePowerWindow, #endif // USE_ENERGY_POWER_LIMIT #endif // USE_ENERGY_MARGIN_DETECTION - &CmndEnergyReset, &CmndTariff }; + &CmndEnergyReset, &CmndTariff}; const char kEnergyPhases[] PROGMEM = "|%s / %s|%s / %s / %s||[%s,%s]|[%s,%s,%s]"; @@ -102,6 +102,7 @@ struct ENERGY { uint8_t phase_count; // Number of phases active bool voltage_common; // Use single voltage bool frequency_common; // Use single frequency + bool use_overtemp; // Use global temperature as overtemp trigger on internal energy monitor hardware bool kWhtoday_offset_init; bool voltage_available; // Enable if voltage is measured @@ -501,7 +502,7 @@ void EnergyMqttShow(void) void EnergyEverySecond(void) { // Overtemp check - if (TasmotaGlobal.global_update) { + if (Energy.use_overtemp && TasmotaGlobal.global_update) { 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: Temperature %1_f"), &TasmotaGlobal.temperature_celsius); @@ -761,6 +762,13 @@ void CmndModuleAddress(void) { } } +void CmndEnergyConfig(void) { + Energy.command_code = CMND_ENERGYCONFIG; + if (XnrgCall(FUNC_COMMAND)) { + ResponseCmndDone(); + } +} + #ifdef USE_ENERGY_MARGIN_DETECTION void CmndPowerDelta(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) { @@ -1136,7 +1144,7 @@ void EnergyShow(bool json) } KnxSensor(KNX_ENERGY_DAILY, Energy.daily); KnxSensor(KNX_ENERGY_TOTAL, Energy.total); - KnxSensor(KNX_ENERGY_START, Energy.start_energy); + KnxSensor(KNX_ENERGY_YESTERDAY, (float)Settings.energy_kWhyesterday / 100000); } #endif // USE_KNX #ifdef USE_WEBSERVER diff --git a/tasmota/xdrv_07_domoticz.ino b/tasmota/xdrv_07_domoticz.ino index 5542288dd..f2289aa68 100644 --- a/tasmota/xdrv_07_domoticz.ino +++ b/tasmota/xdrv_07_domoticz.ino @@ -602,36 +602,31 @@ void HandleDomoticzConfiguration(void) { } void DomoticzSaveSettings(void) { - char stemp[20]; - char ssensor_indices[6 * MAX_DOMOTICZ_SNS_IDX]; - char tmp[100]; - - for (uint32_t i = 0; i < MAX_DOMOTICZ_IDX; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("r%d"), i); - WebGetArg(stemp, tmp, sizeof(tmp)); - Settings.domoticz_relay_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - snprintf_P(stemp, sizeof(stemp), PSTR("k%d"), i); - WebGetArg(stemp, tmp, sizeof(tmp)); - Settings.domoticz_key_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - snprintf_P(stemp, sizeof(stemp), PSTR("s%d"), i); - WebGetArg(stemp, tmp, sizeof(tmp)); - Settings.domoticz_switch_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); + char tmp1[CMDSZ]; + WebGetArg(PSTR("ut"), tmp1, sizeof(tmp1)); + char command[500]; + snprintf_P(command, sizeof(command), PSTR(D_CMND_BACKLOG "0 " D_PRFX_DOMOTICZ D_CMND_UPDATETIMER " %s"), + (!strlen(tmp1)) ? STR(DOMOTICZ_UPDATE_TIMER) : tmp1); + char arg_idx[8]; + char tmp2[CMDSZ]; + char tmp3[CMDSZ]; + for (uint32_t i = 1; i <= MAX_DOMOTICZ_IDX; i++) { + snprintf_P(arg_idx, sizeof(arg_idx), PSTR("r%d"), i -1); + WebGetArg(arg_idx, tmp1, sizeof(tmp1)); + arg_idx[0] = 'k'; + WebGetArg(arg_idx, tmp2, sizeof(tmp2)); + arg_idx[0] = 's'; + WebGetArg(arg_idx, tmp3, sizeof(tmp3)); + snprintf_P(command, sizeof(command),PSTR("%s;" D_PRFX_DOMOTICZ D_CMND_IDX "%d %s;" D_PRFX_DOMOTICZ D_CMND_KEYIDX "%d %s;" D_PRFX_DOMOTICZ D_CMND_SWITCHIDX "%d %s"), + command, i, (!strlen(tmp1)) ? "0" : tmp1, i, (!strlen(tmp2)) ? "0" : tmp2, i, (!strlen(tmp3)) ? "0" : tmp3); } - ssensor_indices[0] = '\0'; - for (uint32_t i = 0; i < DZ_MAX_SENSORS; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("l%d"), i); - WebGetArg(stemp, tmp, sizeof(tmp)); - Settings.domoticz_sensor_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - snprintf_P(ssensor_indices, sizeof(ssensor_indices), PSTR("%s%s%d"), ssensor_indices, (strlen(ssensor_indices)) ? "," : "", Settings.domoticz_sensor_idx[i]); + for (uint32_t i = 1; i <= DZ_MAX_SENSORS; i++) { + snprintf_P(arg_idx, sizeof(arg_idx), PSTR("l%d"), i -1); + WebGetArg(arg_idx, tmp1, sizeof(tmp1)); + snprintf_P(command, sizeof(command),PSTR("%s;" D_PRFX_DOMOTICZ D_CMND_SENSORIDX "%d %s"), + command, i, (!strlen(tmp1)) ? "0" : tmp1); } - WebGetArg(PSTR("ut"), tmp, sizeof(tmp)); - Settings.domoticz_update_timer = (!strlen(tmp)) ? DOMOTICZ_UPDATE_TIMER : atoi(tmp); - - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_DOMOTICZ D_CMND_IDX " %d,%d,%d,%d, " D_CMND_KEYIDX " %d,%d,%d,%d, " D_CMND_SWITCHIDX " %d,%d,%d,%d, " D_CMND_SENSORIDX " %s, " D_CMND_UPDATETIMER " %d"), - Settings.domoticz_relay_idx[0], Settings.domoticz_relay_idx[1], Settings.domoticz_relay_idx[2], Settings.domoticz_relay_idx[3], - Settings.domoticz_key_idx[0], Settings.domoticz_key_idx[1], Settings.domoticz_key_idx[2], Settings.domoticz_key_idx[3], - Settings.domoticz_switch_idx[0], Settings.domoticz_switch_idx[1], Settings.domoticz_switch_idx[2], Settings.domoticz_switch_idx[3], - ssensor_indices, Settings.domoticz_update_timer); + ExecuteWebCommand(command); // Note: beware of max number of commands in backlog currently 30 (MAX_BACKLOG) } #endif // USE_WEBSERVER diff --git a/tasmota/xdrv_09_timers.ino b/tasmota/xdrv_09_timers.ino index af273fa8f..22e38a2e6 100644 --- a/tasmota/xdrv_09_timers.ino +++ b/tasmota/xdrv_09_timers.ino @@ -879,14 +879,12 @@ void HandleTimerConfiguration(void) void TimerSaveSettings(void) { - char tmp[MAX_TIMERS *12]; // Need space for MAX_TIMERS x 10 digit numbers separated by a comma - char message[32 + (MAX_TIMERS *11)]; // MQT: Timers 0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000 Timer timer; Settings.flag3.timers_enable = Webserver->hasArg(F("e0")); // CMND_TIMERS + char tmp[MAX_TIMERS *12]; // Need space for MAX_TIMERS x 10 digit numbers separated by a comma WebGetArg(PSTR("t0"), tmp, sizeof(tmp)); char *p = tmp; - snprintf_P(message, sizeof(message), PSTR(D_LOG_MQTT D_CMND_TIMERS " %d"), Settings.flag3.timers_enable); // CMND_TIMERS for (uint32_t i = 0; i < MAX_TIMERS; i++) { timer.data = strtol(p, &p, 10); p++; // Skip comma @@ -895,9 +893,10 @@ void TimerSaveSettings(void) Settings.timer[i].data = timer.data; if (flag) TimerSetRandomWindow(i); } - snprintf_P(message, sizeof(message), PSTR("%s,0x%08X"), message, Settings.timer[i].data); } - AddLogData(LOG_LEVEL_DEBUG, message); + char command[CMDSZ]; + snprintf_P(command, sizeof(command), PSTR(D_CMND_TIMERS)); + ExecuteWebCommand(command); } #endif // USE_TIMERS_WEB #endif // USE_WEBSERVER diff --git a/tasmota/xdrv_10_rules.ino b/tasmota/xdrv_10_rules.ino index 01bc88ec0..cf539ec6b 100644 --- a/tasmota/xdrv_10_rules.ino +++ b/tasmota/xdrv_10_rules.ino @@ -759,9 +759,7 @@ bool RuleSetProcess(uint8_t rule_set, String &event_saved) RulesVarReplace(commands, F("%TOPIC%"), TasmotaGlobal.mqtt_topic); snprintf_P(stemp, sizeof(stemp), PSTR("%06X"), ESP_getChipId()); RulesVarReplace(commands, F("%DEVICEID%"), stemp); - String mac_address = WiFi.macAddress(); - mac_address.replace(":", ""); - RulesVarReplace(commands, F("%MACADDR%"), mac_address); + RulesVarReplace(commands, F("%MACADDR%"), NetworkUniqueId()); #if defined(USE_TIMERS) && defined(USE_SUNRISE) RulesVarReplace(commands, F("%SUNRISE%"), String(SunMinutes(0))); RulesVarReplace(commands, F("%SUNSET%"), String(SunMinutes(1))); @@ -2138,10 +2136,10 @@ void CmndRule(void) rule = rule.substring(0, MAX_RULE_SIZE); rule += F("..."); } - // snprintf_P (TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("{\"%s%d\":\"%s\",\"Once\":\"%s\",\"StopOnError\":\"%s\",\"Free\":%d,\"Rules\":\"%s\"}"), + // snprintf_P (TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("{\"%s%d\":{\"State\":\"%s\",\"Once\":\"%s\",\"StopOnError\":\"%s\",\"Free\":%d,\"Rules\":\"%s\"}}"), // XdrvMailbox.command, index, GetStateText(bitRead(Settings.rule_enabled, index -1)), GetStateText(bitRead(Settings.rule_once, index -1)), // GetStateText(bitRead(Settings.rule_stop, index -1)), sizeof(Settings.rules[index -1]) - strlen(Settings.rules[index -1]) -1, Settings.rules[index -1]); - snprintf_P (TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("{\"%s%d\":\"%s\",\"Once\":\"%s\",\"StopOnError\":\"%s\",\"Length\":%d,\"Free\":%d,\"Rules\":\"%s\"}"), + snprintf_P (TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("{\"%s%d\":{\"State\":\"%s\",\"Once\":\"%s\",\"StopOnError\":\"%s\",\"Length\":%d,\"Free\":%d,\"Rules\":\"%s\"}}"), XdrvMailbox.command, index, GetStateText(bitRead(Settings.rule_enabled, index -1)), GetStateText(bitRead(Settings.rule_once, index -1)), GetStateText(bitRead(Settings.rule_stop, index -1)), rule_len, MAX_RULE_SIZE - GetRuleLenStorage(index - 1), diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index 7731237bd..5e920afba 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -65,7 +65,9 @@ keywords if then else endif, or, and are better readable for beginners (others m #define SCRIPT_MAXPERM (PMEM_SIZE)-4/sizeof(float) #define MAX_SCRIPT_SIZE MAX_RULE_SIZE*MAX_RULE_SETS +#ifndef MAX_SARRAY_NUM #define MAX_SARRAY_NUM 32 +#endif uint32_t EncodeLightId(uint8_t relay_id); uint32_t DecodeLightId(uint32_t hue_id); @@ -1413,38 +1415,42 @@ uint32_t match_vars(char *dvnam, float **fp, char **sp, uint32_t *ind) { } #endif //USE_SCRIPT_GLOBVARS +#ifndef SCRIPT_IS_STRING_MAXSIZE +#define SCRIPT_IS_STRING_MAXSIZE 256 +#endif + char *isargs(char *lp, uint32_t isind) { float fvar; lp = GetNumericArgument(lp, OPER_EQU, &fvar, 0); SCRIPT_SKIP_SPACES - if (*lp!='"') { + if (*lp != '"') { return lp; } lp++; - if (glob_script_mem.si_num[isind]>0 && glob_script_mem.last_index_string[isind]) { + if (glob_script_mem.si_num[isind] > 0 && glob_script_mem.last_index_string[isind]) { free(glob_script_mem.last_index_string[isind]); } char *sstart = lp; uint8_t slen = 0; - for (uint32_t cnt = 0; cnt<256; cnt++) { - if (*lp=='\n' || *lp=='"' || *lp==0) { + for (uint32_t cnt = 0; cnt < SCRIPT_IS_STRING_MAXSIZE; cnt++) { + if (*lp == '\n' || *lp == '"' || *lp == 0) { lp++; - if (cnt>0 && !slen) { + if (cnt > 0 && !slen) { slen++; } glob_script_mem.siro_num[isind] = slen; break; } - if (*lp=='|') { + if (*lp == '|') { slen++; } lp++; } glob_script_mem.si_num[isind] = fvar; - if (glob_script_mem.si_num[isind]>0) { - if (glob_script_mem.si_num[isind]>MAX_SARRAY_NUM) { + if (glob_script_mem.si_num[isind] > 0) { + if (glob_script_mem.si_num[isind] > MAX_SARRAY_NUM) { glob_script_mem.si_num[isind] = MAX_SARRAY_NUM; } @@ -1468,17 +1474,17 @@ float fvar; char str[SCRIPT_MAXSSIZE]; str[0] = 0; uint8_t index = fvar; - if (index<1) index = 1; + if (index < 1) index = 1; index--; if (gv) gv->strind = index; glob_script_mem.sind_num = isind; if (glob_script_mem.last_index_string[isind]) { if (!glob_script_mem.si_num[isind]) { - if (index<=glob_script_mem.siro_num[isind]) { + if (index <= glob_script_mem.siro_num[isind]) { GetTextIndexed(str, sizeof(str), index , glob_script_mem.last_index_string[isind]); } } else { - if (index>glob_script_mem.si_num[isind]) { + if (index > glob_script_mem.si_num[isind]) { index = glob_script_mem.si_num[isind]; } strlcpy(str,glob_script_mem.last_index_string[isind] + (index * glob_script_mem.max_ssize), glob_script_mem.max_ssize); @@ -1866,6 +1872,15 @@ chknext: } #endif //USE_SCRIPT_TASK #endif //ESP32 +#ifdef USE_ANGLE_FUNC + if (!strncmp(vname, "cos(", 4)) { + lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); + fvar = cosf(fvar); + lp++; + len = 0; + goto exit; + } +#endif break; case 'd': if (!strncmp(vname, "day", 3)) { @@ -2196,6 +2211,22 @@ chknext: len = 0; goto exit; } + if (!strncmp(vname, "fmt(", 4)) { + lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); + if (!fvar) { +#ifdef ESP8266 + LittleFS.format(); +#endif +#ifdef ESP32 + LITTLEFS.format(); +#endif + } else { + //SD.format(); + } + lp++; + len = 0; + goto exit; + } if (!strncmp(vname, "frd(", 4)) { char str[glob_script_mem.max_ssize + 1]; lp = GetStringArgument(lp + 4, OPER_EQU, str, 0); diff --git a/tasmota/xdrv_11_knx.ino b/tasmota/xdrv_11_knx.ino index 445bcf0f0..037f22b73 100644 --- a/tasmota/xdrv_11_knx.ino +++ b/tasmota/xdrv_11_knx.ino @@ -107,7 +107,7 @@ device_parameters_t device_param[] = { { KNX_ENERGY_POWER , false, false, KNX_Empty }, { KNX_ENERGY_POWERFACTOR , false, false, KNX_Empty }, { KNX_ENERGY_DAILY , false, false, KNX_Empty }, - { KNX_ENERGY_START , false, false, KNX_Empty }, + { KNX_ENERGY_YESTERDAY , false, false, KNX_Empty }, { KNX_ENERGY_TOTAL , false, false, KNX_Empty }, { KNX_SLOT1 , false, false, KNX_Empty }, { KNX_SLOT2 , false, false, KNX_Empty }, @@ -501,7 +501,7 @@ void KNX_INIT(void) if ( TasmotaGlobal.energy_driver != ENERGY_NONE ) { device_param[KNX_ENERGY_POWER-1].show = true; device_param[KNX_ENERGY_DAILY-1].show = true; - device_param[KNX_ENERGY_START-1].show = true; + device_param[KNX_ENERGY_YESTERDAY-1].show = true; device_param[KNX_ENERGY_TOTAL-1].show = true; device_param[KNX_ENERGY_VOLTAGE-1].show = true; device_param[KNX_ENERGY_CURRENT-1].show = true; @@ -684,13 +684,14 @@ void KNX_CB_Action(message_t const &msg, void *arg) } } } - else if (chan->type == KNX_ENERGY_START) // Reply KNX_ENERGY_START + else if (chan->type == KNX_ENERGY_YESTERDAY) // Reply KNX_ENERGY_YESTERDAY { if (Energy.data_valid[0]) { - knx.answer_4byte_float(msg.received_on, Energy.start_energy); + float energy_kWhyesterday = (float)Settings.energy_kWhyesterday / 100000; + knx.answer_4byte_float(msg.received_on, energy_kWhyesterday); if (Settings.flag.knx_enable_enhancement) { - knx.answer_4byte_float(msg.received_on, Energy.start_energy); - knx.answer_4byte_float(msg.received_on, Energy.start_energy); + knx.answer_4byte_float(msg.received_on, energy_kWhyesterday); + knx.answer_4byte_float(msg.received_on, energy_kWhyesterday); } } } @@ -813,7 +814,7 @@ void KnxSensor(uint8_t sensor_type, float value) knx.write_4byte_float(KNX_addr, value); } - AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s " D_SENT_TO " %d.%d.%d "), + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s " D_SENT_TO " %d.%d.%d"), device_param_ga[sensor_type -1], KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member); diff --git a/tasmota/xdrv_12_discovery.ino b/tasmota/xdrv_12_discovery.ino new file mode 100644 index 000000000..9a592159a --- /dev/null +++ b/tasmota/xdrv_12_discovery.ino @@ -0,0 +1,294 @@ +/* + xdrv_12_discovery.ino - Discovery support for Tasmota + + Copyright (C) 2021 Erik Montnemery, Federico Leoni and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_TASMOTA_DISCOVERY +#undef USE_HOME_ASSISTANT +/*********************************************************************************************\ + * Tasmota discovery + * + * A version of xdrv_12_home_assistant supporting the new Tasmota Discovery be used by + * latest versions of Home Assistant or TasmoManager. + * + * SetOption19 0 - [DiscoverOff 0] [Discover 1] Enables discovery (default) + * SetOption19 1 - [DiscoverOff 1] [Discover 0] Disables discovery and removes retained message from MQTT server + * SetOption73 1 - [DiscoverButton] Enable discovery for buttons + * SetOption114 1 - [DiscoverSwitch] Enable discovery for switches +\*********************************************************************************************/ + +#define XDRV_12 12 + +uint8_t TasDiscoverData_init_step; + +void TasDiscoverMessage(void) { + Response_P(PSTR("{\"ip\":\"%_I\"," // IP Address + "\"dn\":\"%s\"," // Device Name + "\"fn\":["), // Friendly Names (start) + (uint32_t)WiFi.localIP(), + SettingsText(SET_DEVICENAME)); + + uint32_t maxfn = (TasmotaGlobal.devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!TasmotaGlobal.devices_present) ? 1 : TasmotaGlobal.devices_present; + for (uint32_t i = 0; i < MAX_FRIENDLYNAMES; i++) { + char fname[TOPSZ]; + snprintf_P(fname, sizeof(fname), PSTR("\"%s\""), EscapeJSONString(SettingsText(SET_FRIENDLYNAME1 +i)).c_str()); + ResponseAppend_P(PSTR("%s%s"), (i > 0 ? "," : ""), (i < maxfn) ? fname : PSTR("null")); + } + + bool TuyaMod = false; + bool iFanMod = false; +#ifdef ESP8266 + if ((TUYA_DIMMER == TasmotaGlobal.module_type) || (SK03_TUYA == TasmotaGlobal.module_type)) { TuyaMod = true; }; + if ((SONOFF_IFAN02 == TasmotaGlobal.module_type) || (SONOFF_IFAN03 == TasmotaGlobal.module_type)) { iFanMod = true; }; +#endif // ESP8266 + + ResponseAppend_P(PSTR("]," // Friendly Names (end) + "\"hn\":\"%s\"," // Host Name + "\"mac\":\"%s\"," // Full MAC as Device id + "\"md\":\"%s\"," // Module or Template Name + "\"ty\":%d,\"if\":%d," // Flag for TuyaMCU and Ifan devices + "\"ofln\":\"" MQTT_LWT_OFFLINE "\"," // Payload Offline + "\"onln\":\"" MQTT_LWT_ONLINE "\"," // Payload Online + "\"state\":[\"%s\",\"%s\",\"%s\",\"%s\"]," // State text for "OFF","ON","TOGGLE","HOLD" + "\"sw\":\"%s\"," // Software Version + "\"t\":\"%s\"," // Topic + "\"ft\":\"%s\"," // Full Topic + "\"tp\":[\"%s\",\"%s\",\"%s\"]," // Topics for command, stat and tele + "\"rl\":["), // Relays (start) + TasmotaGlobal.hostname, + NetworkUniqueId().c_str(), + ModuleName().c_str(), + TuyaMod, iFanMod, + GetStateText(0), GetStateText(1), GetStateText(2), GetStateText(3), + TasmotaGlobal.version, + TasmotaGlobal.mqtt_topic, + SettingsText(SET_MQTT_FULLTOPIC), + PSTR(SUB_PREFIX), + PSTR(PUB_PREFIX), + PSTR(PUB_PREFIX2)); + + uint8_t lightidx = MAX_RELAYS + 1; // Will store the starting position of the lights + if (Light.subtype > LST_NONE) { + if (!light_controller.isCTRGBLinked()) { // One or two lights present + lightidx = TasmotaGlobal.devices_present - 2; + } else { + lightidx = TasmotaGlobal.devices_present - 1; + } + } + + if ((Light.device > 0) && Settings.flag3.pwm_multi_channels) { // How many relays are light devices? + lightidx = TasmotaGlobal.devices_present - Light.subtype; + } + + uint16_t Relay[MAX_RELAYS] = { 0 }; // Base array to store the relay type + uint16_t Shutter[MAX_RELAYS] = { 0 }; // Array to store a temp list for shutters + for (uint32_t i = 0; i < MAX_RELAYS; i++) { + if (i < TasmotaGlobal.devices_present) { + +#ifdef USE_SHUTTER + if (Settings.flag3.shutter_mode) { + for (uint32_t k = 0; k < MAX_SHUTTERS; k++) { + if (0 == Settings.shutter_startrelay[k]) { + break; + } else { + if (Settings.shutter_startrelay[k] > 0 && Settings.shutter_startrelay[k] <= MAX_SHUTTER_RELAYS) { + Shutter[Settings.shutter_startrelay[k]-1] = Shutter[Settings.shutter_startrelay[k]] = 1; + } + } + } + } +#endif // USE_SHUTTER + + if (Shutter[i] != 0) { // Check if there are shutters present + Relay[i] = 3; // Relay is a shutter + } else { + if (i >= lightidx || (iFanMod && (0 == i))) { // First relay on Ifan controls the light + Relay[i] = 2; // Relay is a light + } else { + if (!iFanMod) { // Relays 2-4 for ifan are controlled by FANSPEED and don't need to be present if TasmotaGlobal.module_type = SONOFF_IFAN02 or SONOFF_IFAN03 + Relay[i] = 1; // Simple Relay + } + } + } + } + ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), Relay[i]); // Vector for the Official Integration + } + + ResponseAppend_P(PSTR("]," // Relays (end) + "\"swc\":[")); // Switch modes (start) + + // Enable Discovery for Switches only if SetOption114 is enabled + for (uint32_t i = 0; i < MAX_SWITCHES; i++) { + ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), (PinUsed(GPIO_SWT1, i) && Settings.flag5.mqtt_switches) ? Settings.switchmode[i] : -1); + } + + ResponseAppend_P(PSTR("]," // Switch modes (end) + "\"swn\":[")); // Switch names (start) + + // Enable Discovery for Switches only if SetOption114 is enabled + for (uint32_t i = 0; i < MAX_SWITCHES; i++) { + char sname[TOPSZ]; + snprintf_P(sname, sizeof(sname), PSTR("\"%s\""), GetSwitchText(i).c_str()); + ResponseAppend_P(PSTR("%s%s"), (i > 0 ? "," : ""), (PinUsed(GPIO_SWT1, i) && Settings.flag5.mqtt_switches) ? sname : PSTR("null")); + } + + ResponseAppend_P(PSTR("]," // Switch names (end) + "\"btn\":[")); // Button flag (start) + + bool SerialButton = false; + // Enable Discovery for Buttons only if SetOption73 is enabled + for (uint32_t i = 0; i < MAX_KEYS; i++) { +#ifdef ESP8266 + SerialButton = ((0 == i) && (SONOFF_DUAL == TasmotaGlobal.module_type )); +#endif // ESP8266 + ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), (SerialButton ? 1 : (PinUsed(GPIO_KEY1, i)) && Settings.flag3.mqtt_buttons)); + } + + ResponseAppend_P(PSTR("]," // Button flag (end) + "\"so\":{\"4\":%d," // SetOptions + "\"11\":%d," + "\"13\":%d," + "\"17\":%d," + "\"20\":%d," + "\"30\":%d," + "\"68\":%d," + "\"73\":%d," + "\"82\":%d," + "\"114\":%d," + "\"117\":%d}," + "\"lk\":%d," // Light CTRGB linked + "\"lt_st\":%d," // Light SubType + "\"sho\":["), // Shutter Options (start) + Settings.flag.mqtt_response, + Settings.flag.button_swap, + Settings.flag.button_single, + Settings.flag.decimal_text, + Settings.flag.not_power_linked, + Settings.flag.hass_light, + Settings.flag3.pwm_multi_channels, + Settings.flag3.mqtt_buttons, + Settings.flag4.alexa_ct_range, + Settings.flag5.mqtt_switches, + Settings.flag5.fade_fixed_duration, + light_controller.isCTRGBLinked(), + Light.subtype); + + for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { +#ifdef USE_SHUTTER + ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), Settings.shutter_options[i]); +#else + ResponseAppend_P(PSTR("%s0"), (i > 0 ? "," : "")); +#endif // USE_SHUTTER + } + + ResponseAppend_P(PSTR("]," // Shutter Options (end) + "\"ver\":1}")); // Discovery version +} + +void TasDiscovery(void) { + TasmotaGlobal.masterlog_level = LOG_LEVEL_DEBUG_MORE; // Hide topic on clean and remove use weblog 4 to show it + + ResponseClear(); // Clear retained message + if (!Settings.flag.hass_discovery) { // SetOption19 - Clear retained message + TasDiscoverMessage(); // Build discovery message + } + char stopic[TOPSZ]; + snprintf_P(stopic, sizeof(stopic), PSTR("tasmota/discovery/%s/config"), NetworkUniqueId().c_str()); + MqttPublish(stopic, true); + + if (!Settings.flag.hass_discovery) { // SetOption19 - Clear retained message + Response_P(PSTR("{\"sn\":")); + MqttShowSensor(); + ResponseAppend_P(PSTR(",\"ver\":1}")); + } + snprintf_P(stopic, sizeof(stopic), PSTR("tasmota/discovery/%s/sensors"), NetworkUniqueId().c_str()); + MqttPublish(stopic, true); + + TasmotaGlobal.masterlog_level = LOG_LEVEL_NONE; // Restore WebLog state +} + +void TasRediscover(void) { + TasDiscoverData_init_step = 1; // Delayed discovery or clear retained messages +} + +void TasDiscoverInit(void) { + if (ResetReason() != REASON_DEEP_SLEEP_AWAKE) { + Settings.flag.hass_discovery = 0; // SetOption19 - Enable Tasmota discovery and Disable legacy Hass discovery + TasDiscoverData_init_step = 10; // Delayed discovery + } +} + +/*********************************************************************************************\ + * Commands + * + * Discover 0 - Disables discovery and removes retained message from MQTT server + * Discover 1 - Enables discovery (default) + * DiscoverOff 0 - Enables discovery (default) + * DiscoverOff 1 - Disables discovery and removes retained message from MQTT server + * DiscoverButton 1 - Enable discovery for buttons + * DiscoverSwitch 1 - Enable discovery for switches +\*********************************************************************************************/ + +const char kTasDiscoverCommands[] PROGMEM = "Discover|" // Prefix + // SetOption synonyms + "Off|Button|Switch|" + // Commands + "|"; + +SO_SYNONYMS(kTasDiscoverSynonyms, + 19, 73, 114 ); + +void (* const TasDiscoverCommand[])(void) PROGMEM = { + &CmndTasDiscover }; + +void CmndTasDiscover(void) { + if (XdrvMailbox.payload >= 0) { + Settings.flag.hass_discovery = !(XdrvMailbox.payload & 1); + TasRediscover(); + } + ResponseCmndChar(GetStateText(!Settings.flag.hass_discovery)); +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv12(uint8_t function) { + bool result = false; + + if (Settings.flag.mqtt_enabled) { // SetOption3 - Enable MQTT + switch (function) { + case FUNC_EVERY_SECOND: + if (TasDiscoverData_init_step) { + TasDiscoverData_init_step--; + if (!TasDiscoverData_init_step) { + TasDiscovery(); // Send the topics for discovery + } + } + break; + case FUNC_COMMAND: + result = DecodeCommand(kTasDiscoverCommands, TasDiscoverCommand, kTasDiscoverSynonyms); + break; + case FUNC_MQTT_INIT: + TasDiscoverInit(); + break; + } + } + return result; +} + +#endif // USE_TASMOTA_DISCOVERY \ No newline at end of file diff --git a/tasmota/xdrv_12_home_assistant.ino b/tasmota/xdrv_12_home_assistant.ino index 617ec2e39..b4d1a945a 100644 --- a/tasmota/xdrv_12_home_assistant.ino +++ b/tasmota/xdrv_12_home_assistant.ino @@ -18,6 +18,7 @@ */ #ifdef USE_HOME_ASSISTANT +#undef USE_TASMOTA_DISCOVERY #define XDRV_12 12 @@ -328,9 +329,7 @@ void NewHAssDiscovery(void) ResponseClear(); // Clear retained message // Full 12 chars MAC address as ID - String mac_address = WiFi.macAddress(); - mac_address.replace(":", ""); - snprintf_P(unique_id, sizeof(unique_id), PSTR("%s"), mac_address.c_str()); + snprintf_P(unique_id, sizeof(unique_id), PSTR("%s"), NetworkUniqueId().c_str()); snprintf_P(stopic, sizeof(stopic), PSTR("tasmota/discovery/%s/config"), unique_id); // Send empty message if new discovery is disabled diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index fe599d7a7..1b8a19df9 100755 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -80,6 +80,7 @@ const uint8_t DISPLAY_LOG_ROWS = 32; // Number of lines in display log #define D_CMND_DISP_CLOCK "Clock" #define D_CMND_DISP_TEXTNC "TextNC" // NC - "No Clear" #define D_CMND_DISP_SCROLLTEXT "ScrollText" +#define D_CMND_DISP_REINIT "reinit" enum XdspFunctions { FUNC_DISPLAY_INIT_DRIVER, FUNC_DISPLAY_INIT, FUNC_DISPLAY_EVERY_50_MSECOND, FUNC_DISPLAY_EVERY_SECOND, FUNC_DISPLAY_MODEL, FUNC_DISPLAY_MODE, FUNC_DISPLAY_POWER, @@ -108,7 +109,7 @@ const char kDisplayCommands[] PROGMEM = D_PRFX_DISPLAY "|" // Prefix #endif D_CMND_DISP_CLEAR "|" D_CMND_DISP_NUMBER "|" D_CMND_DISP_FLOAT "|" D_CMND_DISP_NUMBERNC "|" D_CMND_DISP_FLOATNC "|" D_CMND_DISP_RAW "|" D_CMND_DISP_LEVEL "|" D_CMND_DISP_SEVENSEG_TEXT "|" D_CMND_DISP_SEVENSEG_TEXTNC "|" - D_CMND_DISP_SCROLLDELAY "|" D_CMND_DISP_CLOCK "|" D_CMND_DISP_TEXTNC "|" D_CMND_DISP_SCROLLTEXT + D_CMND_DISP_SCROLLDELAY "|" D_CMND_DISP_CLOCK "|" D_CMND_DISP_TEXTNC "|" D_CMND_DISP_SCROLLTEXT "|" D_CMND_DISP_REINIT ; void (* const DisplayCommand[])(void) PROGMEM = { @@ -120,7 +121,7 @@ void (* const DisplayCommand[])(void) PROGMEM = { #endif &CmndDisplayClear, &CmndDisplayNumber, &CmndDisplayFloat, &CmndDisplayNumberNC, &CmndDisplayFloatNC, &CmndDisplayRaw, &CmndDisplayLevel, &CmndDisplaySevensegText, &CmndDisplaySevensegTextNC, - &CmndDisplayScrollDelay, &CmndDisplayClock, &CmndDisplayTextNC, &CmndDisplayScrollText + &CmndDisplayScrollDelay, &CmndDisplayClock, &CmndDisplayTextNC, &CmndDisplayScrollText,&DisplayReInitDriver }; #ifdef USE_GRAPH @@ -989,7 +990,7 @@ void Display_Text_From_File(const char *file) { File fp; if (!ufsp) return; fp = ufsp->open(file, FS_FILE_READ); - if (fp >= 0) { + if (fp > 0) { char *savptr = XdrvMailbox.data; char linebuff[128]; while (fp.available()) { @@ -1021,7 +1022,7 @@ void Display_Text_From_File(const char *file) { fp.close(); } } -#endif +#endif // USE_UFILESYS #ifdef USE_DT_VARS @@ -2001,6 +2002,11 @@ void CmndDisplayScrollText(void) { if(result) ResponseCmndChar(XdrvMailbox.data); } +void DisplayReInitDriver(void) { + XdspCall(FUNC_DISPLAY_INIT_DRIVER); + ResponseCmndDone(); +} + /*********************************************************************************************\ * Optional drivers \*********************************************************************************************/ diff --git a/tasmota/xdrv_20_hue.ino b/tasmota/xdrv_20_hue.ino index db20ef24c..e41233b9c 100644 --- a/tasmota/xdrv_20_hue.ino +++ b/tasmota/xdrv_20_hue.ino @@ -172,8 +172,7 @@ const char HUE_API[] PROGMEM = "\x00\x06\x3B\x37\x8C\xEC\x2D\x10\xEC\x9C\x2F\x9D String HueBridgeId(void) { - String temp = WiFi.macAddress(); - temp.replace(":", ""); + String temp = NetworkUniqueId(); String bridgeid = temp.substring(0, 6); bridgeid += F("FFFE"); bridgeid += temp.substring(6); @@ -182,8 +181,7 @@ String HueBridgeId(void) String HueSerialnumber(void) { - String serial = WiFi.macAddress(); - serial.replace(":", ""); + String serial = NetworkUniqueId(); serial.toLowerCase(); return serial; // 5ccf7f139f3d } diff --git a/tasmota/xdrv_40_telegram.ino b/tasmota/xdrv_40_telegram.ino index d73f39341..8d1099fc1 100644 --- a/tasmota/xdrv_40_telegram.ino +++ b/tasmota/xdrv_40_telegram.ino @@ -62,11 +62,11 @@ static const uint8_t Telegram_Fingerprint[] PROGMEM = USE_TELEGRAM_FINGERPRINT; typedef struct { String text; + String chat_id; // String from_first_name; // String from_last_name; // uint32_t from_id = 0; uint32_t update_id = 0; - int32_t chat_id = 0; } TelegramMessage; struct { @@ -233,12 +233,12 @@ void TelegramGetUpdates(uint32_t offset) { // Telegram.message[i].from_id = result["message"].getObject()["from"].getObject()["id"].getUInt(); // Telegram.message[i].from_first_name = result["message"].getObject()["from"].getObject()["first_name"].getStr(); // Telegram.message[i].from_last_name = result["message"].getObject()["from"].getObject()["last_name"].getStr(); - Telegram.message[i].chat_id = result["message"].getObject()["chat"].getObject()["id"].getUInt(); + Telegram.message[i].chat_id = result["message"].getObject()["chat"].getObject()["id"].getStr(); Telegram.message[i].text = result["message"].getObject()["text"].getStr(); } Telegram.next_update_id = Telegram.message[i].update_id +1; // Write id of last read message - AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Parsed update_id %d, chat_id %d, text \"%s\""), Telegram.message[i].update_id, Telegram.message[i].chat_id, Telegram.message[i].text.c_str()); + AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Parsed update_id %d, chat_id %s, text \"%s\""), Telegram.message[i].update_id, Telegram.message[i].chat_id.c_str(), Telegram.message[i].text.c_str()); } } else { // AddLog(LOG_LEVEL_DEBUG, PSTR("TGM: No new messages")); @@ -248,7 +248,7 @@ void TelegramGetUpdates(uint32_t offset) { } } -bool TelegramSendMessage(int32_t chat_id, String text) { +bool TelegramSendMessage(String chat_id, String text) { AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: sendMessage")); if (!TelegramInit()) { return false; } @@ -256,7 +256,7 @@ bool TelegramSendMessage(int32_t chat_id, String text) { bool sent = false; if (text != "") { String _token = SettingsText(SET_TELEGRAM_TOKEN); - String command = "bot" + _token + "/sendMessage?chat_id=" + String(chat_id) + "&text=" + UrlEncode(text); + String command = "bot" + _token + "/sendMessage?chat_id=" + chat_id + "&text=" + UrlEncode(text); String response = TelegramConnectToTelegram(command); // AddLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Response %s"), response.c_str()); @@ -440,7 +440,7 @@ void CmndTmSend(void) { if (XdrvMailbox.data_len > 0) { String message = XdrvMailbox.data; String chat_id = SettingsText(SET_TELEGRAM_CHATID); - if (!TelegramSendMessage(chat_id.toInt(), message)) { + if (!TelegramSendMessage(chat_id, message)) { ResponseCmndFailed(); return; } diff --git a/tasmota/xdrv_50_filesystem.ino b/tasmota/xdrv_50_filesystem.ino index 3a5626cfb..c187df02c 100644 --- a/tasmota/xdrv_50_filesystem.ino +++ b/tasmota/xdrv_50_filesystem.ino @@ -279,7 +279,7 @@ bool TfsFileExists(const char *fname){ bool yes = ffsp->exists(fname); if (!yes) { - AddLog(LOG_LEVEL_DEBUG, PSTR("TFS: File not found")); + AddLog(LOG_LEVEL_DEBUG, PSTR("TFS: File '%s' not found"), fname); } return yes; } @@ -320,7 +320,7 @@ bool TfsLoadFile(const char *fname, uint8_t *buf, uint32_t len) { File file = ffsp->open(fname, "r"); if (!file) { - AddLog(LOG_LEVEL_INFO, PSTR("TFS: File not found")); + AddLog(LOG_LEVEL_INFO, PSTR("TFS: File '%s' not found"), fname); return false; } @@ -564,21 +564,46 @@ const char UFS_FORM_SDC_DIRa[] PROGMEM = const char UFS_FORM_SDC_DIRc[] PROGMEM = ""; const char UFS_FORM_FILE_UPGb[] PROGMEM = +#ifdef GUI_EDIT_FILE + "
" + "" +#endif "
" "" ""; const char UFS_FORM_SDC_DIRd[] PROGMEM = "
%s
"; const char UFS_FORM_SDC_DIRb[] PROGMEM = - "
%s %s %8d %s
"; + "
%s %s %8d %s %s
"; const char UFS_FORM_SDC_HREF[] PROGMEM = - "http://%_I/ufsd?download=%s/%s"; + "ufsd?download=%s/%s"; + #ifdef GUI_TRASH_FILE const char UFS_FORM_SDC_HREFdel[] PROGMEM = - //"🗑"; - "🔥"; // 🔥 + //"🗑"; // 🗑️ + "🔥"; // 🔥 #endif // GUI_TRASH_FILE +#ifdef GUI_EDIT_FILE + +#define FILE_BUFFER_SIZE 1024 + +const char UFS_FORM_SDC_HREFedit[] PROGMEM = + "📝"; // 📝 + +const char HTTP_EDITOR_FORM_START[] PROGMEM = + "
 " D_EDIT_FILE " " + "
" + "

" + "" + "" + "
"; + +#endif // #ifdef GUI_EDIT_FILE + void UfsDirectory(void) { if (!HttpCheckPriviledgedAccess()) { return; } @@ -656,7 +681,7 @@ void UfsListDir(char *path, uint8_t depth) { if (dir) { dir.rewindDirectory(); if (strlen(path)>1) { - ext_snprintf_P(npath, sizeof(npath), PSTR("http://%_I/ufsd?download=%s"), (uint32_t)WiFi.localIP(), path); + ext_snprintf_P(npath, sizeof(npath), PSTR("ufsd?download=%s"), path); for (uint32_t cnt = strlen(npath) - 1; cnt > 0; cnt--) { if (npath[cnt] == '/') { if (npath[cnt - 1] == '=') { @@ -698,7 +723,7 @@ void UfsListDir(char *path, uint8_t depth) { sprintf(cp, format, ep); if (entry.isDirectory()) { - ext_snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, (uint32_t)WiFi.localIP(), pp, ep); + ext_snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, pp, ep); WSContentSend_P(UFS_FORM_SDC_DIRd, npath, ep, name); uint8_t plen = strlen(path); if (plen > 1) { @@ -710,13 +735,20 @@ void UfsListDir(char *path, uint8_t depth) { } else { #ifdef GUI_TRASH_FILE char delpath[128]; - ext_snprintf_P(delpath, sizeof(delpath), UFS_FORM_SDC_HREFdel, (uint32_t)WiFi.localIP(), pp, ep); + ext_snprintf_P(delpath, sizeof(delpath), UFS_FORM_SDC_HREFdel, pp, ep); #else char delpath[2]; delpath[0]=0; #endif // GUI_TRASH_FILE - ext_snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, (uint32_t)WiFi.localIP(), pp, ep); - WSContentSend_P(UFS_FORM_SDC_DIRb, npath, ep, name, tstr.c_str(), entry.size(), delpath); +#ifdef GUI_EDIT_FILE + char editpath[128]; + ext_snprintf_P(editpath, sizeof(editpath), UFS_FORM_SDC_HREFedit, pp, ep); +#else + char editpath[2]; + editpath[0]=0; +#endif // GUI_TRASH_FILE + ext_snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, pp, ep); + WSContentSend_P(UFS_FORM_SDC_DIRb, npath, ep, name, tstr.c_str(), entry.size(), delpath, editpath); } } entry.close(); @@ -733,13 +765,13 @@ uint8_t UfsDownloadFile(char *file) { File download_file; if (!dfsp->exists(file)) { - AddLog(LOG_LEVEL_INFO, PSTR("UFS: File not found")); + AddLog(LOG_LEVEL_INFO, PSTR("UFS: File '%s' not found"), file); return 0; } download_file = dfsp->open(file, UFS_FILE_READ); if (!download_file) { - AddLog(LOG_LEVEL_INFO, PSTR("UFS: Could not open file")); + AddLog(LOG_LEVEL_INFO, PSTR("UFS: Could not open file '%s'"), file); return 0; } @@ -877,6 +909,117 @@ void UfsUploadFileClose(void) { ufs_upload_file.close(); } + +//****************************************************************************************** +// File Editor +//****************************************************************************************** + +#ifdef GUI_EDIT_FILE + +void UfsEditor(void) { + if (!HttpCheckPriviledgedAccess()) { return; } + + AddLog(LOG_LEVEL_DEBUG, PSTR("UFS: UfsEditor GET")); + + String fname; + if (Webserver->hasArg(F("file"))) { + fname = Webserver->arg(F("file")); + } + else { + fname = D_NEW_FILE; + } + if (fname[0] != '/') fname = "/" +fname; + + AddLog(LOG_LEVEL_DEBUG, PSTR("UFS: UfsEditor: file=%s, ffs_type=%d, TfsFileExist=%d"), fname.c_str(), ffs_type, TfsFileExists(fname.c_str())); + + WSContentStart_P(PSTR(D_EDIT_FILE)); + WSContentSendStyle(); + WSContentSend_P(HTTP_EDITOR_FORM_START, fname.c_str()); + + if (ffs_type && TfsFileExists(fname.c_str())) { + File fp = ffsp->open(fname.c_str(), "r"); + if (!fp) { + AddLog(LOG_LEVEL_DEBUG, PSTR("UFS: UfsEditor: file open failed")); + WSContentSend_P(D_NEW_FILE); + } + else { + uint8_t *buf = (uint8_t*)malloc(FILE_BUFFER_SIZE+1); + size_t filelen = fp.size(); + AddLog(LOG_LEVEL_DEBUG, PSTR("UFS: UfsEditor: file len=%d"), filelen); + while ( filelen > 0 ) { + size_t l = fp.read(buf, FILE_BUFFER_SIZE); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("UFS: UfsEditor: read=%d"), l); + if (l < 0) break; + buf[l] = '\0'; + WSContentSend_P((const char*)buf); + filelen -= l; + } + fp.close(); + free(buf); + AddLog(LOG_LEVEL_DEBUG, PSTR("UFS: UfsEditor: read done")); + } + } + else { + WSContentSend_P(D_NEW_FILE); + } + + WSContentSend_P(HTTP_EDITOR_FORM_END); + WSContentSend_P(UFS_WEB_DIR, PSTR(D_MANAGE_FILE_SYSTEM)); + WSContentStop(); +} + +void UfsEditorUpload(void) { + AddLog(LOG_LEVEL_DEBUG, PSTR("UFS: UfsEditor: file upload")); + + if (!HttpCheckPriviledgedAccess()) { return; } + + if (!Webserver->hasArg("name")) { + AddLog(LOG_LEVEL_ERROR, PSTR("UFS: UfsEditor: file upload - no filename")); + WSSend(400, CT_PLAIN, F("400: Bad request - no filename")); + return; + } + String name = Webserver->arg("name"); + AddLog(LOG_LEVEL_DEBUG, PSTR("UFS: UfsEditor: file '%s'"), name.c_str()); + + if (!Webserver->hasArg("content")) { + AddLog(LOG_LEVEL_ERROR, PSTR("UFS: UfsEditor: file upload - no content")); + WSSend(400, CT_PLAIN, F("400: Bad request - no content")); + return; + } + String content = Webserver->arg("content"); + + if (!ffsp) { + Web.upload_error = 1; + AddLog(LOG_LEVEL_ERROR, PSTR("UFS: UfsEditor: 507: no storage available")); + WSSend(507, CT_PLAIN, F("507: no storage available")); + return; + } + + File fp = ffsp->open(name.c_str(), "w"); + if(!fp) { + Web.upload_error = 1; + AddLog(LOG_LEVEL_ERROR, PSTR("UFS: UfsEditor: 400: invalid file name '%s'"), name.c_str()); + WSSend(400, CT_PLAIN, F("400: bad request - invalid filename")); + return; + } + + if (*content.c_str()) { + content.replace("\r\n", "\n"); + content.replace("\r", "\n"); + } + + if (!fp.print(content)) { + AddLog(LOG_LEVEL_ERROR, PSTR("UFS: UfsEditor: write error on '%s'"), name.c_str()); + } + + fp.close(); + + Webserver->sendHeader(F("Location"),F("/ufsu")); + Webserver->send(303); +} + +#endif // #ifdef GUI_EDIT_FILE + #endif // USE_WEBSERVER /*********************************************************************************************\ @@ -916,6 +1059,10 @@ bool Xdrv50(uint8_t function) { Webserver->on("/ufsd", UfsDirectory); Webserver->on("/ufsu", HTTP_GET, UfsDirectory); Webserver->on("/ufsu", HTTP_POST,[](){Webserver->sendHeader(F("Location"),F("/ufsu"));Webserver->send(303);}, HandleUploadLoop); +#ifdef GUI_EDIT_FILE + Webserver->on("/ufse", HTTP_GET, UfsEditor); + Webserver->on("/ufse", HTTP_POST, UfsEditorUpload); +#endif break; #endif // USE_WEBSERVER } diff --git a/tasmota/xdrv_52_3_berry_tasmota.ino b/tasmota/xdrv_52_3_berry_tasmota.ino index 89ea65858..e22330a7e 100644 --- a/tasmota/xdrv_52_3_berry_tasmota.ino +++ b/tasmota/xdrv_52_3_berry_tasmota.ino @@ -361,4 +361,21 @@ void berry_log(const char * berry_buf) { } +/*********************************************************************************************\ + * Helper function for `Driver` class + * + * get_tasmota() -> tasmota instance from globals + * allows to use solidified methods refering to the global object `tasmota` + * +\*********************************************************************************************/ +extern "C" { + + int32_t d_getTasmotaGlob(struct bvm *vm); + int32_t d_getTasmotaGlob(struct bvm *vm) { + be_getglobal(berry.vm, PSTR("tasmota")); + be_return(vm); // Return + } + +} + #endif // USE_BERRY diff --git a/tasmota/xdrv_52_7_berry_embedded.ino b/tasmota/xdrv_52_7_berry_embedded.ino index cfcce38e2..80755d691 100644 --- a/tasmota/xdrv_52_7_berry_embedded.ino +++ b/tasmota/xdrv_52_7_berry_embedded.ino @@ -22,7 +22,7 @@ /*********************************************************************************************\ * Handlers for Berry calls and async - * + * \*********************************************************************************************/ const char berry_prog[] = @@ -106,7 +106,7 @@ const char berry_prog[] = // "self._rules.remove(pat) " // "end " // "end " - + // // Rules trigger if match. return true if match, false if not // "def try_rule(event, rule, f) " // "import string " @@ -161,7 +161,7 @@ const char berry_prog[] = // "end " // "return false " // "end " - + // "def set_timer(delay,f) " // "if !self._timers self._timers=[] end " // "self._timers.push([self.millis(delay),f]) " @@ -258,7 +258,7 @@ const char berry_prog[] = // "c() " // "self.log(string.format(\"BRY: sucessfully loaded '%s'\",f)) " // "except .. as e " - // "raise \"io_error\",string.format(\"Could not load file '%s'\",f) " + // "raise \"io_error\",string.format(\"Could not load file '%s'\",f) " // "end " // "end " @@ -352,6 +352,15 @@ const char berry_prog[] = "end " + // // Monkey patch `Driver` class - To be continued + // "class Driver2 : Driver " + // "def add_cmd(c, f) " + // "var tasmota = self.get_tasmota() " + // "tasmota.add_cmd(c, / cmd, idx, payload, payload_json -> f(self, cmd, idx, payload, payload_json)) " + // "end " + // "end " + // "Driver = Driver2 " + // Instantiate tasmota object "tasmota = Tasmota() " "def log(m,l) tasmota.log(m,l) end " @@ -380,12 +389,16 @@ const char berry_prog[] = // "end " // "end " +#ifdef USE_I2C "tasmota.wire1 = Wire(1) " "tasmota.wire2 = Wire(2) " "wire1 = tasmota.wire1 " "wire2 = tasmota.wire2 " +#endif // USE_I2C + // auto-import gpio "import gpio " + #ifdef USE_LIGHT "import light " #endif // USE_LIGHT @@ -395,8 +408,8 @@ const char berry_autoexec[] = // load "autoexec.be" using import, which loads either .be or .bec file "try " "load('autoexec.be') " - "except .. " - "log(\"BRY: No 'autoexec.be' file\") " + "except .. as e,m " + "log(\"BRY: exception in autoexec '\",e,\"':\",m) " "end " ; #endif // USE_BERRY diff --git a/tasmota/xdsp_16_epaper_47.ino b/tasmota/xdsp_16_esp32_epaper_47.ino similarity index 92% rename from tasmota/xdsp_16_epaper_47.ino rename to tasmota/xdsp_16_esp32_epaper_47.ino index d56651a6f..990c92fdf 100644 --- a/tasmota/xdsp_16_epaper_47.ino +++ b/tasmota/xdsp_16_esp32_epaper_47.ino @@ -1,5 +1,5 @@ /* - xdsp_16_epaper_47.ino - LILIGO47 e-paper support for Tasmota + xdsp_16_esp32_epaper_47.ino - LILIGO47 e-paper support for Tasmota Copyright (C) 2021 Theo Arends, Gerhard Mutz and LILIGO @@ -17,7 +17,7 @@ along with this program. If not, see . */ - +#ifdef ESP32 #ifdef USE_DISPLAY #ifdef USE_LILYGO47 @@ -37,8 +37,8 @@ extern uint16_t bg_color; /*********************************************************************************************/ void EpdInitDriver47(void) { + if (PinUsed(GPIO_EPD_DATA)) { - if (1) { Settings.display_model = XDSP_16; if (Settings.display_width != EPD47_WIDTH) { @@ -53,7 +53,7 @@ void EpdInitDriver47(void) { epd47->Init(); renderer = epd47; - renderer->DisplayInit(DISPLAY_INIT_FULL, Settings.display_size, Settings.display_rotate, Settings.display_font); + renderer->DisplayInit(DISPLAY_INIT_MODE, Settings.display_size, Settings.display_rotate, Settings.display_font); renderer->setTextColor(EPD47_BLACK, EPD47_WHITE); #ifdef SHOW_SPLASH @@ -96,5 +96,6 @@ bool Xdsp16(uint8_t function) return result; } -#endif // USE_DISPLAY_EPAPER +#endif // USE_LILYGO47 #endif // USE_DISPLAY +#endif // ESP32 diff --git a/tasmota/xdsp_17_universal.ino b/tasmota/xdsp_17_universal.ino new file mode 100644 index 000000000..c72b4cb85 --- /dev/null +++ b/tasmota/xdsp_17_universal.ino @@ -0,0 +1,332 @@ +/* + xdsp_17_universal.ino - universal display driver support for Tasmota + + Copyright (C) 2021 Gerhard Mutz and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#ifdef USE_DISPLAY +#ifdef USE_UNIVERSAL_DISPLAY + +#define XDSP_17 17 + +#include + +uDisplay *udisp; +bool udisp_init_done = false; +extern uint8_t color_type; +extern uint16_t fg_color; +extern uint16_t bg_color; + +#ifdef USE_UFILESYS +extern FS *ufsp; +#endif + +#define DISPDESC_SIZE 1000 + +#define DSP_ROM_DESC + +/*********************************************************************************************/ +#ifdef DSP_ROM_DESC +/* sample descriptor */ +const char DSP_SAMPLE_DESC[] PROGMEM = +// name,xs,ys,bpp,interface, (HEX) address, scl,sda,reset +// '*' means take pin number from tasmota +":H\n" +"SH1106,128,64,1,I2C,3c,*,*,*\n" +// splash settings, font, size, fgcol, bgcol, x,y +":S\n" +"0,1,1,0,40,20\n" +// init register settings, must be in HEX +":I\n" +"AE\n" +"D5,80\n" +"A8,3f\n" +"D3,00\n" +"40\n" +"8D,14\n" +"20,00\n" +"A1\n" +"C8\n" +"DA,12\n" +"81,CF\n" +"D9F1\n" +"DB,40\n" +"A4\n" +"A6\n" +"AF\n" +// switch display off +":o\n" +"AE\n" +// switch display on +":O\n" +"AF\n" +"#\n"; + +#endif // DSP_ROM_DESC +/*********************************************************************************************/ + +void Init_uDisp(void) { +char *ddesc = 0; +char *fbuff; + + if (TasmotaGlobal.gpio_optiona.udisplay_driver) { + Settings.display_model = XDSP_17; + + fg_color = 1; + bg_color = 0; + color_type = COLOR_BW; + + fbuff = (char*)calloc(DISPDESC_SIZE, 1); + if (!fbuff) return; + +#ifdef USE_UFILESYS + if (ufsp && !TasmotaGlobal.no_autoexec) { + File fp; + fp = ufsp->open("/dispdesc.txt", "r"); + if (fp > 0) { + uint32_t size = fp.size(); + fp.read((uint8_t*)fbuff, size); + fp.close(); + ddesc = fbuff; + AddLog(LOG_LEVEL_INFO, PSTR("DSP: File descriptor used")); + } + } +#endif + + +#ifdef USE_SCRIPT + if (bitRead(Settings.rule_enabled, 0) && !ddesc) { + uint8_t dfound = Run_Scripter(">d",-2,0); + if (dfound == 99) { + char *lp = glob_script_mem.section_ptr + 2; + while (*lp != '\n') lp++; + memcpy(fbuff, lp + 1, DISPDESC_SIZE - 1); + ddesc = fbuff; + AddLog(LOG_LEVEL_INFO, PSTR("DSP: Script descriptor used")); + } + } +#endif // USE_SCRIPT + + +#ifdef DSP_ROM_DESC + if (!ddesc) { + memcpy_P(fbuff, DSP_SAMPLE_DESC, sizeof(DSP_SAMPLE_DESC)); + ddesc = fbuff; + AddLog(LOG_LEVEL_INFO, PSTR("DSP: Flash descriptor used")); + } +#endif // DSP_ROM_DESC + + if (!ddesc) { + AddLog(LOG_LEVEL_INFO, PSTR("DSP: No valid descriptor found")); + if (fbuff) free(fbuff); + return; + } + // now replace tasmota vars before passing to driver + char *cp = strstr(ddesc, "I2C"); + if (cp) { + cp += 4; + //,3c,22,21,-1 + // i2c addr + //if (*cp == '*') { + // Settings.display_address + //} + uint8_t i2caddr = strtol(cp, 0, 16); + if (I2cSetDevice(i2caddr)) { + I2cSetActiveFound(i2caddr, "DSP-I2C"); + } + cp+=3; + //replacepin(&cp, Settings.display_address); + replacepin(&cp, Pin(GPIO_I2C_SCL)); + replacepin(&cp, Pin(GPIO_I2C_SDA)); + replacepin(&cp, Pin(GPIO_OLED_RESET)); + } + + cp = strstr(ddesc, "SPI"); + if (cp) { + cp += 4; + //; 7 params nr,cs,sclk,mosi,dc,bl,reset,miso + //SPI,*,*,*,*,*,*,* + if (*cp == '1') { + cp+=2; + replacepin(&cp, Pin(GPIO_SPI_CS)); + replacepin(&cp, Pin(GPIO_SPI_CLK)); + replacepin(&cp, Pin(GPIO_SPI_MOSI)); + replacepin(&cp, Pin(GPIO_SPI_DC)); + replacepin(&cp, Pin(GPIO_BACKLIGHT)); + replacepin(&cp, Pin(GPIO_OLED_RESET)); + replacepin(&cp, Pin(GPIO_SPI_MISO)); + } else { + // soft spi pins + cp+=2; + replacepin(&cp, Pin(GPIO_SSPI_CS)); + replacepin(&cp, Pin(GPIO_SSPI_SCLK)); + replacepin(&cp, Pin(GPIO_SSPI_MOSI)); + replacepin(&cp, Pin(GPIO_SSPI_DC)); + replacepin(&cp, Pin(GPIO_BACKLIGHT)); + replacepin(&cp, Pin(GPIO_OLED_RESET)); + replacepin(&cp, Pin(GPIO_SSPI_MISO)); + } + } + + // init renderer + if (udisp) delete udisp; + udisp = new uDisplay(ddesc); + +/* + File fp; + fp = ufsp->open("/dump.txt", "w"); + fp.write(ddesc, DISPDESC_SIZE); + fp.close(); +*/ + // release desc buffer + if (fbuff) free(fbuff); + + renderer = udisp->Init(); + if (!renderer) return; + + Settings.display_width = renderer->width(); + Settings.display_height = renderer->height(); + fg_color = udisp->fgcol(); + bg_color = udisp->bgcol(); + + renderer->DisplayInit(DISPLAY_INIT_MODE, Settings.display_size, Settings.display_rotate, Settings.display_font); + + +#ifdef SHOW_SPLASH + udisp->Splash(); +#endif + + udisp_init_done = true; + AddLog(LOG_LEVEL_INFO, PSTR("DSP: %s!"), udisp->devname()); + } +} + + +/*********************************************************************************************/ + +void replacepin(char **cp, uint16_t pin) { + char *lp = *cp; + if (*lp == ',') lp++; + if (*lp == '*') { + char val[8]; + itoa(pin, val, 10); + uint16_t slen = strlen(val); + //AddLog(LOG_LEVEL_INFO, PSTR("replace pin: %d"), pin); + memmove(lp + slen, lp + 1, strlen(lp)); + memmove(lp, val, slen); + } + char *np = strchr(lp, ','); + if (np) { + *cp = np + 1; + } +} + +#ifdef USE_DISPLAY_MODES1TO5 + +void UDISP_PrintLog(void) +{ + disp_refresh--; + if (!disp_refresh) { + disp_refresh = Settings.display_refresh; + if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); } + + char* txt = DisplayLogBuffer('\370'); + if (txt != NULL) { + uint8_t last_row = Settings.display_rows -1; + + renderer->clearDisplay(); + renderer->setTextSize(Settings.display_size); + renderer->setCursor(0,0); + for (byte i = 0; i < last_row; i++) { + strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols); + renderer->println(disp_screen_buffer[i]); + } + strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols); + DisplayFillScreen(last_row); + + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]); + + renderer->println(disp_screen_buffer[last_row]); + renderer->Updateframe(); + } + } +} + +void UDISP_Time(void) +{ + char line[12]; + + renderer->clearDisplay(); + renderer->setTextSize(Settings.display_size); + renderer->setTextFont(Settings.display_font); + renderer->setCursor(0, 0); + snprintf_P(line, sizeof(line), PSTR(" %02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); // [ 12:34:56 ] + renderer->println(line); + renderer->println(); + snprintf_P(line, sizeof(line), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year); // [01-02-2018] + renderer->println(line); + renderer->Updateframe(); +} + +void UDISP_Refresh(void) // Every second +{ + if (!renderer) return; + if (Settings.display_mode) { // Mode 0 is User text + switch (Settings.display_mode) { + case 1: // Time + UDISP_Time(); + break; + case 2: // Local + case 3: // Local + case 4: // Mqtt + case 5: // Mqtt + UDISP_PrintLog(); + break; + } + } +} + +#endif // USE_DISPLAY_MODES1TO5 + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdsp17(uint8_t function) +{ + bool result = false; + + if (FUNC_DISPLAY_INIT_DRIVER == function) { + Init_uDisp(); + } + else if (udisp_init_done && (XDSP_17 == Settings.display_model)) { + switch (function) { + case FUNC_DISPLAY_MODEL: + result = true; + break; +#ifdef USE_DISPLAY_MODES1TO5 + case FUNC_DISPLAY_EVERY_SECOND: + UDISP_Refresh(); + break; +#endif // USE_DISPLAY_MODES1TO5 + } + } + return result; +} + +#endif // USE_UNIVERSAL_DISPLAY +#endif // USE_DISPLAY diff --git a/tasmota/xnrg_01_hlw8012.ino b/tasmota/xnrg_01_hlw8012.ino index 0c8ac6a20..770ebed3b 100644 --- a/tasmota/xnrg_01_hlw8012.ino +++ b/tasmota/xnrg_01_hlw8012.ino @@ -280,7 +280,8 @@ void HlwDrvInit(void) Energy.current_available = false; Energy.voltage_available = false; } - + Energy.use_overtemp = true; // Use global temperature for overtemp detection + TasmotaGlobal.energy_driver = XNRG_01; } } diff --git a/tasmota/xnrg_02_cse7766.ino b/tasmota/xnrg_02_cse7766.ino index 24c7fcc09..e925d9b6b 100644 --- a/tasmota/xnrg_02_cse7766.ino +++ b/tasmota/xnrg_02_cse7766.ino @@ -221,7 +221,7 @@ void CseSnsInit(void) { // Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions // CseSerial = new TasmotaSerial(Pin(GPIO_CSE7766_RX), Pin(GPIO_CSE7766_TX), 1); CseSerial = new TasmotaSerial(Pin(GPIO_CSE7766_RX), -1, 1); - if (CseSerial->begin(4800, 2)) { // Fake Software Serial 8E1 by using two stop bits + if (CseSerial->begin(4800, SERIAL_8E1)) { if (CseSerial->hardwareSerial()) { SetSerial(4800, TS_SERIAL_8E1); ClaimSerial(); @@ -230,6 +230,7 @@ void CseSnsInit(void) { Settings.param[P_CSE7766_INVALID_POWER] = CSE_MAX_INVALID_POWER; // SetOption39 1..255 } Cse.power_invalid = Settings.param[P_CSE7766_INVALID_POWER]; + Energy.use_overtemp = true; // Use global temperature for overtemp detection } else { TasmotaGlobal.energy_driver = ENERGY_NONE; } diff --git a/tasmota/xnrg_04_mcp39f501.ino b/tasmota/xnrg_04_mcp39f501.ino index d71402dfa..395f66852 100644 --- a/tasmota/xnrg_04_mcp39f501.ino +++ b/tasmota/xnrg_04_mcp39f501.ino @@ -573,6 +573,7 @@ void McpSnsInit(void) mcp_buffer = (char*)(malloc(MCP_BUFFER_SIZE)); } DigitalWrite(GPIO_MCP39F5_RST, 0, 1); // MCP enable + Energy.use_overtemp = true; // Use global temperature for overtemp detection } else { TasmotaGlobal.energy_driver = ENERGY_NONE; } diff --git a/tasmota/xnrg_07_ade7953.ino b/tasmota/xnrg_07_ade7953.ino index f2c5802a2..5da3ec952 100644 --- a/tasmota/xnrg_07_ade7953.ino +++ b/tasmota/xnrg_07_ade7953.ino @@ -215,6 +215,7 @@ void Ade7953DrvInit(void) Energy.phase_count = 2; // Handle two channels as two phases Energy.voltage_common = true; // Use common voltage Energy.frequency_common = true; // Use common frequency + Energy.use_overtemp = true; // Use global temperature for overtemp detection TasmotaGlobal.energy_driver = XNRG_07; } } diff --git a/tasmota/xnrg_14_bl0940.ino b/tasmota/xnrg_14_bl0940.ino index 81a9d4791..00a69c323 100644 --- a/tasmota/xnrg_14_bl0940.ino +++ b/tasmota/xnrg_14_bl0940.ino @@ -219,6 +219,7 @@ void Bl0940SnsInit(void) { Settings.energy_current_calibration = BL0940_IREF; Settings.energy_power_calibration = BL0940_PREF; } + Energy.use_overtemp = true; // Use global temperature for overtemp detection for (uint32_t i = 0; i < 5; i++) { for (uint32_t j = 0; j < 6; j++) { diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino index c1e0fc9d9..75ff81cef 100755 --- a/tasmota/xnrg_15_teleinfo.ino +++ b/tasmota/xnrg_15_teleinfo.ino @@ -38,6 +38,27 @@ #define TINFO_READ_TIMEOUT 400 +#define D_NAME_TELEINFO "Teleinfo" + +// Json Command +//const char S_JSON_TELEINFO_COMMAND_STRING[] PROGMEM = "{\"" D_NAME_TELEINFO "\":{\"%s\":%s}}"; +//const char S_JSON_TELEINFO_COMMAND_NVALUE[] PROGMEM = "{\"" D_NAME_TELEINFO "\":{\"%s\":%d}}"; +const char TELEINFO_COMMAND_SETTINGS[] PROGMEM = "TIC: Settings Mode:%s, Raw:%s, Skip:%d, Limit:%d"; + +#define MAX_TINFO_COMMAND_NAME 16+1 // Change this if one of the following kTInfo_Commands is higher then 16 char +const char kTInfo_Commands[] PROGMEM = "historique|standard|noraw|full|changed|skip|limit"; + +enum TInfoCommands { // commands for Console + CMND_TELEINFO_HISTORIQUE=0, // Set Legacy mode + CMND_TELEINFO_STANDARD, // Set Standard Mode + CMND_TELEINFO_RAW_DISABLE, // Disable Raw frame sending + CMND_TELEINFO_RAW_FULL, // Enable all RAW frame send + CMND_TELEINFO_RAW_CHANGE, // Enable only changed values RAW frame send + CMND_TELEINFO_SKIP, // Set number of frame to skip when raw mode is enabled + CMND_TELEINFO_LIMIT // Limit RAW frame to values subject to fast change (Power, Current, ...), TBD +}; + + // All contract type for legacy, standard mode has in clear text enum TInfoContrat{ CONTRAT_BAS = 1, // BASE => Option Base. @@ -126,6 +147,7 @@ bool tinfo_found = false; int contrat; int tarif; int isousc; +int raw_skip; /*********************************************************************************************/ @@ -366,15 +388,17 @@ void DataCallback(struct _ValueList * me, uint8_t flags) Function: responseDumpTInfo Purpose : add teleinfo values into JSON response Input : 1st separator space if begining of JSON, else comma -Output : - + : select if append all data or just changed one +Output : false if asked for changed value and none has changed else true Comments: - ====================================================================== */ -void ResponseAppendTInfo(char sep) +bool ResponseAppendTInfo(char sep, bool all) { struct _ValueList * me = tinfo.getList(); char * p ; - boolean isNumber ; + bool isNumber ; + bool hasValue = false; // Loop thru all the teleinfo frame but // always check we don't buffer overflow of MQTT data @@ -383,34 +407,41 @@ void ResponseAppendTInfo(char sep) me = me->next; if (me->name && me->value && *me->name && *me->value) { - isNumber = true; - p = me->value; - // Specific treatment serial number don't convert to number later - if (strcmp(me->name, "ADCO")==0 || strcmp(me->name, "ADSC")==0) { - isNumber = false; - } else { - // check if value is number - while (*p && isNumber) { - if ( *p < '0' || *p > '9' ) { - isNumber = false; + // Add values only if we want all data or if data has changed + if (all || ( Settings.teleinfo.raw_report_changed && (me->flags & (TINFO_FLAGS_UPDATED | TINFO_FLAGS_ADDED | TINFO_FLAGS_ALERT) ) ) ) { + + isNumber = true; + hasValue = true; + p = me->value; + + // Specific treatment serial number don't convert to number later + if (strcmp(me->name, "ADCO")==0 || strcmp(me->name, "ADSC")==0) { + isNumber = false; + } else { + // check if value is number + while (*p && isNumber) { + if ( *p < '0' || *p > '9' ) { + isNumber = false; + } + p++; } - p++; } + + ResponseAppend_P( PSTR("%c\"%s\":"), sep, me->name ); + + if (!isNumber) { + ResponseAppend_P( PSTR("\"%s\""), me->value ); + } else { + ResponseAppend_P( PSTR("%d"), atoi(me->value)); + } + + // Now JSON separator is needed + sep =','; } - - ResponseAppend_P( PSTR("%c\"%s\":"), sep, me->name ); - - if (!isNumber) { - ResponseAppend_P( PSTR("\"%s\""), me->value ); - } else { - ResponseAppend_P( PSTR("%d"), atoi(me->value)); - } - - // Now JSON separator is needed - sep =','; } } + return hasValue; } /* ====================================================================== @@ -425,15 +456,29 @@ void NewFrameCallback(struct _ValueList * me) // Reset Energy Watchdog Energy.data_valid[0] = 0; - // send teleinfo full frame only if setup like that - // see setOption108 - if (Settings.flag4.teleinfo_rawdata) { - Response_P(PSTR("{")); - ResponseAppendTInfo(' '); - ResponseJsonEnd(); - // Publish adding ADCO serial number into the topic - // Need setOption4 to be enabled - MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, serialNumber, false); + // Deprecated see setOption108 + // send teleinfo raw data only if setup like that + if (Settings.teleinfo.raw_send) { + // Do we need to skip this frame + if (raw_skip == 0 ) { + Response_P(PSTR("{")); + // send teleinfo full frame or only changed data + bool hasData = ResponseAppendTInfo(' ', Settings.teleinfo.raw_report_changed ? false : true ); + ResponseJsonEnd(); + + // Publish adding ADCO serial number into the topic + // Need setOption4 to be enabled + // No need to send empty payload + if (hasData) { + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, serialNumber, false); + } + + // Reset frame skip counter (if 0 it's disabled) + raw_skip = Settings.teleinfo.raw_skip; + } else { + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: not sending yet, will do in %d frame(s)"), raw_skip); + raw_skip--; + } } } @@ -463,9 +508,9 @@ void TInfoInit(void) int baudrate; int serial_buffer_size; - - // SetOption102 - Set Baud rate for Teleinfo serial communication (0 = 1200 or 1 = 9600) - if (Settings.flag4.teleinfo_baudrate) { + // Deprecated SetOption102 - Set Baud rate for Teleinfo serial communication (0 = 1200 or 1 = 9600) + // now set in bit field TeleinfoCfg + if (Settings.teleinfo.mode_standard) { baudrate = 9600; tinfo_mode = TINFO_MODE_STANDARD; serial_buffer_size = TELEINFO_SERIAL_BUFFER_STANDARD; @@ -475,6 +520,7 @@ void TInfoInit(void) serial_buffer_size = TELEINFO_SERIAL_BUFFER_HISTORIQUE; } + if (PinUsed(GPIO_TELEINFO_RX)) { int8_t rx_pin = Pin(GPIO_TELEINFO_RX); AddLog(LOG_LEVEL_INFO, PSTR("TIC: RX on GPIO%d, baudrate %d"), rx_pin, baudrate); @@ -533,11 +579,180 @@ void TInfoInit(void) tinfo.attachNewFrame(NewFrameCallback); tinfo_found = true; + if (Settings.teleinfo.raw_send) { + raw_skip = Settings.teleinfo.raw_skip; + AddLog(LOG_LEVEL_INFO, PSTR("TIC: Raw mode enabled")); + if (raw_skip) { + AddLog(LOG_LEVEL_INFO, PSTR("TIC: Sending only one frame over %d "), raw_skip+1); + } + } AddLog(LOG_LEVEL_INFO, PSTR("TIC: Ready")); } } } + +/* ====================================================================== +Function: TInfoCmd +Purpose : Tasmota core command engine for Teleinfo commands +Input : - +Output : - +Comments: - +====================================================================== */ +bool TInfoCmd(void) { + bool serviced = false; + char command[CMDSZ]; + //uint8_t name_len = strlen(D_NAME_TELEINFO); + + // At least "EnergyConfig" + if (CMND_ENERGYCONFIG == Energy.command_code) { + + AddLog_P(LOG_LEVEL_DEBUG, PSTR("TIC: len %d, data '%s'"), XdrvMailbox.data_len, XdrvMailbox.data ? XdrvMailbox.data : "null" ); + + // Just "EnergyConfig" no more parameter + // Show Teleinfo configuration + if (XdrvMailbox.data_len == 0) { + + char mode_name[MAX_TINFO_COMMAND_NAME]; + char raw_name[MAX_TINFO_COMMAND_NAME]; + int index_mode = Settings.teleinfo.mode_standard ? CMND_TELEINFO_STANDARD : CMND_TELEINFO_HISTORIQUE; + int index_raw = Settings.teleinfo.raw_send ? CMND_TELEINFO_RAW_FULL : CMND_TELEINFO_RAW_DISABLE; + if (Settings.teleinfo.raw_send && Settings.teleinfo.raw_report_changed) { + index_raw = CMND_TELEINFO_RAW_CHANGE; + } + // Get the mode and raw name + GetTextIndexed(mode_name, MAX_TINFO_COMMAND_NAME, index_mode, kTInfo_Commands); + GetTextIndexed(raw_name, MAX_TINFO_COMMAND_NAME, index_raw, kTInfo_Commands); + + AddLog_P(LOG_LEVEL_INFO, TELEINFO_COMMAND_SETTINGS, mode_name, raw_name, Settings.teleinfo.raw_skip, Settings.teleinfo.raw_limit); + + serviced = true; + + // At least "EnergyConfig xyz" plus one space and one (or more) char + // so "EnergyConfig 0" or "EnergyConfig Teleinfo Standard" + } else if (XdrvMailbox.data_len) { + // Now point on parameter + char *pParam = XdrvMailbox.data; + char *p = pParam; + char *pValue = nullptr; + // Check for sub parameter ie : EnergyConfig Teleinfo Skip value + while(*p) { + if (*p == ' ') { + if (*(p+1)) { + // Skip parameter by emptying th string so below getcommandcode works + *p++ = 0x00; + // Save parameter value for later + pValue = p; + } + break; + } + p++; + } + + int command_code = GetCommandCode(command, sizeof(command), pParam, kTInfo_Commands); + + AddLog_P(LOG_LEVEL_DEBUG, PSTR("TIC: param '%s' cmnd %d"), pParam, command_code); + + switch (command_code) { + case CMND_TELEINFO_STANDARD: + case CMND_TELEINFO_HISTORIQUE: { + char mode_name[MAX_TINFO_COMMAND_NAME]; + + // Get the mode name + GetTextIndexed(mode_name, MAX_TINFO_COMMAND_NAME, command_code, kTInfo_Commands); + + // Only if current settings is different than previous + if ( (tinfo_mode==TINFO_MODE_STANDARD && command_code==CMND_TELEINFO_HISTORIQUE) || + (tinfo_mode==TINFO_MODE_HISTORIQUE && command_code==CMND_TELEINFO_STANDARD) ) { + + // Cleanup Serial not sure it will works since + // there is no end() or close() on tasmotaserial class + if (TInfoSerial) { + TInfoSerial->flush(); + //TInfoSerial->end(); + free(TInfoSerial); + } + + // Change mode + Settings.teleinfo.mode_standard = command_code == CMND_TELEINFO_STANDARD ? 1 : 0; + + AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: '%s' mode"), mode_name); + + // Re init teleinfo (LibTeleinfo always free linked list on init) + TInfoInit(); + + serviced = true; + + } else { + AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: No change to '%s' mode"), mode_name); + } + } + break; + + case CMND_TELEINFO_RAW_DISABLE: + case CMND_TELEINFO_RAW_FULL: + case CMND_TELEINFO_RAW_CHANGE: { + + // Enable all RAW frame send + char raw_name[MAX_TINFO_COMMAND_NAME]; + + // Get the raw name + GetTextIndexed(raw_name, MAX_TINFO_COMMAND_NAME, command_code, kTInfo_Commands); + + if (command_code == CMND_TELEINFO_RAW_DISABLE) { + // disable raw mode + Settings.teleinfo.raw_send = 0; + } else { + // enable raw mode + Settings.teleinfo.raw_send = 1; + Settings.teleinfo.raw_report_changed = command_code == CMND_TELEINFO_RAW_CHANGE ? 1 : 0; + } + + AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: Raw to '%s'"), raw_name); + serviced = true; + } + break; + + case CMND_TELEINFO_SKIP: { + // Set Raw mode skip frame number + char skip_name[MAX_TINFO_COMMAND_NAME]; + // Get the raw name + GetTextIndexed(skip_name, MAX_TINFO_COMMAND_NAME, command_code, kTInfo_Commands); + int l = strlen(skip_name); + + // At least "EnergyConfig Teleinfo skip" plus one space and one (or more) digit + // so "EnergyConfig Skip 0" or "EnergyConfig Skip 123" + if ( pValue ) { + int value = atoi(pValue); + if (value >= 0 && value <= 255) { + raw_skip = value; + Settings.teleinfo.raw_skip = raw_skip; + + if (raw_skip ==0) { + AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: Raw no skip")); + } else { + AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: Raw each %d frame(s)"), raw_skip+1); + } + serviced = true; + } else { + AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: skip can be 0 to 255")); + } + } else { + AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: no skip value")); + } + } + break; + + default: + AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: bad cmd param '%s'"), pParam); + break; + + } + } + } + return serviced ; +} + /* ====================================================================== Function: TInfoProcess Purpose : Tasmota callback executed often enough to read serial @@ -614,7 +829,7 @@ void TInfoShow(bool json) } // add teleinfo full frame - ResponseAppendTInfo(','); + ResponseAppendTInfo(',', true); #ifdef USE_WEBSERVER } @@ -696,11 +911,16 @@ void TInfoShow(bool json) \*********************************************************************************************/ bool Xnrg15(uint8_t function) { + bool result = false; switch (function) { case FUNC_EVERY_250_MSECOND: TInfoProcess(); break; + case FUNC_COMMAND: + result = TInfoCmd(); + break; + case FUNC_JSON_APPEND: TInfoShow(1); break; @@ -716,7 +936,7 @@ bool Xnrg15(uint8_t function) TInfoDrvInit(); break; } - return false; + return result; } #endif // USE_TELEINFO diff --git a/tasmota/xnrg_19_cse7761.ino b/tasmota/xnrg_19_cse7761.ino index a644c48f4..478d5db62 100644 --- a/tasmota/xnrg_19_cse7761.ino +++ b/tasmota/xnrg_19_cse7761.ino @@ -600,6 +600,7 @@ void Cse7761DrvInit(void) { #ifdef CSE7761_FREQUENCY Energy.frequency_common = true; // Use common frequency #endif + Energy.use_overtemp = true; // Use global temperature for overtemp detection TasmotaGlobal.energy_driver = XNRG_19; } } diff --git a/tasmota/xnrg_20_dummy.ino b/tasmota/xnrg_20_dummy.ino index 07b4a22ec..f1bac903b 100644 --- a/tasmota/xnrg_20_dummy.ino +++ b/tasmota/xnrg_20_dummy.ino @@ -33,6 +33,7 @@ #define NRG_DUMMY_U_COMMON true // Phase voltage = false, Common voltage = true #define NRG_DUMMY_F_COMMON true // Phase frequency = false, Common frequency = true #define NRG_DUMMY_DC false // AC = false, DC = true; +#define NRG_DUMMY_OVERTEMP true // Use global temperature for overtemp detection #define NRG_DUMMY_UREF 24000 // Voltage 240.00 V (= P / I) #define NRG_DUMMY_IREF 41666 // Current 0.417 A (= P / U) @@ -99,6 +100,10 @@ bool NrgDummyCommand(void) { } } } + else if (CMND_ENERGYCONFIG == Energy.command_code) { + AddLog_P(LOG_LEVEL_DEBUG, PSTR("NRG: Config index %d, payload %d, data '%s'"), + XdrvMailbox.index, XdrvMailbox.payload, XdrvMailbox.data ? XdrvMailbox.data : "null" ); + } else serviced = false; // Unknown command return serviced; @@ -117,6 +122,7 @@ void NrgDummyDrvInit(void) { Energy.voltage_common = NRG_DUMMY_U_COMMON; // Phase voltage = false, Common voltage = true Energy.frequency_common = NRG_DUMMY_F_COMMON; // Phase frequency = false, Common frequency = true Energy.type_dc = NRG_DUMMY_DC; // AC = false, DC = true; + Energy.use_overtemp = NRG_DUMMY_OVERTEMP; // Use global temperature for overtemp detection TasmotaGlobal.energy_driver = XNRG_20; } diff --git a/tasmota/xsns_52_esp32_ibeacon_ble.ino b/tasmota/xsns_52_esp32_ibeacon_ble.ino index 432455924..b18cbcc99 100644 --- a/tasmota/xsns_52_esp32_ibeacon_ble.ino +++ b/tasmota/xsns_52_esp32_ibeacon_ble.ino @@ -42,6 +42,11 @@ // IBEACON.PERSEC - count of adverts per sec. USeful for detecting button press? // IBEACON.MAJOR - some iBeacon related term? - only present for some // IBEACON.MINOR - some iBeacon related term? - only present for some +// +// Note for Apple iBeacons with UUID,MAJOR,MINOR: +// iBeacons are compared using UUID+MAJOR+MINOR as the unique id rather than MAC address. +// so each of your beacons should have unique MAJOR+MINOR. +// it would be 'normal' for UUID to be identical for a set of iBeacons. //////////////////////////////////////// @@ -89,9 +94,13 @@ struct IBEACON { struct IBEACON_UID { char MAC[12]; char RSSI[4]; + ////////////////////////////// + // DON'T CHANGE THE ORDER HERE + // we reference these as a single field in comparing for 'same' beacon char UID[32]; char MAJOR[4]; char MINOR[4]; + ////////////////////////////// uint8_t FLAGS; uint8_t TIME; uint8_t REPORTED; @@ -233,8 +242,10 @@ int advertismentCallback(BLE_ESP32::ble_advertisment_t *pStruct) memcpy(UUID,oBeacon.getProximityUUID().getNative()->u128.value,16); ESP32BLE_ReverseStr(UUID,16); - uint16_t Major = ENDIAN_CHANGE_U16(oBeacon.getMajor()); - uint16_t Minor = ENDIAN_CHANGE_U16(oBeacon.getMinor()); +// uint16_t Major = ENDIAN_CHANGE_U16(oBeacon.getMajor()); +// uint16_t Minor = ENDIAN_CHANGE_U16(oBeacon.getMinor()); + uint16_t Major = oBeacon.getMajor(); + uint16_t Minor = oBeacon.getMinor(); uint8_t PWR = oBeacon.getSignalPower(); DumpHex((const unsigned char*)&UUID,16,ib.UID); @@ -340,7 +351,7 @@ uint32_t ibeacon_add(struct IBEACON *ib) { if (!strncmp_P(ib->UID,PSTR("00000000000000000000000000000000"),32)) { if (!strncmp(ibeacons[cnt].MAC,ib->MAC,12)) { // exists - strncpy(ibeacons[cnt].NAME,ib->NAME,sizeof(ibeacons[cnt].NAME)); + memcpy(ibeacons[cnt].NAME,ib->NAME,sizeof(ibeacons[cnt].NAME)); memcpy(ibeacons[cnt].RSSI,ib->RSSI,4); ibeacons[cnt].TIME=0; if (ibeacons[cnt].REPTIME >= IB_UPDATE_TIME) { @@ -351,9 +362,14 @@ uint32_t ibeacon_add(struct IBEACON *ib) { return 2; } } else { - if (!strncmp(ibeacons[cnt].UID,ib->UID,32)) { + // iBeacons from a phone can change thier MAC frequently. + // but it is intended that UUID+MAJOR+MINOR are unique. + // so if we find the SAME UUID+MAJOR+MINOR, then update the MAC and assume the same device. + // NOT: THIS RELIES ON THE STRUCTURE ORDER + if (!strncmp(ibeacons[cnt].UID,ib->UID,sizeof(ib->UID)+sizeof(ib->MAJOR)+sizeof(ib->MINOR))) { // exists - strncpy(ibeacons[cnt].NAME,ib->NAME,sizeof(ibeacons[cnt].NAME)); + memcpy(ibeacons[cnt].NAME,ib->NAME,sizeof(ibeacons[cnt].NAME)); + memcpy(ibeacons[cnt].MAC,ib->MAC,12); memcpy(ibeacons[cnt].RSSI,ib->RSSI,4); ibeacons[cnt].TIME=0; if (ibeacons[cnt].REPTIME >= IB_UPDATE_TIME) { @@ -368,7 +384,7 @@ uint32_t ibeacon_add(struct IBEACON *ib) { } for (uint32_t cnt=0;cntNAME,sizeof(ibeacons[cnt].NAME)); + memcpy(ibeacons[cnt].NAME,ib->NAME,sizeof(ibeacons[cnt].NAME)); memcpy(ibeacons[cnt].MAC,ib->MAC,12); memcpy(ibeacons[cnt].RSSI,ib->RSSI,4); memcpy(ibeacons[cnt].UID,ib->UID,32); @@ -376,7 +392,6 @@ uint32_t ibeacon_add(struct IBEACON *ib) { memcpy(ibeacons[cnt].MINOR,ib->MINOR,4); ibeacons[cnt].FLAGS=1; ibeacons[cnt].TIME=0; - memcpy(ibeacons[cnt].NAME,ib->NAME,16); ibeacons[cnt].REPTIME = 0; ibeacons[cnt].REPORTED = 0; ibeacons[cnt].count = 0; @@ -414,13 +429,15 @@ const char HTTP_IBEACON_HL[] PROGMEM = "{s}
{m}
{e}"; const char HTTP_IBEACON_mac[] PROGMEM = "{s}IBEACON-MAC : %s" " {m} RSSI : %s" "{e}"; const char HTTP_IBEACON_uid[] PROGMEM = - "{s}IBEACON-UID : %s" " {m} RSSI : %s" "{e}"; + "{s}IBEACON-UID : %s:%s:%s" " {m} RSSI : %s" "{e}"; const char HTTP_IBEACON_name[] PROGMEM = "{s}IBEACON-NAME : %s (%s)" " {m} RSSI : %s" "{e}"; void IBEACON_Show(void) { char mac[14]; char rssi[6]; char uid[34]; + char major[6]; + char minor[6]; char name[18]; //TasAutoMutex localmutex(&beaconmutex, "iBeacShow"); int total = 0; @@ -434,6 +451,10 @@ void IBEACON_Show(void) { rssi[4]=0; memcpy(uid,ibeacons[cnt].UID,32); uid[32]=0; + memcpy(major,ibeacons[cnt].MAJOR,4); + major[4]=0; + memcpy(minor,ibeacons[cnt].MINOR,4); + minor[4]=0; memcpy(name,ibeacons[cnt].NAME,16); name[16]=0; if (!strncmp_P(uid,PSTR("00000000000000000000000000000000"),32)) { @@ -443,7 +464,7 @@ void IBEACON_Show(void) { WSContentSend_PD(HTTP_IBEACON_mac,mac,rssi); } } else { - WSContentSend_PD(HTTP_IBEACON_uid,uid,rssi); + WSContentSend_PD(HTTP_IBEACON_uid,uid,major,minor,rssi); } } } diff --git a/tasmota/xsns_87_esp32_halleffect.ino b/tasmota/xsns_87_esp32_sensors.ino similarity index 57% rename from tasmota/xsns_87_esp32_halleffect.ino rename to tasmota/xsns_87_esp32_sensors.ino index 07fdad4bb..c5fc80d52 100644 --- a/tasmota/xsns_87_esp32_halleffect.ino +++ b/tasmota/xsns_87_esp32_sensors.ino @@ -1,5 +1,5 @@ /* - xsns_87_esp32_halleffect.ino - ESP32 Hall Effect sensor for Tasmota + xsns_87_esp32_sensors.ino - ESP32 Temperature and Hall Effect sensor for Tasmota Copyright (C) 2021 Theo Arends @@ -18,11 +18,10 @@ */ #ifdef ESP32 -#if CONFIG_IDF_TARGET_ESP32 -#ifdef USE_HALLEFFECT /*********************************************************************************************\ - * ESP32 internal Hall Effect sensor connected to both GPIO36 and GPIO39 + * ESP32 CPU Temperature and optional Hall Effect sensor * + * ESP32 internal Hall Effect sensor connected to both GPIO36 and GPIO39 * To enable set * GPIO36 as HallEffect 1 * GPIO39 as HallEffect 2 @@ -30,13 +29,15 @@ #define XSNS_87 87 +#if CONFIG_IDF_TARGET_ESP32 + #define HALLEFFECT_SAMPLE_COUNT 32 // 32 takes about 12 mS at 80MHz CPU frequency struct { bool present = false; } HEData; -void HallEffectInit(void) { +void Esp32SensorInit(void) { if (PinUsed(GPIO_HALLEFFECT) && PinUsed(GPIO_HALLEFFECT, 1)) { if (((36 == Pin(GPIO_HALLEFFECT)) && (39 == Pin(GPIO_HALLEFFECT, 1))) || ((39 == Pin(GPIO_HALLEFFECT)) && (36 == Pin(GPIO_HALLEFFECT, 1)))) { @@ -46,27 +47,56 @@ void HallEffectInit(void) { } } -#ifdef USE_WEBSERVER -// {s} =
-const char HTTP_SNS_HALL_EFFECT[] PROGMEM = "{s}" D_HALL_EFFECT "{m}%d{e}"; -#endif // USE_WEBSERVER +#endif // CONFIG_IDF_TARGET_ESP32 -void HallEffectShow(bool json) { +void Esp32SensorShow(bool json) { + float t = CpuTemperature(); + +#if CONFIG_IDF_TARGET_ESP32 int value = 0; - for (uint32_t i = 0; i < HALLEFFECT_SAMPLE_COUNT; i++) { - value += hallRead(); + if (HEData.present) { + for (uint32_t i = 0; i < HALLEFFECT_SAMPLE_COUNT; i++) { + value += hallRead(); + } + value /= HALLEFFECT_SAMPLE_COUNT; } - value /= HALLEFFECT_SAMPLE_COUNT; +#endif // CONFIG_IDF_TARGET_ESP32 + if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_HALLEFFECT "\":%d"), value); + bool temperature_present = (strstr_P(TasmotaGlobal.mqtt_data, PSTR(D_JSON_TEMPERATURE)) != nullptr); + ResponseAppend_P(PSTR(",\"ESP32\":{\"" D_JSON_TEMPERATURE "\":%*_f"), Settings.flag2.temperature_resolution, &t); + +#if CONFIG_IDF_TARGET_ESP32 + if (HEData.present) { + ResponseAppend_P(PSTR(",\"" D_JSON_HALLEFFECT "\":%d"), value); + } +#endif // CONFIG_IDF_TARGET_ESP32 + + ResponseJsonEnd(); #ifdef USE_DOMOTICZ if (0 == TasmotaGlobal.tele_period) { - DomoticzSensor(DZ_COUNT, value); + if (!temperature_present) { // Only send if no other sensor already did + DomoticzFloatSensor(DZ_TEMP, t); + } + +#if CONFIG_IDF_TARGET_ESP32 + if (HEData.present) { + DomoticzSensor(DZ_COUNT, value); + } +#endif // CONFIG_IDF_TARGET_ESP32 + } #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { - WSContentSend_P(HTTP_SNS_HALL_EFFECT, value); + WSContentSend_Temp("ESP32", t); + +#if CONFIG_IDF_TARGET_ESP32 + if (HEData.present) { + WSContentSend_P(HTTP_SNS_HALL_EFFECT, "ESP32", value); + } +#endif // CONFIG_IDF_TARGET_ESP32 + #endif // USE_WEBSERVER } } @@ -78,24 +108,20 @@ void HallEffectShow(bool json) { bool Xsns87(uint8_t function) { bool result = false; - if (FUNC_INIT == function) { - HallEffectInit(); - } - else if (HEData.present) { - switch (function) { - case FUNC_JSON_APPEND: - HallEffectShow(1); - break; + switch (function) { + case FUNC_JSON_APPEND: + Esp32SensorShow(1); + break; #ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - HallEffectShow(0); - break; + case FUNC_WEB_SENSOR: + Esp32SensorShow(0); + break; #endif // USE_WEBSERVER - } + case FUNC_INIT: + Esp32SensorInit(); + break; } return result; } -#endif // USE_HALLEFFECT -#endif // CONFIG_IDF_TARGET_ESP32 #endif // ESP32
, {m} = , {e} =