Merge branch 'development' into pre-release-11.1

This commit is contained in:
Theo Arends 2022-04-12 12:14:38 +02:00
commit 6e2592fe02
36 changed files with 152 additions and 68 deletions

View File

@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file.
## [11.0.0.7] 20220413
### Added
- HX711 command ``Sensor34 10 0|1|<weight in gram>`` to set HX711 fixed tare (0 = use auto tare, 1 = use calibrated tare, Any other value is user selected tare)
- Command ``SetOption138 1`` to switch GUI energy multi-column layout from left/center (0) to right (1) align (#15342)
### Changed
- HX711 commands ``Sensor34 11 <valueA>`` and ``Sensor34 12 <valueB>`` to use HX711 absolute weight conversion (#15292)
@ -34,6 +35,7 @@ All notable changes to this project will be documented in this file.
- Support for improv as used by esp-web-tools
- Command ``IfxSensor 1`` to send non-teleperiod data to influxdb
- ESP32 Support for OpenHASP v1.0 by Stephan Hadinger (#15307)
- Command ``SetOption137 1`` to avoid MQTT publish of defined Tuya CMDs if SO66 is active (#15267)
### Changed
- Remove support for Internet Explorer by allowing ECMAScript6 syntax using less JavaScript code bytes (#15280)

View File

@ -107,6 +107,8 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo
### Added
- Command ``SetOption135 1`` to disable LVGL splash screen
- Command ``SetOption136 1`` to disable single sensor reports from Tuya devices while keeping teleperiod reports [#15216](https://github.com/arendst/Tasmota/issues/15216)
- Command ``SetOption137 1`` to avoid MQTT publish of defined Tuya CMDs if SO66 is active [#15267](https://github.com/arendst/Tasmota/issues/15267)
- Command ``SetOption138 1`` to switch GUI energy multi-column layout from left/center (0) to right (1) align [#15342](https://github.com/arendst/Tasmota/issues/15342)
- Command ``SspmMap 0`` to reset Sonoff SPM default mapping
- Command ``TcpConnect <port><ip_address>`` to add client connection mode [#14874](https://github.com/arendst/Tasmota/issues/14874)
- Command ``RfTimeout 100..60000`` to disable duplicate RfReceive. Default 1000 [#15061](https://github.com/arendst/Tasmota/issues/15061)
@ -132,6 +134,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo
- ESP32 TasmotaSerial uart mapping to support multiple ``begin()`` and implement ``getUart()`` [#14981](https://github.com/arendst/Tasmota/issues/14981)
### Breaking Changed
- Remove support for Internet Explorer by allowing ECMAScript6 syntax using less JavaScript code bytes [#15280](https://github.com/arendst/Tasmota/issues/15280)
### Changed
- Adafruit BusIO library from v1.0.10 to v1.11.0
@ -139,7 +142,6 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo
- Sonoff SPM increase max number of relays supported to 32 (8 SPM-4Relay modules)
- Extent number of pulsetimers from 8 to 32 [#8266](https://github.com/arendst/Tasmota/issues/8266)
- Consolidate three RTC chip drivers (DS3231, BM8563, PCF85363) into one driver updating RTC as soon as possible after restart
- Remove support for Internet Explorer by allowing ECMAScript6 syntax using less JavaScript code bytes [#15280](https://github.com/arendst/Tasmota/issues/15280)
- DS3231 I2C address define ``USE_RTC_ADDR`` into ``DS3231_ADDRESS``
- Display of energy values in GUI use columns when define ``USE_ENERGY_COLUMN_GUI`` is enabled (default)
- ESP8266 Shrinked tasmota-minimal.bin by removing all commands except ``Upgrade``, ``Upload``, ``OtaUrl``, ``Seriallog``, ``Weblog`` and ``Restart``

View File

@ -870,7 +870,7 @@ const char HTTP_SNS_DISTANCE_CM[] PROGMEM = "{s}%s " D_DISTANCE "{
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}";
const char HTTP_SNS_POWER[] PROGMEM = "{s}" D_POWERUSAGE_ACTIVE "{m}%s " D_UNIT_WATT "{e}";
const char HTTP_SNS_ENERGY_TOTAL[] PROGMEM = "{s}" D_ENERGY_TOTAL "{m}%s " D_UNIT_KILOWATTHOUR "{e}";
const char HTTP_SNS_PH[] PROGMEM = "{s}%s " D_PH "{m}%s " "{e}";
const char HTTP_SNS_MQ[] PROGMEM = "{s}" D_MQ"-%s" "{m}%s " D_UNIT_PARTS_PER_MILLION "{e}";

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -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 v10.1.0.6 - Last update 09.04.2022
* Updated until v11.0.0.7 - Last update 10.04.2022
\*********************************************************************/
#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -615,6 +615,7 @@
#define D_SENSOR_DHT11 "DHT11"
#define D_SENSOR_AM2301 "AM2301"
#define D_SENSOR_SI7021 "SI7021"
#define D_SENSOR_MS01 "MS01"
#define D_SENSOR_DS18X20 "DS18x20"
#define D_SENSOR_I2C_SCL "I2C SCL"
#define D_SENSOR_I2C_SDA "I2C SDA"

View File

@ -167,7 +167,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t display_no_splash : 1; // bit 21 (v11.0.0.2) - SetOption135 - (Display & LVGL) forece disbabling default splash screen
uint32_t tuyasns_no_immediate : 1; // bit 22 (v11.0.0.4) - SetOption136 - (TuyaSNS) When ON disable publish single SNS value on Tuya Receive (keep Teleperiod)
uint32_t tuya_exclude_from_mqtt : 1; // bit 23 (v11.0.0.5) - SetOption137 - (Tuya) When Set, avoid the (MQTT-) publish of defined Tuya CMDs (see xdrv_16_tuyamcu.ino) if SetOption66 is active
uint32_t spare24 : 1; // bit 24
uint32_t gui_table_align : 1; // bit 24 (v11.0.0.7) - SetOption138 - (GUI) Align (energy) table values left (0) or right (1)
uint32_t spare25 : 1; // bit 25
uint32_t spare26 : 1; // bit 26
uint32_t spare27 : 1; // bit 27

View File

@ -116,7 +116,18 @@ void WifiConfig(uint8_t type)
}
}
#ifdef CONFIG_IDF_TARGET_ESP32C3
// https://github.com/espressif/arduino-esp32/issues/6264#issuecomment-1040147331
// There's an include for this but it doesn't define the function if it doesn't think it needs it, so manually declare the function
extern "C" void phy_bbpll_en_usb(bool en);
#endif // CONFIG_IDF_TARGET_ESP32C3
void WifiSetMode(WiFiMode_t wifi_mode) {
#ifdef CONFIG_IDF_TARGET_ESP32C3
// https://github.com/espressif/arduino-esp32/issues/6264#issuecomment-1094376906
// This brings the USB serial-jtag back to life. Suggest doing this immediately after wifi startup.
phy_bbpll_en_usb(true);
#endif // CONFIG_IDF_TARGET_ESP32C3
if (WiFi.getMode() == wifi_mode) { return; }
if (wifi_mode != WIFI_OFF) {

View File

@ -185,6 +185,7 @@ enum UserSelectablePins {
GPIO_BL6523_TX, GPIO_BL6523_RX, // BL6523 based Watt meter Serial interface
GPIO_ADE7880_IRQ, // ADE7880 IRQ
GPIO_RESET, // Generic reset
GPIO_MS01, // Sonoff MS01 Moisture Sensor 1wire interface
GPIO_SENSOR_END };
enum ProgramSelectablePins {
@ -409,6 +410,7 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_BL6523_TX "|" D_SENSOR_BL6523_RX "|"
D_SENSOR_ADE7880_IRQ "|"
D_SENSOR_RESET "|"
D_SENSOR_MS01 "|"
;
const char kSensorNamesFixed[] PROGMEM =
@ -599,6 +601,7 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_DHT11), // DHT11
AGPIO(GPIO_DHT22), // DHT21, DHT22, AM2301, AM2302, AM2321
AGPIO(GPIO_SI7021), // iTead SI7021
AGPIO(GPIO_MS01), // Sonoff MS01
AGPIO(GPIO_DHT11_OUT), // Pseudo Single wire DHT11, DHT21, DHT22, AM2301, AM2302, AM2321
#endif
#ifdef USE_DS18x20

View File

@ -178,14 +178,24 @@ char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t
}
}
#ifdef USE_ENERGY_COLUMN_GUI
if ((Energy.phase_count > 1) && single) { // Need to set colspan so need a new column
ext_snprintf_P(result, TOPSZ, PSTR("</td><td colspan='%d' style='text-align:center;'>%*_f</td><td>"), Energy.phase_count, resolution, &input[0]);
ext_snprintf_P(result, TOPSZ *2, PSTR("</td>")); // Skip first column
if ((Energy.phase_count > 1) && single) { // Need to set colspan so need new columns
// </td><td colspan='3' style='text-align:right'>1.23</td><td>&nbsp;</td><td>
// </td><td colspan='5' style='text-align:right'>1.23</td><td>&nbsp;</td><td>
// </td><td colspan='7' style='text-align:right'>1.23</td><td>&nbsp;</td><td>
ext_snprintf_P(result, TOPSZ *2, PSTR("%s<td colspan='%d' style='text-align:%s'>%*_f</td><td>&nbsp;</td>"),
result, (Energy.phase_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[0]);
} else {
ext_snprintf_P(result, TOPSZ, PSTR("</td><td>")); // Skip first column
// </td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td>
// </td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td>
// </td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td>
// </td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td>
for (uint32_t i = 0; i < Energy.phase_count; i++) {
ext_snprintf_P(result, TOPSZ, PSTR("%s%*_f</td><td>"), result, resolution, &input[i]);
ext_snprintf_P(result, TOPSZ *2, PSTR("%s<td style='text-align:%s'>%*_f</td><td>&nbsp;</td>"),
result, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[i]);
}
}
ext_snprintf_P(result, TOPSZ *2, PSTR("%s<td>"), result);
#else // not USE_ENERGY_COLUMN_GUI
uint32_t index = (single) ? 1 : Energy.phase_count; // 1,2,3
result[0] = '\0';
@ -1111,9 +1121,9 @@ void EnergyShow(bool json) {
energy_tariff = true;
}
char value_chr[TOPSZ]; // Used by EnergyFormatIndex
char value2_chr[TOPSZ];
char value3_chr[TOPSZ];
char value_chr[TOPSZ * 2]; // Used by EnergyFormatIndex
char value2_chr[TOPSZ * 2];
char value3_chr[TOPSZ * 2];
if (json) {
bool show_energy_period = (0 == TasmotaGlobal.tele_period);
@ -1232,25 +1242,17 @@ void EnergyShow(bool json) {
#ifdef USE_WEBSERVER
} else {
#ifdef USE_ENERGY_COLUMN_GUI
// Need a new table supporting more columns
WSContentSend_P(PSTR("</table>{t}{s}</th><th>")); // First column is empty ({t} = <table style='width:100%'>, {s} = <tr><th>)
// Calculate nice inter-column spacing without using table spacing or column padding
uint32_t len = 6; // Minimum width is 60px
for (uint32_t i = 0; i < Energy.phase_count; i++) {
// Using active power expecting to be the largest number not counting increasing total energy
uint32_t len_new = ext_snprintf_P(value_chr, sizeof(value_chr), PSTR("%*_f"), Settings->flag2.wattage_resolution, &Energy.active_power[i]);
if (len_new > len) { len = len_new; }
// len_new = ext_snprintf_P(value_chr, sizeof(value_chr), PSTR("%*_f"), Settings->flag2.energy_resolution, &Energy.total[i]);
// if (len_new > len) { len = len_new; }
}
uint32_t width = len * 10; // Default 60px. Every additonal character adds 10px
// Need a new table supporting more columns using empty columns (with &nbsp; in data rows) as easy column spacing
// {s}</th><th></th><th>Head1</th><th></th><td>{e}
// {s}</th><th></th><th>Head1</th><th></th><th>Head2</th><th></th><td>{e}
// {s}</th><th></th><th>Head1</th><th></th><th>Head2</th><th></th><th>Head3</th><th></th><td>{e}
// {s}</th><th></th><th>Head1</th><th></th><th>Head2</th><th></th><th>Head3</th><th></th><th>Head4</th><th></th><td>{e}
WSContentSend_P(PSTR("</table><hr/>{t}{s}</th><th></th>")); // First column is empty ({t} = <table style='width:100%'>, {s} = <tr><th>)
bool no_label = Energy.voltage_common || (1 == Energy.phase_count);
for (uint32_t i = 0; i < Energy.phase_count; i++) {
WSContentSend_P(PSTR("</th><th style='width:%dpx;white-space:nowrap'>%s%s"), width, (no_label)?"":"L", (no_label)?"":itoa(i +1, value_chr, 10));
WSContentSend_P(PSTR("<th style='text-align:center'>%s%s<th></th>"), (no_label)?"":"L", (no_label)?"":itoa(i +1, value_chr, 10));
}
WSContentSend_P(PSTR("</th><td>{e}")); // Last column is units ({e} = </td></tr>)
WSContentSend_P(PSTR("<td>{e}")); // Last column is units ({e} = </td></tr>)
#endif // USE_ENERGY_COLUMN_GUI
if (Energy.voltage_available) {
WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy.voltage, Settings->flag2.voltage_resolution, Energy.voltage_common));
@ -1280,7 +1282,7 @@ void EnergyShow(bool json) {
}
#ifdef USE_ENERGY_COLUMN_GUI
XnrgCall(FUNC_WEB_COL_SENSOR);
WSContentSend_P(PSTR("</table>{t}")); // {t} = <table style='width:100%'> - Define for next FUNC_WEB_SENSOR
WSContentSend_P(PSTR("</table><hr/>{t}")); // {t} = <table style='width:100%'> - Define for next FUNC_WEB_SENSOR
#endif // USE_ENERGY_COLUMN_GUI
XnrgCall(FUNC_WEB_SENSOR);
#endif // USE_WEBSERVER

View File

@ -20,6 +20,7 @@
//#define USE_SONOFF_SPM
#ifdef ESP32
#ifdef USE_ENERGY_SENSOR
#ifdef USE_SONOFF_SPM
/*********************************************************************************************\
* Sonoff Stackable Power Manager
@ -1891,34 +1892,22 @@ bool SSPMButton(void) {
/*********************************************************************************************/
const uint16_t SSPM_SIZE = 128;
const uint16_t SSPM_SIZE = 300;
char* SSPMEnergyFormat(char* result, float* input, uint32_t resolution, uint8_t* indirect, uint8_t offset, uint32_t count) {
result[0] = '\0';
ext_snprintf_P(result, SSPM_SIZE, PSTR("</td>")); // Skip first column
// </td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td>
// </td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td>
// </td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td>
// </td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td style='text-align:right'>1.23</td><td>&nbsp;</td><td>
for (uint32_t i = 0; i < count; i++) {
ext_snprintf_P(result, SSPM_SIZE, PSTR("%s<td>%*_f</td>"), result, resolution, &input[indirect[offset +i]]);
ext_snprintf_P(result, SSPM_SIZE, PSTR("%s<td style='text-align:%s'>%*_f</td><td>&nbsp;</td>"),
result, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[indirect[offset +i]]);
}
ext_snprintf_P(result, SSPM_SIZE, PSTR("%s<td style='white-space:nowrap'>"), result);
ext_snprintf_P(result, SSPM_SIZE, PSTR("%s<td>"), result);
return result;
}
#ifdef USE_WEBSERVER
const char HTTP_SSPM_VOLTAGE[] PROGMEM =
"{s}" D_VOLTAGE "</th>%s" D_UNIT_VOLT "{e}"; // {s} = <tr><th>, {m} = </th><td style='width:20px;white-space:nowrap'>, {e} = </td></tr>
const char HTTP_SSPM_CURRENT[] PROGMEM =
"{s}" D_CURRENT "</th>%s" D_UNIT_AMPERE "{e}";
const char HTTP_SSPM_POWER[] PROGMEM =
"{s}" D_POWERUSAGE_ACTIVE "</th>%s" D_UNIT_WATT "{e}";
const char HTTP_SSPM_POWER2[] PROGMEM =
"{s}" D_POWERUSAGE_APPARENT "</th>%s" D_UNIT_VA "{e}"
"{s}" D_POWERUSAGE_REACTIVE "</th>%s" D_UNIT_VAR "{e}"
"{s}" D_POWER_FACTOR "</th>%s{e}";
const char HTTP_SSPM_ENERGY[] PROGMEM =
"{s}" D_ENERGY_TODAY "</th>%s" D_UNIT_KILOWATTHOUR "{e}"
"{s}" D_ENERGY_YESTERDAY "</th>%s" D_UNIT_KILOWATTHOUR "{e}"
"{s}" D_ENERGY_TOTAL "</th>%s" D_UNIT_KILOWATTHOUR "{e}";
#endif // USE_WEBSERVER
void SSPMEnergyShow(bool json) {
if (!TasmotaGlobal.devices_present) { return; } // Not ready yet
@ -1992,24 +1981,29 @@ void SSPMEnergyShow(bool json) {
uint32_t offset = (Sspm->rotate >> 2) * 4;
uint32_t count = index - offset;
if (count > 4) { count = 4; }
WSContentSend_P(PSTR("</table>{t}{s}")); // First column is empty ({t} = <table style='width:100%'>, {s} = <tr><th>)
for (uint32_t i = 0; i < count; i++) {
WSContentSend_P(PSTR("</th><th style='width:60px;white-space:nowrap'>L%d"), relay[offset +i]);
}
WSContentSend_P(PSTR("</th><td>{e}")); // Last column is units ({e} = </td></tr>)
// {s}</th><th></th><th>Head1</th><th></th><td>{e}
// {s}</th><th></th><th>Head1</th><th></th><th>Head2</th><th></th><td>{e}
// {s}</th><th></th><th>Head1</th><th></th><th>Head2</th><th></th><th>Head3</th><th></th><td>{e}
// {s}</th><th></th><th>Head1</th><th></th><th>Head2</th><th></th><th>Head3</th><th></th><th>Head4</th><th></th><td>{e}
char value_chr[SSPM_SIZE];
WSContentSend_PD(HTTP_SSPM_VOLTAGE, SSPMEnergyFormat(value_chr, Sspm->voltage[0], Settings->flag2.voltage_resolution, indirect, offset, count));
WSContentSend_PD(HTTP_SSPM_CURRENT, SSPMEnergyFormat(value_chr, Sspm->current[0], Settings->flag2.current_resolution, indirect, offset, count));
WSContentSend_PD(HTTP_SSPM_POWER, SSPMEnergyFormat(value_chr, Sspm->active_power[0], Settings->flag2.wattage_resolution, indirect, offset, count));
WSContentSend_P(PSTR("</table><hr/>{t}{s}</th><th></th>")); // First column is empty ({t} = <table style='width:100%'>, {s} = <tr><th>)
bool no_label = false;
for (uint32_t i = 0; i < count; i++) {
WSContentSend_P(PSTR("<th style='text-align:center'>%s%s<th></th>"), (no_label)?"":"L", (no_label)?"":itoa(relay[offset +i], value_chr, 10));
}
WSContentSend_P(PSTR("<td>{e}")); // Last column is units ({e} = </td></tr>)
WSContentSend_PD(HTTP_SNS_VOLTAGE, SSPMEnergyFormat(value_chr, Sspm->voltage[0], Settings->flag2.voltage_resolution, indirect, offset, count));
WSContentSend_PD(HTTP_SNS_CURRENT, SSPMEnergyFormat(value_chr, Sspm->current[0], Settings->flag2.current_resolution, indirect, offset, count));
WSContentSend_PD(HTTP_SNS_POWER, SSPMEnergyFormat(value_chr, Sspm->active_power[0], Settings->flag2.wattage_resolution, indirect, offset, count));
char valu2_chr[SSPM_SIZE];
char valu3_chr[SSPM_SIZE];
WSContentSend_PD(HTTP_SSPM_POWER2, SSPMEnergyFormat(value_chr, Sspm->apparent_power[0], Settings->flag2.wattage_resolution, indirect, offset, count),
SSPMEnergyFormat(valu2_chr, Sspm->reactive_power[0], Settings->flag2.wattage_resolution, indirect, offset, count),
SSPMEnergyFormat(valu3_chr, Sspm->power_factor[0], 2, indirect, offset, count));
WSContentSend_PD(HTTP_SSPM_ENERGY, SSPMEnergyFormat(value_chr, Sspm->energy_today[0], Settings->flag2.energy_resolution, indirect, offset, count),
SSPMEnergyFormat(valu2_chr, Sspm->Settings.energy_yesterday[0], Settings->flag2.energy_resolution, indirect, offset, count),
SSPMEnergyFormat(valu3_chr, Sspm->energy_total[0], Settings->flag2.energy_resolution, indirect, offset, count));
WSContentSend_P(PSTR("</table>{t}")); // {t} = <table style='width:100%'> - Define for next FUNC_WEB_SENSOR
WSContentSend_PD(HTTP_ENERGY_SNS1, SSPMEnergyFormat(value_chr, Sspm->apparent_power[0], Settings->flag2.wattage_resolution, indirect, offset, count),
SSPMEnergyFormat(valu2_chr, Sspm->reactive_power[0], Settings->flag2.wattage_resolution, indirect, offset, count),
SSPMEnergyFormat(valu3_chr, Sspm->power_factor[0], 2, indirect, offset, count));
WSContentSend_PD(HTTP_ENERGY_SNS2, SSPMEnergyFormat(value_chr, Sspm->energy_today[0], Settings->flag2.energy_resolution, indirect, offset, count),
SSPMEnergyFormat(valu2_chr, Sspm->Settings.energy_yesterday[0], Settings->flag2.energy_resolution, indirect, offset, count),
SSPMEnergyFormat(valu3_chr, Sspm->energy_total[0], Settings->flag2.energy_resolution, indirect, offset, count));
WSContentSend_P(PSTR("</table><hr/>{t}")); // {t} = <table style='width:100%'> - Define for next FUNC_WEB_SENSOR
}
#endif // USE_WEBSERVER
}
@ -2298,4 +2292,5 @@ bool Xdrv86(uint8_t function) {
}
#endif // USE_SONOFF_SPM
#endif // USE_ENERGY_SENSOR
#endif // ESP32

View File

@ -87,6 +87,9 @@ bool DhtRead(uint32_t sensor) {
case GPIO_SI7021: // iTead SI7021
delayMicroseconds(500);
break;
case GPIO_MS01: // Sonoff MS01
delayMicroseconds(450);
break;
}
if (!dht_dual_mode) {
@ -101,6 +104,7 @@ bool DhtRead(uint32_t sensor) {
delayMicroseconds(50);
break;
case GPIO_SI7021: // iTead SI7021
case GPIO_MS01: // Sonoff MS01
delayMicroseconds(30); // See: https://github.com/letscontrolit/ESPEasy/issues/1798 and 20210524: https://github.com/arendst/Tasmota/issues/12180
break;
}
@ -152,14 +156,39 @@ bool DhtRead(uint32_t sensor) {
*/
break;
case GPIO_DHT22: // DHT21, DHT22, AM2301, AM2302, AM2321
case GPIO_SI7021: // iTead SI7021
case GPIO_SI7021: { // iTead SI7021
humidity = ((dht_data[0] << 8) | dht_data[1]) * 0.1;
// DHT21/22 (Adafruit):
int16_t temp16 = dht_data[2] << 8 | dht_data[3]; // case 1 : signed 16 bits
if ((dht_data[2] & 0xF0) == 0x80) // case 2 : negative when high nibble = 0x80
if ((dht_data[2] & 0xF0) == 0x80) { // case 2 : negative when high nibble = 0x80
temp16 = -(0xFFF & temp16);
}
temperature = 0.1f * temp16;
break;
}
case GPIO_MS01: { // Sonoff MS01
int32_t voltage = ((dht_data[0] << 8) | dht_data[1]);
// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("DHT: MS01 %d"), voltage);
// Rough approximate of soil moisture % (based on values observed in the eWeLink app)
// Observed values are available here: https://gist.github.com/minovap/654cdcd8bc37bb0d2ff338f8d144a509
float x;
if (voltage < 15037) {
x = voltage - 15200;
humidity = - FastPrecisePowf(0.0024 * x, 3) - 0.0004 * x + 20.1;
}
else if (voltage < 22300) {
humidity = - 0.00069 * voltage + 30.6;
}
else {
x = voltage - 22800;
humidity = - FastPrecisePowf(0.00046 * x, 3) - 0.0004 * x + 15;
}
temperature = 0;
break;
}
}
if (isnan(temperature) || isnan(humidity)) {
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT "Invalid reading"));
@ -178,7 +207,8 @@ bool DhtRead(uint32_t sensor) {
/********************************************************************************************/
bool DhtPinState() {
if ((XdrvMailbox.index >= AGPIO(GPIO_DHT11)) && (XdrvMailbox.index <= AGPIO(GPIO_SI7021))) {
if (((XdrvMailbox.index >= AGPIO(GPIO_DHT11)) && (XdrvMailbox.index <= AGPIO(GPIO_SI7021))) ||
(XdrvMailbox.index == AGPIO(GPIO_MS01))) {
if (dht_sensors < DHT_MAX_SENSORS) {
Dht[dht_sensors].pin = XdrvMailbox.payload;
Dht[dht_sensors].type = BGPIO(XdrvMailbox.index);
@ -232,7 +262,19 @@ void DhtEverySecond(void) {
void DhtShow(bool json) {
for (uint32_t i = 0; i < dht_sensors; i++) {
TempHumDewShow(json, ((0 == TasmotaGlobal.tele_period) && (0 == i)), Dht[i].stype, Dht[i].t, Dht[i].h);
if (GPIO_MS01 == Dht[i].type) {
if (json) {
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_HUMIDITY "\":%*_f}"), Dht[i].stype, Settings->flag2.humidity_resolution, &Dht[i].h);
#ifdef USE_WEBSERVER
} else {
char parameter[FLOATSZ];
dtostrfd(Dht[i].h, Settings->flag2.humidity_resolution, parameter);
WSContentSend_PD(HTTP_SNS_HUM, Dht[i].stype, parameter);
#endif // USE_WEBSERVER
}
} else {
TempHumDewShow(json, ((0 == TasmotaGlobal.tele_period) && (0 == i)), Dht[i].stype, Dht[i].t, Dht[i].h);
}
}
}

View File

@ -59,6 +59,7 @@ RFRECV = GPIO_RFRECV
DHT11 = GPIO_DHT11
DHT22 = GPIO_DHT22
SI7021 = GPIO_SI7021
MS01 = GPIO_MS01
DHT11_OUT = GPIO_DHT11_OUT
DSB = GPIO_DSB
DSB_OUT = GPIO_DSB_OUT