mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-27 19:57:38 +00:00
Merge branch 'mega' of https://github.com/letscontrolit/ESPEasy into feature/Cleanup-and-provisioning-fallback-cmds
This commit is contained in:
@@ -171,7 +171,7 @@ extra_scripts = ${esp82xx_common.extra_scripts}
|
||||
;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1311-2008-5.5_orig/framework-arduinoespressif32-release_v5.5_orig-276436da.tar.xz
|
||||
|
||||
platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55_gcc15
|
||||
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/0401-1225-5.5/framework-arduinoespressif32-release_v5.5-ad03770f.tar.xz
|
||||
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1002-1125-5.5_gcc151/framework-arduinoespressif32-release_v5.5_gcc151-7eede06a.tar.xz
|
||||
|
||||
custom_remove_include = true
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ build_unflags = ${esp32_base_idf5_5.build_unflags}
|
||||
-fexceptions
|
||||
board_build.filesystem = littlefs
|
||||
lib_ignore = ${esp32_base_idf5_5.lib_ignore}
|
||||
PPP
|
||||
HeatpumpIR
|
||||
IRremoteESP8266
|
||||
board = esp32c6cdc
|
||||
|
||||
|
||||
@@ -78,6 +81,7 @@ build_flags = ${esp32c6_common_LittleFS.build_flags}
|
||||
-D ST7789_EXTRA_INIT=1
|
||||
-D P116_EXTRA_ST7789=1
|
||||
extra_scripts = ${esp32c6_common_LittleFS.extra_scripts}
|
||||
lib_ignore = ${esp32_base_idf5_5.lib_ignore}
|
||||
|
||||
|
||||
[env:max_ESP32c6_16M8M]
|
||||
@@ -91,6 +95,7 @@ build_flags = ${esp32c6_common_LittleFS.build_flags}
|
||||
-D ST7789_EXTRA_INIT=1
|
||||
-D P116_EXTRA_ST7789=1
|
||||
extra_scripts = ${esp32c6_common_LittleFS.extra_scripts}
|
||||
lib_ignore = ${esp32_base_idf5_5.lib_ignore}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -229,13 +229,15 @@ void NW004_data_struct_ETH_SPI::webform_load(EventStruct *event)
|
||||
addFormNote(F("I²C-address of Ethernet PHY"));
|
||||
}
|
||||
{
|
||||
if ((getSPIBusCount() > 1) && (Settings.isSPI_valid(0u) || Settings.isSPI_valid(1u))) {
|
||||
if (Settings.getNrConfiguredSPI_buses()) {
|
||||
const int key = NW004_KEY_SPI_BUS;
|
||||
const uint8_t spiBus = _kvs->getValueAsInt(key);
|
||||
KVS_StorageType::Enum storageType;
|
||||
SPIInterfaceSelector(getLabelString(key, true, storageType),
|
||||
getLabelString(key, false, storageType),
|
||||
spiBus);
|
||||
} else {
|
||||
// TODO TD-er: Add error message as we need a SPI bus
|
||||
}
|
||||
|
||||
const int gpio_keys[] = {
|
||||
@@ -446,7 +448,7 @@ bool NW004_data_struct_ETH_SPI::ETHConnectRelaxed() {
|
||||
|
||||
// FIXME TD-er: Fallback for ETH01-EVO board
|
||||
SPI_host = spi_host_device_t::SPI2_HOST;
|
||||
Settings.InitSPI = static_cast<int>(SPI_Options_e::UserDefined);
|
||||
Settings.InitSPI = static_cast<int>(SPI_Options_e::UserDefined_VSPI);
|
||||
Settings.SPI_SCLK_pin = 7;
|
||||
Settings.SPI_MISO_pin = 3;
|
||||
Settings.SPI_MOSI_pin = 10;
|
||||
@@ -454,7 +456,8 @@ bool NW004_data_struct_ETH_SPI::ETHConnectRelaxed() {
|
||||
}
|
||||
|
||||
// else
|
||||
{
|
||||
if (SPI_host != spi_host_device_t::SPI_HOST_MAX) {
|
||||
// TODO TD-er: Do we need to include the CLK, MISO, MOSI pins in the call or do we need to start the SPI bus first?
|
||||
# if ETH_SPI_SUPPORTS_CUSTOM
|
||||
success = iface->begin(
|
||||
to_ESP_phy_type(phyType),
|
||||
|
||||
@@ -107,7 +107,7 @@ bool checkNrArguments(const char *cmd, const String& Line, int nrArguments) {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
log += F(" lineLength=");
|
||||
log += F(" lineLength:");
|
||||
log += Line.length();
|
||||
addLogMove(LOG_LEVEL_ERROR, log);
|
||||
}
|
||||
|
||||
@@ -103,6 +103,9 @@ To create/register a plugin, you have to :
|
||||
#ifndef WEBSERVER_HARDWARE
|
||||
#define WEBSERVER_HARDWARE
|
||||
#endif
|
||||
#ifndef WEBSERVER_INTERFACES
|
||||
#define WEBSERVER_INTERFACES
|
||||
#endif
|
||||
#ifndef WEBSERVER_PINSTATES
|
||||
#define WEBSERVER_PINSTATES
|
||||
#endif
|
||||
@@ -2179,6 +2182,10 @@ To create/register a plugin, you have to :
|
||||
#define PLUGIN_DESCR "Climate A"
|
||||
#endif
|
||||
|
||||
#ifndef BUILD_NO_DEBUG
|
||||
#define BUILD_NO_DEBUG
|
||||
#endif
|
||||
|
||||
// Features and plugins cherry picked from stable set
|
||||
#ifndef FEATURE_SERVO
|
||||
#define FEATURE_SERVO 1
|
||||
|
||||
@@ -371,6 +371,7 @@ public:
|
||||
bool noCheck = false) const;
|
||||
|
||||
bool isSPI_enabled(uint8_t spi_bus) const;
|
||||
uint8_t getNrConfiguredSPI_buses() const;
|
||||
#ifdef ESP32
|
||||
spi_host_device_t getSPI_host(uint8_t spi_bus = 0) const;
|
||||
#endif
|
||||
@@ -395,6 +396,8 @@ public:
|
||||
|
||||
// Return true if I2C settings are correct
|
||||
bool isI2CEnabled(uint8_t i2cBus) const;
|
||||
uint8_t getNrConfiguredI2C_buses() const;
|
||||
|
||||
|
||||
uint8_t getI2CInterface(taskIndex_t TaskIndex) const;
|
||||
int8_t getI2CSdaPin(uint8_t i2cBus) const;
|
||||
|
||||
@@ -993,6 +993,17 @@ bool SettingsStruct_tmpl<N_TASKS>::isSPI_enabled(uint8_t spi_bus) const {
|
||||
return SPI_Options_e::None != SPI_selection;
|
||||
}
|
||||
|
||||
template<uint32_t N_TASKS>
|
||||
uint8_t SettingsStruct_tmpl<N_TASKS>::getNrConfiguredSPI_buses() const
|
||||
{
|
||||
uint8_t res{};
|
||||
if (isSPI_valid(0u)) ++res;
|
||||
#ifdef ESP32
|
||||
if (getSPIBusCount() > 1 && isSPI_valid(1u)) ++res;
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
template<uint32_t N_TASKS>
|
||||
bool SettingsStruct_tmpl<N_TASKS>::getSPI_pins(int8_t spi_gpios[3], uint8_t spi_bus, bool noCheck) const {
|
||||
spi_gpios[0] = -1;
|
||||
@@ -1020,7 +1031,10 @@ bool SettingsStruct_tmpl<N_TASKS>::getSPI_pins(int8_t spi_gpios[3], uint8_t spi_
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case SPI_Options_e::UserDefined:
|
||||
case SPI_Options_e::UserDefined_VSPI:
|
||||
#if SOC_SPI_PERIPH_NUM > 2
|
||||
case SPI_Options_e::UserDefined_HSPI:
|
||||
#endif
|
||||
{
|
||||
#ifdef ESP32
|
||||
if (0 == spi_bus)
|
||||
@@ -1059,6 +1073,7 @@ spi_host_device_t SettingsStruct_tmpl<N_TASKS>::getSPI_host(uint8_t spi_bus) con
|
||||
const SPI_Options_e SPI_selection = static_cast<SPI_Options_e>(0 == spi_bus ? InitSPI : InitSPI1);
|
||||
switch (SPI_selection) {
|
||||
case SPI_Options_e::Vspi_Fspi:
|
||||
case SPI_Options_e::UserDefined_VSPI:
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
return static_cast<spi_host_device_t>(FSPI_HOST);
|
||||
@@ -1072,14 +1087,12 @@ spi_host_device_t SettingsStruct_tmpl<N_TASKS>::getSPI_host(uint8_t spi_bus) con
|
||||
return static_cast<spi_host_device_t>(HSPI_HOST);
|
||||
}
|
||||
#endif
|
||||
case SPI_Options_e::UserDefined:
|
||||
#if SOC_SPI_PERIPH_NUM > 2
|
||||
case SPI_Options_e::UserDefined_HSPI:
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
return static_cast<spi_host_device_t>(FSPI_HOST);
|
||||
#else
|
||||
return static_cast<spi_host_device_t>(VSPI_HOST);
|
||||
#endif
|
||||
return static_cast<spi_host_device_t>(HSPI_HOST);
|
||||
}
|
||||
#endif
|
||||
case SPI_Options_e::None:
|
||||
break;
|
||||
}
|
||||
@@ -1202,6 +1215,24 @@ bool SettingsStruct_tmpl<N_TASKS>::isI2CEnabled(uint8_t i2cBus) const {
|
||||
(getI2CClockSpeedSlow(i2cBus) > 0);
|
||||
}
|
||||
|
||||
template<uint32_t N_TASKS>
|
||||
uint8_t SettingsStruct_tmpl<N_TASKS>::getNrConfiguredI2C_buses() const
|
||||
{
|
||||
#ifdef ESP32
|
||||
uint8_t res{};
|
||||
if (isI2CEnabled(0)) ++res;
|
||||
if (getI2CBusCount() > 1) {
|
||||
if (isI2CEnabled(1)) ++res;
|
||||
#if FEATURE_I2C_INTERFACE_3
|
||||
if (isI2CEnabled(2)) ++res;
|
||||
#endif
|
||||
}
|
||||
return res;
|
||||
#else
|
||||
return isI2CEnabled(0) ? 1 : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// stored in I2C_SPI_bus_Flags per Task
|
||||
template<uint32_t N_TASKS>
|
||||
uint8_t SettingsStruct_tmpl<N_TASKS>::getSPIBusForTask(taskIndex_t TaskIndex) const {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#ifdef ESP32
|
||||
|
||||
#include "../Helpers/Hardware_device_info.h"
|
||||
|
||||
// ESP32 VSPI:
|
||||
// SCK = 18
|
||||
// MISO = 19
|
||||
@@ -35,28 +37,31 @@
|
||||
|
||||
|
||||
# if CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3
|
||||
#define VSPI_FSPI_SHORT_STRING "FSPI"
|
||||
#define VSPI_FSPI_SHORT_STRING "FSPI (" STRINGIFY(FSPI_HOST) ")"
|
||||
# elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2
|
||||
#define VSPI_FSPI_SHORT_STRING "FSPI"
|
||||
# elif CONFIG_IDF_TARGET_ESP32C2 // ESP32-C2
|
||||
#define VSPI_FSPI_SHORT_STRING "FSPI"
|
||||
# elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3
|
||||
#define VSPI_FSPI_SHORT_STRING "SPI"
|
||||
# elif CONFIG_IDF_TARGET_ESP32C5 // ESP32-C5
|
||||
#define VSPI_FSPI_SHORT_STRING "FSPI"
|
||||
# elif CONFIG_IDF_TARGET_ESP32C6 // ESP32-C6
|
||||
#define VSPI_FSPI_SHORT_STRING "FSPI"
|
||||
# elif CONFIG_IDF_TARGET_ESP32C61 // ESP32-C61
|
||||
#define VSPI_FSPI_SHORT_STRING "FSPI"
|
||||
# elif CONFIG_IDF_TARGET_ESP32P4 // ESP32-P4
|
||||
#define VSPI_FSPI_SHORT_STRING "FSPI"
|
||||
#define VSPI_FSPI_SHORT_STRING "FSPI (" STRINGIFY(FSPI_HOST) ")"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C61 || CONFIG_IDF_TARGET_ESP32P4
|
||||
# if SOC_SPI_PERIPH_NUM > 2
|
||||
#define VSPI_FSPI_SHORT_STRING "FSPI (" STRINGIFY(VSPI_HOST) ")"
|
||||
# else
|
||||
#define VSPI_FSPI_SHORT_STRING "SPI" // STRINGIFY(VSPI_HOST)
|
||||
# endif
|
||||
|
||||
# elif CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#define VSPI_FSPI_SHORT_STRING "VSPI"
|
||||
#define VSPI_FSPI_SHORT_STRING "VSPI (" STRINGIFY(VSPI_HOST) ")"
|
||||
|
||||
# else // if CONFIG_IDF_TARGET_ESP32S2
|
||||
# error Target CONFIG_IDF_TARGET is not supported
|
||||
# endif // if CONFIG_IDF_TARGET_ESP32S2
|
||||
|
||||
#if SOC_SPI_PERIPH_NUM > 2
|
||||
#ifdef ESP32_CLASSIC
|
||||
#define HSPI_SHORT_STRING "HSPI (" STRINGIFY(HSPI_HOST) ")"
|
||||
#else
|
||||
#define HSPI_SHORT_STRING STRINGIFY(HSPI_HOST)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
const __FlashStringHelper* getSPI_optionToString(SPI_Options_e option) {
|
||||
switch (option) {
|
||||
@@ -65,43 +70,73 @@ const __FlashStringHelper* getSPI_optionToString(SPI_Options_e option) {
|
||||
case SPI_Options_e::Vspi_Fspi:
|
||||
return F(
|
||||
VSPI_FSPI_SHORT_STRING
|
||||
": CLK=GPIO-" STRINGIFY(VSPI_FSPI_SCK)
|
||||
", MISO=GPIO-" STRINGIFY(VSPI_FSPI_MISO)
|
||||
", MOSI=GPIO-" STRINGIFY(VSPI_FSPI_MOSI) );
|
||||
": CLK=" STRINGIFY(VSPI_FSPI_SCK)
|
||||
", MISO=" STRINGIFY(VSPI_FSPI_MISO)
|
||||
", MOSI=" STRINGIFY(VSPI_FSPI_MOSI) );
|
||||
#ifdef ESP32_CLASSIC
|
||||
case SPI_Options_e::Hspi:
|
||||
return F(
|
||||
"HSPI"
|
||||
": CLK=GPIO-" STRINGIFY(HSPI_SCLK)
|
||||
", MISO=GPIO-" STRINGIFY(HSPI_MISO)
|
||||
", MOSI=GPIO-" STRINGIFY(HSPI_MOSI) );
|
||||
HSPI_SHORT_STRING
|
||||
": CLK=" STRINGIFY(HSPI_SCLK)
|
||||
", MISO=" STRINGIFY(HSPI_MISO)
|
||||
", MOSI=" STRINGIFY(HSPI_MOSI) );
|
||||
|
||||
|
||||
#endif
|
||||
case SPI_Options_e::UserDefined:
|
||||
return F("User-defined: CLK, MISO, MOSI GPIO-pins");
|
||||
case SPI_Options_e::UserDefined_VSPI:
|
||||
return F("User-defined " VSPI_FSPI_SHORT_STRING);
|
||||
#if SOC_SPI_PERIPH_NUM > 2
|
||||
case SPI_Options_e::UserDefined_HSPI:
|
||||
return F("User-defined " HSPI_SHORT_STRING);
|
||||
#endif
|
||||
}
|
||||
return F("Unknown");
|
||||
}
|
||||
|
||||
const __FlashStringHelper* get_vspi_fspi_str()
|
||||
{
|
||||
return F(VSPI_FSPI_SHORT_STRING);
|
||||
}
|
||||
|
||||
const String getSPI_optionToShortString(SPI_Options_e option, uint8_t spi_bus) {
|
||||
#ifdef ESP32
|
||||
String res;
|
||||
switch (option) {
|
||||
case SPI_Options_e::None:
|
||||
return F("Disabled");
|
||||
case SPI_Options_e::Vspi_Fspi:
|
||||
res = F(VSPI_FSPI_SHORT_STRING);
|
||||
break;
|
||||
#ifdef ESP32_CLASSIC
|
||||
case SPI_Options_e::Hspi:
|
||||
res = F("HSPI");
|
||||
break;
|
||||
#endif
|
||||
case SPI_Options_e::UserDefined_VSPI:
|
||||
res = F("User-defined " VSPI_FSPI_SHORT_STRING);
|
||||
break;
|
||||
#if SOC_SPI_PERIPH_NUM > 2
|
||||
case SPI_Options_e::UserDefined_HSPI:
|
||||
res = F("User-defined " HSPI_SHORT_STRING);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (!res.isEmpty()) {
|
||||
if (getSPIBusCount() > 1) {
|
||||
return concat(res + F(" bus "), spi_bus);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
switch (option) {
|
||||
case SPI_Options_e::None:
|
||||
return F("Disabled");
|
||||
case SPI_Options_e::Vspi_Fspi:
|
||||
return F(VSPI_FSPI_SHORT_STRING);
|
||||
#ifdef ESP32_CLASSIC
|
||||
case SPI_Options_e::Hspi:
|
||||
return F("HSPI");
|
||||
#endif
|
||||
case SPI_Options_e::UserDefined:
|
||||
#ifdef ESP32
|
||||
return concat(F("User-defined SPI Bus "), spi_bus);
|
||||
#endif // ifdef ESP32
|
||||
#ifdef ESP8266
|
||||
case SPI_Options_e::UserDefined_VSPI:
|
||||
return F("User-defined SPI");
|
||||
#endif // ifdef ESP8266
|
||||
}
|
||||
#endif
|
||||
return F("Unknown");
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// ESP32-S2/S3 : FSPI
|
||||
|
||||
// ESP32 classic:
|
||||
// SPI_HOST = SPI1_HOST // Only usable on ESP32
|
||||
// SPI_HOST = SPI1_HOST // Only usable on ESP32, when all functions doing SPI operations are in IRAM
|
||||
// HSPI_HOST = SPI2_HOST
|
||||
// VSPI_HOST = SPI3_HOST
|
||||
//
|
||||
@@ -73,12 +73,16 @@ enum class SPI_Options_e {
|
||||
// For ESP32 classic, this is called VSPI
|
||||
// For later versions it is called FSPI
|
||||
// N.B. the ESP32-C3 does not seem to name these as there is no SPI3_HOST.
|
||||
UserDefined = 9 // Leave some room for other, possible future, hardware-related options
|
||||
UserDefined_VSPI = 9 // Leave some room for other, possible future, hardware-related options
|
||||
#if SOC_SPI_PERIPH_NUM > 2
|
||||
,UserDefined_HSPI = 10
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#ifdef ESP32
|
||||
const __FlashStringHelper* getSPI_optionToString(SPI_Options_e option);
|
||||
const __FlashStringHelper* get_vspi_fspi_str();
|
||||
const String getSPI_optionToShortString(SPI_Options_e option, uint8_t spi_bus = 0);
|
||||
#endif // ifdef ESP32
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include <ESPEasySerialPort.h>
|
||||
|
||||
#ifdef ESP32
|
||||
#include <esp32-hal-periman.h>
|
||||
# include <esp32-hal-periman.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -241,11 +241,12 @@ void EspEasy_Console_t::begin(uint32_t baudrate)
|
||||
if (_fallbackSerial._serial != nullptr) {
|
||||
_fallbackSerial._serial->begin(baudrate);
|
||||
|
||||
#ifdef ESP32
|
||||
# ifdef ESP32
|
||||
|
||||
// Need to have this string as C-string, not F-string
|
||||
perimanSetPinBusExtraType(SOC_RX0, "Console");
|
||||
perimanSetPinBusExtraType(SOC_TX0, "Console");
|
||||
#endif
|
||||
# endif // ifdef ESP32
|
||||
|
||||
addLog(LOG_LEVEL_INFO, F("ESPEasy console fallback enabled"));
|
||||
}
|
||||
@@ -329,8 +330,10 @@ bool EspEasy_Console_t::process_serialWriteBuffer() {
|
||||
res = true;
|
||||
}
|
||||
#endif // if USES_ESPEASY_CONSOLE_FALLBACK_PORT
|
||||
#if FEATURE_TIMING_STATS
|
||||
|
||||
STOP_TIMER(CONSOLE_WRITE_SERIAL);
|
||||
if (res) { STOP_TIMER(CONSOLE_WRITE_SERIAL); }
|
||||
#endif // if FEATURE_TIMING_STATS
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
|
||||
|
||||
#ifdef ESP32
|
||||
#define CONSOLE_INPUT_BUFFER_SIZE 1280
|
||||
# define CONSOLE_INPUT_BUFFER_SIZE 1280
|
||||
#else
|
||||
#define CONSOLE_INPUT_BUFFER_SIZE 128
|
||||
#endif
|
||||
# define CONSOLE_INPUT_BUFFER_SIZE 128
|
||||
#endif // ifdef ESP32
|
||||
|
||||
|
||||
/*
|
||||
@@ -31,19 +31,20 @@
|
||||
*/
|
||||
|
||||
EspEasy_Console_Port::EspEasy_Console_Port(LogDestination log_destination)
|
||||
: _serialWriteBuffer(log_destination)
|
||||
: _serialWriteBuffer(log_destination)
|
||||
{
|
||||
InputBuffer_Serial = (char*)calloc(1, CONSOLE_INPUT_BUFFER_SIZE);
|
||||
InputBuffer_Serial = (char *)calloc(1, CONSOLE_INPUT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
EspEasy_Console_Port::~EspEasy_Console_Port()
|
||||
{
|
||||
#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT
|
||||
|
||||
if (_serial != nullptr) {
|
||||
delete _serial;
|
||||
_serial = nullptr;
|
||||
}
|
||||
#endif
|
||||
#endif // if FEATURE_DEFINE_SERIAL_CONSOLE_PORT
|
||||
free(InputBuffer_Serial);
|
||||
}
|
||||
|
||||
@@ -111,14 +112,36 @@ void EspEasy_Console_Port::endPort()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool EspEasy_Console_Port::process_serialWriteBuffer()
|
||||
{
|
||||
if (_serial != nullptr) {
|
||||
#ifdef ESP32
|
||||
if (!xPortCanYield()) return false;
|
||||
#endif
|
||||
return _serialWriteBuffer.process(_serial, _serial->availableForWrite());
|
||||
|
||||
if (!xPortCanYield()) { return false; }
|
||||
#endif // ifdef ESP32
|
||||
size_t availableForWrite = _serial->availableForWrite();
|
||||
|
||||
if (availableForWrite == 0) { return false; }
|
||||
|
||||
if (availableForWrite == 1) {
|
||||
// For only a single byte, just write it directly
|
||||
return _serialWriteBuffer.process(_serial, availableForWrite);
|
||||
}
|
||||
|
||||
if (availableForWrite > 64) {
|
||||
// Set to max. of 64 bytes as this is the optimum 'chunk size' for most
|
||||
// serial ports, like the CDC ports and I2C to UART.
|
||||
// Also it is relatively fast to allocate.
|
||||
availableForWrite = 64;
|
||||
}
|
||||
|
||||
PrintToString str;
|
||||
str.reserve(availableForWrite);
|
||||
|
||||
if (_serialWriteBuffer.process(&str, availableForWrite)) {
|
||||
_serial->write(str.get().c_str(), str.length());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -147,7 +170,7 @@ bool EspEasy_Console_Port::process_consoleInput(uint8_t SerialInByte)
|
||||
Logging.consolePrintln(concat('>', cmd));
|
||||
#endif
|
||||
|
||||
ExecuteCommand_all({EventValueSource::Enum::VALUE_SOURCE_SERIAL, std::move(cmd)}, true);
|
||||
ExecuteCommand_all({ EventValueSource::Enum::VALUE_SOURCE_SERIAL, std::move(cmd) }, true);
|
||||
SerialInByteCounter = 0;
|
||||
InputBuffer_Serial[0] = 0; // serial data processed, clear buffer
|
||||
return true;
|
||||
|
||||
@@ -466,7 +466,7 @@ bool BuildFixes()
|
||||
}
|
||||
|
||||
if (Settings.Build < 20115) {
|
||||
if (Settings.InitSPI != static_cast<int>(SPI_Options_e::UserDefined)) { // User-defined SPI pins set to None
|
||||
if (Settings.InitSPI != static_cast<int>(SPI_Options_e::UserDefined_VSPI)) { // User-defined SPI pins set to None
|
||||
Settings.SPI_SCLK_pin = -1;
|
||||
Settings.SPI_MISO_pin = -1;
|
||||
Settings.SPI_MOSI_pin = -1;
|
||||
|
||||
@@ -168,7 +168,7 @@ void run_compiletime_checks() {
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr size_t offset_WireClockStretchLimit = offsetof(SettingsStruct, WireClockStretchLimit);
|
||||
// constexpr size_t offset_WireClockStretchLimit = offsetof(SettingsStruct, WireClockStretchLimit);
|
||||
constexpr size_t offset_ConnectionFailuresThreshold = offsetof(SettingsStruct, ConnectionFailuresThreshold);
|
||||
static_assert(184 == offset_ConnectionFailuresThreshold, "");
|
||||
|
||||
|
||||
@@ -13,14 +13,7 @@
|
||||
|
||||
void initI2C() {
|
||||
// configure hardware pins according to eeprom settings.
|
||||
if (!Settings.isI2CEnabled(0)
|
||||
#if FEATURE_I2C_MULTIPLE
|
||||
&& !Settings.isI2CEnabled(1)
|
||||
# if FEATURE_I2C_INTERFACE_3
|
||||
&& !Settings.isI2CEnabled(2)
|
||||
# endif // if FEATURE_I2C_INTERFACE_3
|
||||
#endif // if FEATURE_I2C_MULTIPLE
|
||||
)
|
||||
if (Settings.getNrConfiguredI2C_buses() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -36,11 +36,7 @@ void initializeSPIBuses() {
|
||||
#endif // if FEATURE_ETHERNET
|
||||
|
||||
|
||||
if (Settings.isSPI_valid(0u)
|
||||
#ifdef ESP32
|
||||
|| Settings.isSPI_valid(1u)
|
||||
#endif // ifdef ESP32
|
||||
)
|
||||
if (Settings.getNrConfiguredSPI_buses())
|
||||
{
|
||||
#ifdef ESP32
|
||||
|
||||
|
||||
@@ -266,7 +266,8 @@ uint32_t getFlashChipSpeed() {
|
||||
// spi_clk is equal to system clock
|
||||
return getApbFrequency();
|
||||
}
|
||||
return spiClockDivToFrequency(spi_clock);
|
||||
// TODO TD-er: For P4 a pointer to the SPI bus is needed.
|
||||
return spiClockDivToFrequency(nullptr, spi_clock);
|
||||
#endif
|
||||
# endif // if ESP_IDF_STILL_NEEDS_SPI_REGISTERS_FIXED
|
||||
#endif // ifdef ESP8266
|
||||
|
||||
@@ -103,6 +103,7 @@ constexpr uint8_t getI2CBusCount() {
|
||||
#if FEATURE_I2C_MULTIPLE
|
||||
// Not querying the supported nr. of I2C busses in hardware, but using software multiplexing
|
||||
// Assume/expect IDF 5.x
|
||||
// FIXME TD-er: Maybe we should look at SOC_HP_I2C_NUM ????
|
||||
// # if defined(SOC_I2C_SUPPORTED) && SOC_I2C_SUPPORTED
|
||||
# if FEATURE_I2C_INTERFACE_3
|
||||
return 3u; // SOC_I2C_NUM; // Let's go for all I2C busses, including LP_I2C (low power, where available)
|
||||
@@ -117,16 +118,16 @@ constexpr uint8_t getI2CBusCount() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get the number of usable SPI buses
|
||||
constexpr uint8_t getSPIBusCount() {
|
||||
#if defined(ESP32_CLASSIC) || defined(ESP32S2) || defined(ESP32S3) || defined(ESP32P4)
|
||||
return 2u;
|
||||
#elif defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C5) || defined(ESP32C6) || defined(ESP32C61) || defined(ESP32H2)
|
||||
return 1u;
|
||||
#elif defined(ESP8266)
|
||||
return 1u;
|
||||
#else // if defined(ESP32_CLASSIC) || defined(ESP32S2) || defined(ESP32S3) || defined(ESP32P4)
|
||||
#if SOC_SPI_PERIPH_NUM > 3
|
||||
static_assert(false, "Implement processor architecture");
|
||||
#endif // if defined(ESP32_CLASSIC) || defined(ESP32S2) || defined(ESP32S3) || defined(ESP32P4)
|
||||
return 2u;
|
||||
#elif SOC_SPI_PERIPH_NUM > 2
|
||||
return 2u;
|
||||
#else
|
||||
return 1u;
|
||||
#endif
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
|
||||
@@ -509,13 +509,7 @@ void I2CInterfaceSelector(String label,
|
||||
String id,
|
||||
uint8_t choice,
|
||||
bool reloadWhenNeeded) {
|
||||
const uint8_t i2cMaxBusCount = (getI2CBusCount() > 1
|
||||
? ((Settings.isI2CEnabled(1) ? 1 : 0)
|
||||
# if FEATURE_I2C_INTERFACE_3
|
||||
+ (Settings.isI2CEnabled(2) ? 1 : 0)
|
||||
# endif // if FEATURE_I2C_INTERFACE_3
|
||||
)
|
||||
: 0) + (Settings.isI2CEnabled(0) ? 1 : 0);
|
||||
const uint8_t i2cMaxBusCount = Settings.getNrConfiguredI2C_buses();
|
||||
|
||||
if (i2cMaxBusCount > 1) {
|
||||
static uint8_t i2cBusCount = 0;
|
||||
|
||||
@@ -121,6 +121,8 @@ void KeyValueWriter_JSON::write(const KeyValueStruct& kv)
|
||||
|
||||
const size_t nrValues = kv._values.size();
|
||||
|
||||
const bool forceString = kv._format == KeyValueStruct::Format::PreFormatted;
|
||||
|
||||
if (!kv._isArray) {
|
||||
// Either 1 value or empty value
|
||||
if (nrValues == 0) {
|
||||
@@ -129,7 +131,7 @@ void KeyValueWriter_JSON::write(const KeyValueStruct& kv)
|
||||
pr.write('"');
|
||||
}
|
||||
else {
|
||||
writeValue(kv._values[0]);
|
||||
writeValue(kv._values[0], forceString);
|
||||
}
|
||||
} else {
|
||||
// Multiple values, so we must wrap it in []
|
||||
@@ -153,7 +155,7 @@ void KeyValueWriter_JSON::write(const KeyValueStruct& kv)
|
||||
pr.write('\t');
|
||||
#endif // ifdef USE_KWH_JSON_PRETTY_PRINT
|
||||
|
||||
writeValue(kv._values[i]);
|
||||
writeValue(kv._values[i], forceString);
|
||||
}
|
||||
getPrint().write(']');
|
||||
#ifndef USE_KWH_JSON_PRETTY_PRINT
|
||||
@@ -162,7 +164,7 @@ void KeyValueWriter_JSON::write(const KeyValueStruct& kv)
|
||||
}
|
||||
}
|
||||
|
||||
void KeyValueWriter_JSON::writeValue(const ValueStruct& val)
|
||||
void KeyValueWriter_JSON::writeValue(const ValueStruct& val, bool forceString)
|
||||
{
|
||||
if (!val.isSet()) { return; }
|
||||
auto& pr = getPrint();
|
||||
@@ -196,6 +198,14 @@ void KeyValueWriter_JSON::writeValue(const ValueStruct& val)
|
||||
case ValueStruct::ValueType::Unset:
|
||||
case ValueStruct::ValueType::String:
|
||||
case ValueStruct::ValueType::FlashString:
|
||||
if (forceString) {
|
||||
String tmp(to_json_value(str));
|
||||
if (!isWrappedWithQuotes(tmp)) {
|
||||
tmp = wrap_String(tmp, '"');
|
||||
}
|
||||
pr.print(tmp);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
pr.print(to_json_value(str));
|
||||
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void writeValue(const ValueStruct& value);
|
||||
void writeValue(const ValueStruct& value, bool forceString);
|
||||
|
||||
#ifdef USE_KWH_JSON_PRETTY_PRINT
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ void LogStreamWriter::clear()
|
||||
_readpos = 0;
|
||||
}
|
||||
|
||||
bool LogStreamWriter::process(Stream*stream, size_t availableForWrite)
|
||||
bool LogStreamWriter::process(Print*stream, size_t availableForWrite)
|
||||
{
|
||||
if (stream == nullptr) { return false; }
|
||||
return write(*stream, availableForWrite) != 0;
|
||||
@@ -30,7 +30,7 @@ uint32_t LogStreamWriter::getNrMessages() const
|
||||
return Logging.getNrMessages(_log_destination);
|
||||
}
|
||||
|
||||
size_t LogStreamWriter::write(Stream& stream, size_t nrBytesToWrite)
|
||||
size_t LogStreamWriter::write(Print& stream, size_t nrBytesToWrite)
|
||||
{
|
||||
size_t bytesWritten = 0;
|
||||
|
||||
@@ -45,7 +45,7 @@ size_t LogStreamWriter::write(Stream& stream, size_t nrBytesToWrite)
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
size_t LogStreamWriter::write_single_item(Stream& stream,
|
||||
size_t LogStreamWriter::write_single_item(Print& stream,
|
||||
size_t nrBytesToWrite)
|
||||
{
|
||||
const size_t res = write_item(stream, nrBytesToWrite);
|
||||
@@ -54,7 +54,7 @@ size_t LogStreamWriter::write_single_item(Stream& stream,
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t LogStreamWriter::write_item(Stream& stream,
|
||||
size_t LogStreamWriter::write_item(Print& stream,
|
||||
size_t nrBytesToWrite)
|
||||
{
|
||||
size_t bytesWritten = 0;
|
||||
@@ -103,7 +103,7 @@ size_t LogStreamWriter::write_item(Stream& stream,
|
||||
++_readpos;
|
||||
} else {
|
||||
if ((bytesWritten + 2) > nrBytesToWrite) { return bytesWritten; }
|
||||
bytesWritten += stream.println();
|
||||
bytesWritten += stream.print(F("\r\n")); // stream.println();
|
||||
|
||||
// Done with entry, cleanup and leave
|
||||
clear();
|
||||
@@ -113,6 +113,6 @@ size_t LogStreamWriter::write_item(Stream& stream,
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
size_t LogStreamWriter::write_skipping(Stream& stream) { return 0; }
|
||||
size_t LogStreamWriter::write_skipping(Print& stream) { return 0; }
|
||||
|
||||
void LogStreamWriter::prepare_prefix() {}
|
||||
|
||||
@@ -11,7 +11,7 @@ public:
|
||||
|
||||
virtual ~LogStreamWriter() {}
|
||||
|
||||
virtual bool process(Stream* stream, size_t availableForWrite);
|
||||
virtual bool process(Print* stream, size_t availableForWrite);
|
||||
|
||||
// Only use this from derived classes, as we need a Stream to further process
|
||||
virtual bool process();
|
||||
@@ -24,20 +24,20 @@ protected:
|
||||
|
||||
// Write continuously until either nrBytesToWrite was reached or no new messages were available to process.
|
||||
// @retval Number of bytes written. Zero when no new message was available to process.
|
||||
virtual size_t write(Stream& stream,
|
||||
virtual size_t write(Print& stream,
|
||||
size_t nrBytesToWrite);
|
||||
|
||||
// Write single item and clear() on return.
|
||||
// This way each call starts with a new item and long messages may get truncated based on nrBytesToWrite
|
||||
// @retval Number of bytes written. Zero when no new message was available to process.
|
||||
virtual size_t write_single_item(Stream& stream,
|
||||
virtual size_t write_single_item(Print& stream,
|
||||
size_t nrBytesToWrite);
|
||||
|
||||
virtual size_t write_item(Stream& stream,
|
||||
virtual size_t write_item(Print& stream,
|
||||
size_t nrBytesToWrite);
|
||||
|
||||
|
||||
virtual size_t write_skipping(Stream& stream);
|
||||
virtual size_t write_skipping(Print& stream);
|
||||
|
||||
virtual void prepare_prefix();
|
||||
|
||||
|
||||
@@ -34,14 +34,10 @@ String SerialWriteBuffer_t::colorize(const String& str) const {
|
||||
}
|
||||
|
||||
|
||||
size_t SerialWriteBuffer_t::write_skipping(Stream& stream)
|
||||
size_t SerialWriteBuffer_t::write_skipping(Print& stream)
|
||||
{
|
||||
size_t bytesWritten{};
|
||||
|
||||
// Mark with empty line we skipped the rest of the message.
|
||||
bytesWritten += stream.println(F(" ..."));
|
||||
bytesWritten += stream.println();
|
||||
return bytesWritten;
|
||||
return stream.print(F(" ...\r\n\r\n"));
|
||||
}
|
||||
|
||||
void SerialWriteBuffer_t::prepare_prefix()
|
||||
|
||||
@@ -14,7 +14,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
size_t write_skipping(Stream& stream) override;
|
||||
size_t write_skipping(Print& stream) override;
|
||||
|
||||
void prepare_prefix() override;
|
||||
|
||||
|
||||
@@ -480,13 +480,13 @@ KeyValueStruct getKeyValue(LabelType::Enum label, bool extendedValue)
|
||||
{
|
||||
return KeyValueStruct(F("Show Unit of Measure"), Settings.ShowUnitOfMeasureOnDevicesPage());
|
||||
}
|
||||
#endif // if FEATURE_TASKVALUE_UNIT_OF_MEASURE
|
||||
#if FEATURE_MQTT_CONNECT_BACKGROUND
|
||||
#endif // if FEATURE_TASKVALUE_UNIT_OF_MEASURE
|
||||
#if FEATURE_MQTT_CONNECT_BACKGROUND
|
||||
case LabelType::MQTT_CONNECT_IN_BACKGROUND:
|
||||
{
|
||||
return KeyValueStruct(F("MQTT Connect in background"), Settings.MQTTConnectInBackground());
|
||||
}
|
||||
#endif // if FEATURE_MQTT_CONNECT_BACKGROUND
|
||||
#endif // if FEATURE_MQTT_CONNECT_BACKGROUND
|
||||
|
||||
#if CONFIG_SOC_WIFI_SUPPORT_5G
|
||||
case LabelType::WIFI_BAND_MODE:
|
||||
@@ -544,7 +544,9 @@ KeyValueStruct getKeyValue(LabelType::Enum label, bool extendedValue)
|
||||
}
|
||||
KeyValueStruct kv(F("RSSI"), WiFi.RSSI());
|
||||
#if FEATURE_TASKVALUE_UNIT_OF_MEASURE
|
||||
KV_SETUNIT(UOM_dBm);
|
||||
if (!extendedValue) {
|
||||
KV_SETUNIT(UOM_dBm);
|
||||
}
|
||||
#endif
|
||||
return kv;
|
||||
}
|
||||
@@ -1025,11 +1027,11 @@ KeyValueStruct getKeyValue(LabelType::Enum label, bool extendedValue)
|
||||
KeyValueStruct kv(F("Sketch Size"), str);
|
||||
KV_SETID(F("sketch_size"));
|
||||
|
||||
if (!extendedValue) {
|
||||
#if FEATURE_TASKVALUE_UNIT_OF_MEASURE
|
||||
if (!extendedValue) {
|
||||
KV_SETUNIT(UOM_kB);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return kv;
|
||||
}
|
||||
case LabelType::SKETCH_FREE:
|
||||
@@ -1043,18 +1045,6 @@ KeyValueStruct getKeyValue(LabelType::Enum label, bool extendedValue)
|
||||
}
|
||||
case LabelType::FS_SIZE:
|
||||
{
|
||||
String size;
|
||||
|
||||
if (extendedValue) {
|
||||
size = strformat(
|
||||
F("%d [kB] (%d kB free)"),
|
||||
SpiffsTotalBytes() / 1024,
|
||||
SpiffsFreeSpace() / 1024);
|
||||
}
|
||||
else {
|
||||
size = (SpiffsTotalBytes() >> 10);
|
||||
}
|
||||
|
||||
KeyValueStruct kv(
|
||||
#ifdef USE_LITTLEFS
|
||||
F("Little FS Size"),
|
||||
@@ -1063,15 +1053,10 @@ KeyValueStruct getKeyValue(LabelType::Enum label, bool extendedValue)
|
||||
#endif // ifdef USE_LITTLEFS
|
||||
SpiffsTotalBytes() >> 10);
|
||||
KV_SETID(F("fs_size"));
|
||||
|
||||
#if FEATURE_TASKVALUE_UNIT_OF_MEASURE
|
||||
KV_SETUNIT(UOM_kB);
|
||||
#endif
|
||||
|
||||
if (!extendedValue) {
|
||||
#if FEATURE_TASKVALUE_UNIT_OF_MEASURE
|
||||
KV_SETUNIT(UOM_kB);
|
||||
#endif
|
||||
}
|
||||
return kv;
|
||||
}
|
||||
case LabelType::FS_FREE:
|
||||
|
||||
@@ -239,7 +239,9 @@ String serializeDomoticzJson(struct EventStruct *event)
|
||||
}
|
||||
} else {
|
||||
writer.write({ F("nvalue"), F("0") });
|
||||
writer.write({ F("svalue"), formatDomoticzSensorType(event) });
|
||||
writer.write({ F("svalue"),
|
||||
formatDomoticzSensorType(event),
|
||||
KeyValueStruct::Format::PreFormatted });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "../WebServer/ESPEasy_WebServer.h"
|
||||
#include "../WebServer/Markup.h"
|
||||
#include "../WebServer/Markup_Forms.h"
|
||||
#include "../ESPEasyCore/Controller.h"
|
||||
#include "../DataStructs/ControllerSettingsStruct.h"
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Functions to load and store controller settings on the web page.
|
||||
|
||||
@@ -341,12 +341,12 @@ static const char jsClipboardCopyPart2[] PROGMEM = {
|
||||
// "if(t==null){i= max_loop + 1;"
|
||||
"if(t==null){i=101;"
|
||||
"}else{"
|
||||
"cb+=t.innerHTML.replace(/<[Bb][Rr]\\s*\\/?>/gim,'\\n')+'"
|
||||
"const visibleLines=Array.from(t.children).filter((e=>null!==e.offsetParent)).map((e=>e.innerHTML));visibleLines.length>0&&(cb+=visibleLines.join('\\n').replace(/<[Bb][Rr]\\s*\\/?>/gim,'\\n')+'"
|
||||
};
|
||||
|
||||
//Fix HTML
|
||||
static const char jsClipboardCopyPart3[] PROGMEM = {
|
||||
"';}}"
|
||||
"');}}"
|
||||
"cb=cb.replace(/<\\/[Dd][Ii][Vv]\\s*\\/?>/gim,'\\n');"
|
||||
"cb=cb.replace(/<[^>]*>/gim,'');"
|
||||
"var ti=document.createElement('textarea');"
|
||||
@@ -381,38 +381,91 @@ static const char jsSplitMultipleFields[] PROGMEM = {
|
||||
#ifdef WEBSERVER_INCLUDE_JS
|
||||
static const char DATA_UPDATE_SENSOR_VALUES_DEVICE_PAGE_JS[] PROGMEM = {
|
||||
"function elId(e){return document.getElementById(e)}"
|
||||
"function loopDeLoop(e,s){var o,a,n=0;isNaN(s)&&(s=1),null==e&&(e=1e3),"
|
||||
"i=setInterval(function(){if(n>0){clearInterval(i);return}"
|
||||
"++s>1||fetch('/json?view=sensorupdate').then(function(s){var n;if(200!==s.status){console.log('Looks like there was a problem. Status Code: '+s.status);return}"
|
||||
"s.json().then(function(s){e=s.TTL;"
|
||||
"loopDeLoop(1000);"
|
||||
"const SENSOR_URL='/json?view=sensorupdate';"
|
||||
"function loopDeLoop(e=1000){setTimeout(function(){fetch(SENSOR_URL)"
|
||||
".then(e=>{if(!e.ok)throw new Error(e.status);return e.json()})"
|
||||
".then(o=>{e=o.TTL||e;"
|
||||
#if (defined(FEATURE_TASKVALUE_UNIT_OF_MEASURE) && FEATURE_TASKVALUE_UNIT_OF_MEASURE) || (defined(FEATURE_STRING_VARIABLES) && FEATURE_STRING_VARIABLES)
|
||||
"var r=void 0===s.ShowUoM||s.ShowUoM&&'false'!==s.ShowUoM;"
|
||||
"const n=void 0===o.ShowUoM||o.ShowUoM&&'false'!==o.ShowUoM;"
|
||||
#endif // if (defined(FEATURE_TASKVALUE_UNIT_OF_MEASURE) && FEATURE_TASKVALUE_UNIT_OF_MEASURE) || (defined(FEATURE_STRING_VARIABLES) && FEATURE_STRING_VARIABLES)
|
||||
"for(o=0;o<s.Sensors.length;o++)if(s.Sensors[o].hasOwnProperty('TaskValues'))"
|
||||
"for(a=0;a<s.Sensors[o].TaskValues.length;a++)try{n=s.Sensors[o].TaskValues[a].Value}catch(l){n=l.name}"
|
||||
"finally{if('TypeError'!==n){var u=s.Sensors[o].TaskValues[a].Value,t=s.Sensors[o].TaskValues[a].NrDecimals;t<255&&(u=parseFloat(u).toFixed(t));"
|
||||
"for(let i=0;i<o.Sensors.length;i++){const t=o.Sensors[i];"
|
||||
"if(t.TaskValues)for(let j=0;j<t.TaskValues.length;j++){const r=t.TaskValues[j];"
|
||||
"if(!r||null==r.Value)continue;"
|
||||
"let s=r.Value;const d=r.NrDecimals;"
|
||||
"d<255&&(s=parseFloat(s).toFixed(d));"
|
||||
#if (defined(FEATURE_TASKVALUE_UNIT_OF_MEASURE) && FEATURE_TASKVALUE_UNIT_OF_MEASURE) || (defined(FEATURE_STRING_VARIABLES) && FEATURE_STRING_VARIABLES)
|
||||
"var $=s.Sensors[o].TaskValues[a].UoM,T=s.Sensors[o].TaskValues[a].Presentation;T?u=T:$&&r&&(u+=' '+$);"
|
||||
"r.Presentation?s=r.Presentation:"
|
||||
"r.UoM&&n&&(s+=' '+r.UoM);"
|
||||
#endif // if (defined(FEATURE_TASKVALUE_UNIT_OF_MEASURE) && FEATURE_TASKVALUE_UNIT_OF_MEASURE) || (defined(FEATURE_STRING_VARIABLES) && FEATURE_STRING_VARIABLES)
|
||||
"var S='value_'+(s.Sensors[o].TaskNumber-1)+'_'+(s.Sensors[o].TaskValues[a].ValueNumber-1),"
|
||||
"k='valuename_'+(s.Sensors[o].TaskNumber-1)+'_'+(s.Sensors[o].TaskValues[a].ValueNumber-1),"
|
||||
"V=elId(S),f=elId(k);V&&(V.innerHTML=u),"
|
||||
"f&&(f.innerHTML=s.Sensors[o].TaskValues[a].Name+':')}}"
|
||||
"clearInterval(i),loopDeLoop(e,0)})}).catch(function(s){console.log(s.message),e=5e3,clearInterval(i),loopDeLoop(e,0)}),n=1},e)}"
|
||||
"loopDeLoop(1e3,0);"
|
||||
"const l=t.TaskNumber-1+'_'+(r.ValueNumber-1),"
|
||||
"a=elId('value_'+l);"
|
||||
"a&&(a.innerHTML=s);"
|
||||
"const u=elId('valuename_'+l);"
|
||||
"u&&(u.innerHTML=r.Name+':')"
|
||||
"}}loopDeLoop(e)})"
|
||||
".catch(e=>{loopDeLoop(5000)})},e)}"
|
||||
};
|
||||
#endif // WEBSERVER_INCLUDE_JS
|
||||
|
||||
#ifdef WEBSERVER_INCLUDE_JS
|
||||
static const char DATA_FETCH_AND_PARSE_LOG_JS[] PROGMEM = {
|
||||
"function elId(e){return document.getElementById(e)}"
|
||||
"function getBrowser(){var e,o=navigator.userAgent,r=o.match(/(opera|chrome|safari|firefox|msie|trident(?=\\/))\\/?\\s*(\\d+)/i)||[];return/trident/i.test(r[1])?{name:'IE',version:(e=/\brv[ :]+(\\d+)/g.exec(o)||[])[1]||''}:'Chrome'===r[1]&&null!=(e=o.match(/\bOPR|Edge\\/(\\d+)/))?{name:'Opera',version:e[1]}:(r=r[2]?[r[1],r[2]]:[navigator.appName,navigator.appVersion,'-?'],null!=(e=o.match(/version\\/(\\d+)/i))&&r.splice(1,1,e[1]),{name:r[0],version:r[1]})}"
|
||||
"var browser=getBrowser(),currentBrowser=browser.name+browser.version;textToDisplay=(browser.name=browser.version<12)?'Error: '+currentBrowser+' is not supported! Please try a modern web browser.':'Fetching log entries...',elId('copyText_1').innerHTML=textToDisplay,loopDeLoop(1e3,0);var logLevel=['Unused','Error','Info','Debug','Debug More','Undefined','Undefined','Undefined','Undefined','Debug Dev'];"
|
||||
"function loopDeLoop(e,o){let r='copyText_1';isNaN(o)&&(o=1),null==e&&(e=1e3),scrolling_type=e<=500?'auto':'smooth';var n,t,i='',l=0,"
|
||||
"s=setInterval(function(){if(l>0){clearInterval(s);return}++o>1?l=1:fetch('/logjson').then(function(o){if(200!==o.status){console.log('Looks like there was a problem. Status Code: '+o.status);return}o.json()"
|
||||
".then(function(o){var l;for(null==t&&(t=''),n=0;n<o.Log.nrEntries;++n)try{l=o.Log.Entries[n].timestamp}catch(a){l=a.name}finally{'TypeError'!==l&&(i=o.Log.Entries[n].timestamp,t+='<div class=level_'+o.Log.Entries[n].level+' id='+i+'><font color=\"gray\">'+o.Log.Entries[n].timestamp+':</font> '+o.Log.Entries[n].text+'</div>')}e=o.Log.TTL,''!==t&&('Fetching log entries...'==elId(r).innerHTML&&(elId(r).innerHTML=''),elId(r).innerHTML+=t),t='',!0==(autoscroll_on=elId('autoscroll').checked)&&''!==i&&elId(i).scrollIntoView({behavior:scrolling_type}),elId('current_loglevel').innerHTML='Logging: '+logLevel[o.Log.SettingsWebLogLevel]+' ('+o.Log.SettingsWebLogLevel+')',clearInterval(s),"
|
||||
"loopDeLoop(e,0)})}).catch(function(o){elId(r).innerHTML+='<div>>> '+o.message+' <<</div>',autoscroll_on=elId('autoscroll').checked,elId(r).scrollTop=elId(r).scrollHeight,e=5e3,clearInterval(s),"
|
||||
"loopDeLoop(e,0)}),l=1},e)}"
|
||||
"function elId(e){return document.getElementById(e)}"
|
||||
"const ct1 = elId('copyText_1');"
|
||||
"window.fetch?ct1.textContent='Fetching log entries...':"
|
||||
"ct1.textContent='Error: This browser is not supported. Please use a modern browser.';"
|
||||
"const logLevel={0:'Unused',1:'Error',2:'Info',3:'Debug',4:'Debug More',9:'Debug Dev'};"
|
||||
"function loopDeLoop(e=1000){setTimeout(function(){fetch('/logjson')"
|
||||
".then(e=>{if(!e.ok)throw Error(e.status);return e.json()})"
|
||||
".then(t=>{let o='';"
|
||||
"for(let l=0;l<t.Log.nrEntries;l++){let i=t.Log.Entries[l];"
|
||||
"i&&i.timestamp&&(o+=`<div class=level_${i.level}>"
|
||||
"<font color='gray'>${i.timestamp}:</font> ${i.text}</div>`)}"
|
||||
"e=t.Log.TTL||e;"
|
||||
"o&&(ct1.textContent==='Fetching log entries...'&&(ct1.innerHTML=''),ct1.innerHTML+=o);"
|
||||
"applyLogFilter();"
|
||||
"elId('autoscroll')?.checked&&ct1.scrollTo({top:ct1.scrollHeight,behavior:e<=500?'auto':'smooth'});"
|
||||
"let n=t.Log.SettingsWebLogLevel,r=logLevel[n]?" "?'Undefined';"
|
||||
"elId('current_loglevel').textContent=`Logging: ${r} (${n})`;"
|
||||
"loopDeLoop(e)})"
|
||||
".catch(e=>{ct1.innerHTML+=`<div>>> ${e.message} <<</div>`;"
|
||||
"ct1.scrollTop=ct1.scrollHeight;loopDeLoop(5000)})},e)}"
|
||||
"function applyLogFilter(){"
|
||||
"let e=elId('logfilter').value.split(';').map(e=>e.trim()).filter(Boolean),"
|
||||
"t=document.querySelectorAll('#copyText_1 > div'),"
|
||||
"o=e.some(e=>!e.startsWith('!'));"
|
||||
"for(let l of t){"
|
||||
"l.dataset.originalHtml||(l.dataset.originalHtml=l.innerHTML);"
|
||||
"let i=l.dataset.originalHtml,n=l.textContent.toLowerCase(),r=[],s=!1,a=!o;"
|
||||
"for(let c of e){"
|
||||
"if(c.startsWith('!')){let g=c.slice(1);"
|
||||
"if(!g.includes('&')||g.startsWith('&')||g.endsWith('&')){"
|
||||
"if(g&&n.includes(g.toLowerCase())){s=!0;break}}"
|
||||
"else{let f=g.split('&').map(e=>e.trim()).filter(Boolean),u=-1,d=!0;"
|
||||
"for(let p of f){let h=n.indexOf(p.toLowerCase(),u+1);if(h===-1){d=!1;break}u=h}"
|
||||
"if(d){s=!0;break}}continue}"
|
||||
"if(c.includes('&')&&!c.startsWith('&')&&!c.endsWith('&')){"
|
||||
"let L=c.split('&').map(e=>e.trim()).filter(Boolean);"
|
||||
"if(L.length>=2){let _=-1,$=!0;"
|
||||
"for(let b of L){let m=n.indexOf(b.toLowerCase(),_+1);if(m===-1){$=!1;break}_=m}"
|
||||
"if($){r.push(...L),a=!0;break}}continue}"
|
||||
"if(n.includes(c.toLowerCase())){r.push(c),a=!0;break}}"
|
||||
"if(s||!a){l.style.display='none';continue}"
|
||||
"l.style.display='';l.innerHTML=highlightOutsideTags(i,r)}}"
|
||||
"function highlightOutsideTags(e,t){if(!t.length)return e;"
|
||||
"let o='',l=!1,i=0;"
|
||||
"for(;i<e.length;){let n=e[i];"
|
||||
"if('<'===n&&(l=!0),'>'===n){l=!1;o+=n;i++;continue}"
|
||||
"if(!l){let r=!1;"
|
||||
"for(let s of t){let a=e.slice(i,i+s.length);"
|
||||
"if(a.toLowerCase()===s.toLowerCase()){"
|
||||
"o+=`<span style='background-color: #bb9300;color: black;'>${a}</span>`;"
|
||||
"i+=s.length;r=!0;break}}"
|
||||
"if(r)continue}"
|
||||
"o+=n;i++}return o}"
|
||||
"loopDeLoop(1000);"
|
||||
"const input=document.getElementById('logfilter');"
|
||||
"input&&(input.placeholder='\"!\"=exclude \";\"=or \"&\"=and (e.g. !act)');"
|
||||
};
|
||||
#endif // WEBSERVER_INCLUDE_JS
|
||||
|
||||
|
||||
@@ -1409,11 +1409,11 @@ void devicePage_show_serial_config(taskIndex_t taskIndex)
|
||||
void devicePage_show_SPI_config(taskIndex_t taskIndex, deviceIndex_t DeviceIndex)
|
||||
{
|
||||
if (Device[DeviceIndex].isSPI()
|
||||
&& !(Settings.isSPI_valid(0u) || (getSPIBusCount() > 1 && Settings.isSPI_valid(1u)))) {
|
||||
&& Settings.getNrConfiguredSPI_buses() == 0) {
|
||||
addFormNote(F("SPI Bus not configured yet (Hardware page)."));
|
||||
}
|
||||
#ifdef ESP32
|
||||
if (Device[DeviceIndex].SpiBusSelect && getSPIBusCount() > 1 && (Settings.isSPI_valid(0u) || Settings.isSPI_valid(1u))) {
|
||||
if (Device[DeviceIndex].SpiBusSelect && getSPIBusCount() > 1 && (Settings.getNrConfiguredSPI_buses() != 0)) {
|
||||
uint8_t spiBus = Settings.getSPIBusForTask(taskIndex);
|
||||
SPIInterfaceSelector(F("SPI Bus"),
|
||||
F("pspibus"),
|
||||
@@ -1428,14 +1428,7 @@ void devicePage_show_I2C_config(taskIndex_t taskIndex, deviceIndex_t DeviceIndex
|
||||
|
||||
addFormSubHeader(F("I2C options"));
|
||||
|
||||
if (!Settings.isI2CEnabled(0)
|
||||
# if FEATURE_I2C_MULTIPLE
|
||||
&& (getI2CBusCount() > 1 && !Settings.isI2CEnabled(1))
|
||||
# if FEATURE_I2C_INTERFACE_3
|
||||
&& (getI2CBusCount() > 2 && !Settings.isI2CEnabled(2))
|
||||
# endif // if FEATURE_I2C_INTERFACE_3
|
||||
# endif // if FEATURE_I2C_MULTIPLE
|
||||
) {
|
||||
if (Settings.getNrConfiguredI2C_buses() == 0) {
|
||||
addFormNote(F("I2C Bus is not configured yet (Hardware page)."));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../WebServer/FileList.h"
|
||||
#include "../WebServer/HTML_wrappers.h"
|
||||
#include "../WebServer/HardwarePage.h"
|
||||
#include "../WebServer/InterfacesPage.h"
|
||||
#include "../WebServer/I2C_Scanner.h"
|
||||
#include "../WebServer/JSON.h"
|
||||
#include "../WebServer/LoadFromFS.h"
|
||||
@@ -272,6 +273,9 @@ void WebServerInit()
|
||||
#ifdef WEBSERVER_HARDWARE
|
||||
web_server.on(F("/hardware"), handle_hardware);
|
||||
#endif // ifdef WEBSERVER_HARDWARE
|
||||
#ifdef WEBSERVER_INTERFACES
|
||||
web_server.on(F("/interfaces"), handle_interfaces);
|
||||
#endif
|
||||
#ifdef WEBSERVER_I2C_SCANNER
|
||||
web_server.on(F("/i2cscanner"), handle_i2cscanner);
|
||||
#endif // ifdef WEBSERVER_I2C_SCANNER
|
||||
|
||||
@@ -16,16 +16,10 @@
|
||||
|
||||
#include "../Helpers/ESPEasy_Storage.h"
|
||||
#include "../Helpers/Hardware_GPIO.h"
|
||||
#include "../Helpers/Hardware_I2C.h"
|
||||
#include "../Helpers/Hardware_SPI.h"
|
||||
#include "../Helpers/SPI_Helper.h"
|
||||
#include "../Helpers/StringConverter.h"
|
||||
#include "../Helpers/StringGenerator_GPIO.h"
|
||||
|
||||
#if FEATURE_I2C_MULTIPLE
|
||||
#include "../Helpers/I2C_access.h"
|
||||
#include "../Helpers/Hardware_device_info.h"
|
||||
#endif // if FEATURE_I2C_MULTIPLE
|
||||
|
||||
// ********************************************************************************
|
||||
// Web Interface hardware page
|
||||
@@ -45,90 +39,6 @@ void handle_hardware() {
|
||||
Settings.Pin_status_led = getFormItemInt(F("pled"));
|
||||
Settings.Pin_status_led_Inversed = isFormItemChecked(F("pledi"));
|
||||
Settings.Pin_Reset = getFormItemInt(F("pres"));
|
||||
#if FEATURE_PLUGIN_PRIORITY
|
||||
if (!isI2CPriorityTaskActive(0))
|
||||
#endif //if FEATURE_PLUGIN_PRIORITY
|
||||
{
|
||||
update_whenset_FormItemInt(F("psda0"), Settings.Pin_i2c_sda);
|
||||
update_whenset_FormItemInt(F("pscl0"), Settings.Pin_i2c_scl);
|
||||
}
|
||||
Settings.I2C_clockSpeed = getFormItemInt(F("pi2csp0"), DEFAULT_I2C_CLOCK_SPEED);
|
||||
Settings.I2C_clockSpeed_Slow = getFormItemInt(F("pi2cspslow0"), DEFAULT_I2C_CLOCK_SPEED_SLOW);
|
||||
Settings.WireClockStretchLimit = getFormItemInt(F("wirestretch"));
|
||||
#if FEATURE_I2CMULTIPLEXER
|
||||
Settings.I2C_Multiplexer_Type = getFormItemInt(F("pi2cmuxtype0"));
|
||||
if (Settings.I2C_Multiplexer_Type != I2C_MULTIPLEXER_NONE) {
|
||||
Settings.I2C_Multiplexer_Addr = getFormItemInt(F("pi2cmuxaddr0"));
|
||||
} else {
|
||||
Settings.I2C_Multiplexer_Addr = -1;
|
||||
}
|
||||
Settings.I2C_Multiplexer_ResetPin = getFormItemInt(F("pi2cmuxreset0"));
|
||||
#endif // if FEATURE_I2CMULTIPLEXER
|
||||
#if FEATURE_I2C_MULTIPLE // No loop used here, to avoid adding setters to the SettingsStruct template code
|
||||
if (getI2CBusCount() > 1) {
|
||||
#if FEATURE_PLUGIN_PRIORITY
|
||||
if (!isI2CPriorityTaskActive(1))
|
||||
#endif //if FEATURE_PLUGIN_PRIORITY
|
||||
{
|
||||
update_whenset_FormItemInt(F("psda1"), Settings.Pin_i2c2_sda);
|
||||
update_whenset_FormItemInt(F("pscl1"), Settings.Pin_i2c2_scl);
|
||||
}
|
||||
Settings.I2C2_clockSpeed = getFormItemInt(F("pi2csp1"), DEFAULT_I2C_CLOCK_SPEED);
|
||||
Settings.I2C2_clockSpeed_Slow = getFormItemInt(F("pi2cspslow1"), DEFAULT_I2C_CLOCK_SPEED_SLOW);
|
||||
#if FEATURE_I2CMULTIPLEXER
|
||||
Settings.I2C2_Multiplexer_Type = getFormItemInt(F("pi2cmuxtype1"));
|
||||
if (Settings.I2C2_Multiplexer_Type != I2C_MULTIPLEXER_NONE) {
|
||||
Settings.I2C2_Multiplexer_Addr = getFormItemInt(F("pi2cmuxaddr1"));
|
||||
} else {
|
||||
Settings.I2C2_Multiplexer_Addr = -1;
|
||||
}
|
||||
Settings.I2C2_Multiplexer_ResetPin = getFormItemInt(F("pi2cmuxreset1"));
|
||||
#endif // if FEATURE_I2CMULTIPLEXER
|
||||
}
|
||||
#if FEATURE_I2C_INTERFACE_3
|
||||
if (getI2CBusCount() > 2) {
|
||||
#if FEATURE_PLUGIN_PRIORITY
|
||||
if (!isI2CPriorityTaskActive(2))
|
||||
#endif //if FEATURE_PLUGIN_PRIORITY
|
||||
{
|
||||
update_whenset_FormItemInt(F("psda2"), Settings.Pin_i2c3_sda);
|
||||
update_whenset_FormItemInt(F("pscl2"), Settings.Pin_i2c3_scl);
|
||||
}
|
||||
Settings.I2C3_clockSpeed = getFormItemInt(F("pi2csp2"), DEFAULT_I2C_CLOCK_SPEED);
|
||||
Settings.I2C3_clockSpeed_Slow = getFormItemInt(F("pi2cspslow2"), DEFAULT_I2C_CLOCK_SPEED_SLOW);
|
||||
#if FEATURE_I2CMULTIPLEXER
|
||||
Settings.I2C3_Multiplexer_Type = getFormItemInt(F("pi2cmuxtype2"));
|
||||
if (Settings.I2C3_Multiplexer_Type != I2C_MULTIPLEXER_NONE) {
|
||||
Settings.I2C3_Multiplexer_Addr = getFormItemInt(F("pi2cmuxaddr2"));
|
||||
} else {
|
||||
Settings.I2C3_Multiplexer_Addr = -1;
|
||||
}
|
||||
Settings.I2C3_Multiplexer_ResetPin = getFormItemInt(F("pi2cmuxreset2"));
|
||||
#endif // if FEATURE_I2CMULTIPLEXER
|
||||
}
|
||||
#endif // if FEATURE_I2C_INTERFACE_3
|
||||
set3BitToUL(Settings.I2C_peripheral_bus, I2C_PERIPHERAL_BUS_PCFMCP, getFormItemInt(F("pi2cbuspcf")));
|
||||
#endif // if FEATURE_I2C_MULTIPLE
|
||||
#ifdef ESP32
|
||||
Settings.InitSPI = getFormItemInt(F("initspi0"), static_cast<int>(SPI_Options_e::None));
|
||||
// User-defined SPI bus 0 GPIO pins
|
||||
Settings.SPI_SCLK_pin = getFormItemInt(F("spipinsclk0"), -1);
|
||||
Settings.SPI_MISO_pin = getFormItemInt(F("spipinmiso0"), -1);
|
||||
Settings.SPI_MOSI_pin = getFormItemInt(F("spipinmosi0"), -1);
|
||||
|
||||
Settings.InitSPI1 = getFormItemInt(F("initspi1"), static_cast<int>(SPI_Options_e::None));
|
||||
// User-defined SPI bus 1 GPIO pins
|
||||
Settings.SPI1_SCLK_pin = getFormItemInt(F("spipinsclk1"), -1);
|
||||
Settings.SPI1_MISO_pin = getFormItemInt(F("spipinmiso1"), -1);
|
||||
Settings.SPI1_MOSI_pin = getFormItemInt(F("spipinmosi1"), -1);
|
||||
for (uint8_t spi_bus = 0; spi_bus < getSPIBusCount(); ++spi_bus) {
|
||||
if (Settings.isSPI_enabled(spi_bus) && !Settings.isSPI_valid(spi_bus)) { // Checks
|
||||
error += strformat(F("SPI bus %u pins not configured correctly!<BR>"), spi_bus);
|
||||
}
|
||||
}
|
||||
#else //for ESP8266 we keep the old UI
|
||||
Settings.InitSPI = isFormItemChecked(F("initspi")); // SPI Init
|
||||
#endif
|
||||
#if defined(ESP32) && FEATURE_SD
|
||||
Settings.setSPIBusForSDCard(getFormItemInt(F("sdspibus"), 0));
|
||||
#endif // if defined(ESP32) && FEATURE_SD
|
||||
@@ -149,12 +59,6 @@ void handle_hardware() {
|
||||
}
|
||||
error += SaveSettings();
|
||||
addHtmlError(error);
|
||||
if (error.isEmpty()) {
|
||||
// Apply I2C settings.
|
||||
initI2C();
|
||||
// Apply SPI settings
|
||||
initializeSPIBuses();
|
||||
}
|
||||
}
|
||||
|
||||
addHtml(F("<form method='post'>"));
|
||||
@@ -164,180 +68,20 @@ void handle_hardware() {
|
||||
addFormSubHeader(F("Wifi Status LED"));
|
||||
addFormPinSelect(PinSelectPurpose::Status_led, formatGpioName_output(F("LED")), F("pled"), Settings.Pin_status_led);
|
||||
addFormCheckBox(F("Inversed LED"), F("pledi"), Settings.Pin_status_led_Inversed);
|
||||
addFormNote(F("Use ’GPIO-2 (D4)’ with ’Inversed’ checked for onboard LED"));
|
||||
addFormNote(F("Use ’GPIO-2"
|
||||
#ifdef ESP8266
|
||||
" (D4)"
|
||||
#endif
|
||||
"’ with ’Inversed’ checked for onboard LED"));
|
||||
|
||||
addFormSubHeader(F("Reset Pin"));
|
||||
addFormPinSelect(PinSelectPurpose::Reset_pin, formatGpioName_input(F("Switch")), F("pres"), Settings.Pin_Reset);
|
||||
addFormNote(F("Press about 10s for factory reset"));
|
||||
|
||||
#if FEATURE_I2CMULTIPLEXER
|
||||
const __FlashStringHelper *i2c_muxtype_options[] = {
|
||||
F("- None -"),
|
||||
F("TCA9548a - 8 channel"),
|
||||
F("TCA9546a - 4 channel"),
|
||||
F("TCA9543a - 2 channel"),
|
||||
F("PCA9540 - 2 channel (experimental)")
|
||||
};
|
||||
const int i2c_muxtype_choices[] = {
|
||||
I2C_MULTIPLEXER_NONE,
|
||||
I2C_MULTIPLEXER_TCA9548A,
|
||||
I2C_MULTIPLEXER_TCA9546A,
|
||||
I2C_MULTIPLEXER_TCA9543A,
|
||||
I2C_MULTIPLEXER_PCA9540
|
||||
};
|
||||
const FormSelectorOptions muxSelector(NR_ELEMENTS(i2c_muxtype_choices),
|
||||
i2c_muxtype_options, i2c_muxtype_choices);
|
||||
|
||||
// Select the I2C address for a port multiplexer
|
||||
|
||||
String i2c_mux_options[9];
|
||||
int i2c_mux_choices[9];
|
||||
uint8_t mux_opt = 0;
|
||||
i2c_mux_options[mux_opt] = F("- None -");
|
||||
i2c_mux_choices[mux_opt] = I2C_MULTIPLEXER_NONE;
|
||||
mux_opt++;
|
||||
for (int8_t x = 0; x < 8; x++) {
|
||||
i2c_mux_options[mux_opt] = formatToHex_decimal(0x70 + x);
|
||||
if (x == 0) { // PCA9540 has a fixed address 0f 0x70
|
||||
i2c_mux_options[mux_opt] += F(" [TCA9543a/6a/8a, PCA9540]");
|
||||
} else if (x < 4) {
|
||||
i2c_mux_options[mux_opt] += F(" [TCA9543a/6a/8a]");
|
||||
} else {
|
||||
i2c_mux_options[mux_opt] += F(" [TCA9546a/8a]");
|
||||
}
|
||||
i2c_mux_choices[mux_opt] = 0x70 + x;
|
||||
mux_opt++;
|
||||
}
|
||||
const FormSelectorOptions addrSelector(mux_opt, i2c_mux_options, i2c_mux_choices);
|
||||
#endif // if FEATURE_I2CMULTIPLEXER
|
||||
|
||||
uint8_t i2cBus = 0;
|
||||
#if FEATURE_I2C_MULTIPLE
|
||||
for (uint8_t i2cBus = 0; i2cBus < getI2CBusCount(); ++i2cBus)
|
||||
#endif // if FEATURE_I2C_MULTIPLE
|
||||
{
|
||||
#if !FEATURE_I2C_MULTIPLE
|
||||
addFormSubHeader(F("I2C Bus"));
|
||||
#else // if !FEATURE_I2C_MULTIPLE
|
||||
addFormSubHeader(strformat(F("I2C Bus %u"), i2cBus));
|
||||
#endif // if !FEATURE_I2C_MULTIPLE
|
||||
#if FEATURE_PLUGIN_PRIORITY
|
||||
if (isI2CPriorityTaskActive(i2cBus)) {
|
||||
I2CShowSdaSclReadonly(Settings.getI2CSdaPin(i2cBus), Settings.getI2CSclPin(i2cBus), i2cBus);
|
||||
} else
|
||||
#endif // if FEATURE_PLUGIN_PRIORITY
|
||||
{
|
||||
addFormPinSelectI2C(formatGpioName_bidirectional(F("SDA")), strformat(F("psda%u"), i2cBus), i2cBus, Settings.getI2CSdaPin(i2cBus));
|
||||
addFormPinSelectI2C(formatGpioName_output(F("SCL")), strformat(F("pscl%u"), i2cBus), i2cBus, Settings.getI2CSclPin(i2cBus));
|
||||
}
|
||||
addFormNumericBox(F("Clock Speed"), strformat(F("pi2csp%u"), i2cBus), Settings.getI2CClockSpeed(i2cBus), 100, 3400000);
|
||||
addUnit(F("Hz"));
|
||||
addFormNote(F("Use 100 kHz for old I2C devices, 400 kHz is max for most."));
|
||||
addFormNumericBox(F("Slow device Clock Speed"), strformat(F("pi2cspslow%u"), i2cBus), Settings.getI2CClockSpeedSlow(i2cBus), 100, 3400000);
|
||||
addUnit(F("Hz"));
|
||||
|
||||
if (0 == i2cBus) { // Only support Clock-stretching on Bus 1
|
||||
addFormNumericBox(F("I2C ClockStretchLimit"), F("wirestretch"), Settings.WireClockStretchLimit, 0);
|
||||
#ifdef ESP8266
|
||||
addUnit(F("usec"));
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
addUnit(F("1/80 usec"));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FEATURE_I2CMULTIPLEXER
|
||||
#if !FEATURE_I2C_MULTIPLE
|
||||
addFormSubHeader(F("I2C Multiplexer"));
|
||||
#else // if !FEATURE_I2C_MULTIPLE
|
||||
addFormSubHeader(strformat(F("I2C Multiplexer %u"), i2cBus));
|
||||
#endif // if FEATURE_I2C_MULTIPLE
|
||||
// Select the type of multiplexer to use
|
||||
{
|
||||
muxSelector.addFormSelector(F("I2C Multiplexer type"), strformat(F("pi2cmuxtype%u"), i2cBus), Settings.getI2CMultiplexerType(i2cBus));
|
||||
addrSelector.addFormSelector(F("I2C Multiplexer address"), strformat(F("pi2cmuxaddr%u"), i2cBus), Settings.getI2CMultiplexerAddr(i2cBus));
|
||||
// addFormPinSelect(PinSelectPurpose::Generic_output, formatGpioName_output_optional(F("Reset")), strformat(F("pi2cmuxreset%u"), i2cBus), Settings.getI2CMultiplexerResetPin(i2cBus));
|
||||
const String id = strformat(F("pi2cmuxreset%u"), i2cBus);
|
||||
addRowLabel_tr_id(formatGpioName_output_optional(F("Reset")), id);
|
||||
addPinSelect(PinSelectPurpose::Generic_output, id, Settings.getI2CMultiplexerResetPin(i2cBus));
|
||||
addFormNote(F("Will be pulled low to force a reset. Reset is not available on PCA9540."));
|
||||
}
|
||||
#endif // if FEATURE_I2CMULTIPLEXER
|
||||
}
|
||||
#if FEATURE_I2C_MULTIPLE
|
||||
const uint8_t i2cMaxBusCount = (getI2CBusCount() > 1
|
||||
? ((Settings.isI2CEnabled(1) ? 1 : 0)
|
||||
# if FEATURE_I2C_INTERFACE_3
|
||||
+ (Settings.isI2CEnabled(2) ? 1 : 0)
|
||||
# endif // if FEATURE_I2C_INTERFACE_3
|
||||
)
|
||||
: 0) + (Settings.isI2CEnabled(0) ? 1 : 0);
|
||||
if (i2cMaxBusCount > 1) {
|
||||
addFormSubHeader(F("PCF & MCP Direct I/O"));
|
||||
const uint8_t i2cBus = Settings.getI2CInterfacePCFMCP();
|
||||
I2CInterfaceSelector(F("I2C Bus"),
|
||||
F("pi2cbuspcf"),
|
||||
i2cBus,
|
||||
false);
|
||||
|
||||
}
|
||||
#endif // if FEATURE_I2C_MULTIPLE
|
||||
|
||||
#ifdef ESP32
|
||||
for (uint8_t spi_bus = 0; spi_bus < getSPIBusCount(); ++spi_bus) {
|
||||
// SPI Init
|
||||
addFormSubHeader(concat(F("SPI Bus "), spi_bus));
|
||||
{
|
||||
// Script to show GPIO pins for User-defined SPI GPIOs
|
||||
// html_add_script(F("function spiOptionChanged(elem) {var spipinstyle = elem.value == 9 ? '' : 'none';document.getElementById('tr_spipinsclk').style.display = spipinstyle;document.getElementById('tr_spipinmiso').style.display = spipinstyle;document.getElementById('tr_spipinmosi').style.display = spipinstyle;}"),
|
||||
// Minified:
|
||||
html_add_script(strformat(F("function spi%uOptionChanged(e){var i=9==e.value?'':'none';"
|
||||
"document.getElementById('tr_spipinsclk%u').style.display=i,"
|
||||
"document.getElementById('tr_spipinmiso%u').style.display=i,"
|
||||
"document.getElementById('tr_spipinmosi%u').style.display=i"
|
||||
"}"), spi_bus, spi_bus, spi_bus, spi_bus, spi_bus),
|
||||
false);
|
||||
const __FlashStringHelper * spi_options[] = {
|
||||
getSPI_optionToString(SPI_Options_e::None),
|
||||
getSPI_optionToString(SPI_Options_e::Vspi_Fspi),
|
||||
#ifdef ESP32_CLASSIC
|
||||
getSPI_optionToString(SPI_Options_e::Hspi),
|
||||
#endif
|
||||
getSPI_optionToString(SPI_Options_e::UserDefined)};
|
||||
const int spi_index[] = {
|
||||
static_cast<int>(SPI_Options_e::None),
|
||||
static_cast<int>(SPI_Options_e::Vspi_Fspi),
|
||||
#ifdef ESP32_CLASSIC
|
||||
static_cast<int>(SPI_Options_e::Hspi),
|
||||
#endif
|
||||
static_cast<int>(SPI_Options_e::UserDefined)
|
||||
};
|
||||
constexpr size_t nrOptions = NR_ELEMENTS(spi_index);
|
||||
FormSelectorOptions selector(nrOptions, spi_options, spi_index);
|
||||
selector.onChangeCall = strformat(F("spi%uOptionChanged(this)"), spi_bus);
|
||||
selector.addFormSelector(concat(F("Init SPI Bus "), spi_bus), concat(F("initspi"), spi_bus), 0 == spi_bus ? Settings.InitSPI : Settings.InitSPI1);
|
||||
int8_t spi_gpio[3];
|
||||
Settings.getSPI_pins(spi_gpio, spi_bus, true); // Load GPIO pins even if wrongly configured
|
||||
// User-defined pins
|
||||
addFormPinSelect(PinSelectPurpose::SPI, formatGpioName_output(F("CLK")), concat(F("spipinsclk"), spi_bus), spi_gpio[0]);
|
||||
addFormPinSelect(PinSelectPurpose::SPI_MISO, formatGpioName_input(F("MISO")), concat(F("spipinmiso"), spi_bus), spi_gpio[1]);
|
||||
addFormPinSelect(PinSelectPurpose::SPI, formatGpioName_output(F("MOSI")), concat(F("spipinmosi"), spi_bus), spi_gpio[2]);
|
||||
html_add_script(strformat(F("document.getElementById('initspi%u').onchange();"), spi_bus), false); // Initial trigger onchange script
|
||||
// addFormNote(F("Changing SPI settings requires to press the hardware-reset button or power off-on!"));
|
||||
addFormNote(F("Chip Select (CS) config must be done in the plugin"));
|
||||
}
|
||||
}
|
||||
#else //for ESP8266 we keep the existing UI
|
||||
addFormSubHeader(F("SPI Bus 0"));
|
||||
addFormCheckBox(F("Init SPI"), F("initspi"), Settings.InitSPI > static_cast<int>(SPI_Options_e::None));
|
||||
addFormNote(F("CLK=GPIO-14 (D5), MISO=GPIO-12 (D6), MOSI=GPIO-13 (D7)"));
|
||||
addFormNote(F("Chip Select (CS) config must be done in the plugin"));
|
||||
#endif // ifdef ESP32
|
||||
|
||||
#if FEATURE_SD
|
||||
addFormSubHeader(F("SD Card"));
|
||||
#ifdef ESP32
|
||||
if (getSPIBusCount() > 1 && (Settings.isSPI_valid(0u) || Settings.isSPI_valid(1u))) {
|
||||
if (getSPIBusCount() > 1 && (Settings.getNrConfiguredSPI_buses() != 0)) {
|
||||
uint8_t spiBus = Settings.getSPIBusForSDCard();
|
||||
SPIInterfaceSelector(F("SPI Bus"),
|
||||
F("sdspibus"),
|
||||
@@ -365,26 +109,4 @@ void handle_hardware() {
|
||||
TXBuffer.endStream();
|
||||
}
|
||||
|
||||
#if FEATURE_PLUGIN_PRIORITY
|
||||
bool isI2CPriorityTaskActive(uint8_t i2cBus) {
|
||||
bool hasI2CPriorityTask = false;
|
||||
for (taskIndex_t taskIndex = 0; taskIndex < TASKS_MAX && !hasI2CPriorityTask; taskIndex++) {
|
||||
hasI2CPriorityTask |= isPluginI2CPowerManager_from_TaskIndex(taskIndex, i2cBus);
|
||||
}
|
||||
return hasI2CPriorityTask;
|
||||
}
|
||||
|
||||
void I2CShowSdaSclReadonly(int8_t i2c_sda, int8_t i2c_scl, uint8_t i2cBus) {
|
||||
int pinnr = -1;
|
||||
bool input, output, warning = false;
|
||||
addFormNote(strformat(F("I2C (%d) GPIO pins can't be changed when an I2C Priority task is configured."), i2cBus));
|
||||
addRowLabel(formatGpioName_bidirectional(F("SDA")));
|
||||
getGpioInfo(i2c_sda, pinnr, input, output, warning);
|
||||
addHtml(createGPIO_label(i2c_sda, pinnr, true, true, false));
|
||||
addRowLabel(formatGpioName_output(F("SCL")));
|
||||
getGpioInfo(i2c_scl, pinnr, input, output, warning);
|
||||
addHtml(createGPIO_label(i2c_scl, pinnr, true, true, false));
|
||||
}
|
||||
#endif // if FEATURE_PLUGIN_PRIORITY
|
||||
|
||||
#endif // ifdef WEBSERVER_HARDWARE
|
||||
|
||||
@@ -10,12 +10,6 @@
|
||||
// ********************************************************************************
|
||||
void handle_hardware();
|
||||
|
||||
# if FEATURE_PLUGIN_PRIORITY
|
||||
bool isI2CPriorityTaskActive(uint8_t i2cBus);
|
||||
void I2CShowSdaSclReadonly(int8_t i2c_sda,
|
||||
int8_t i2c_scl,
|
||||
uint8_t i2cBus);
|
||||
# endif // if FEATURE_PLUGIN_PRIORITY
|
||||
#endif // ifdef WEBSERVER_HARDWARE
|
||||
|
||||
#endif // ifndef WEBSERVER_WEBSERVER_HARDWAREPAGE_H
|
||||
|
||||
@@ -0,0 +1,412 @@
|
||||
#include "../WebServer/InterfacesPage.h"
|
||||
|
||||
#ifdef WEBSERVER_INTERFACES
|
||||
|
||||
# include "../WebServer/ESPEasy_WebServer.h"
|
||||
# include "../WebServer/HTML_wrappers.h"
|
||||
# include "../WebServer/Markup.h"
|
||||
# include "../WebServer/Markup_Buttons.h"
|
||||
# include "../WebServer/Markup_Forms.h"
|
||||
|
||||
# include "../CustomBuild/ESPEasyLimits.h"
|
||||
|
||||
# include "../DataStructs/DeviceStruct.h"
|
||||
|
||||
# include "../Globals/Settings.h"
|
||||
|
||||
# include "../Helpers/ESPEasy_Storage.h"
|
||||
# include "../Helpers/Hardware_GPIO.h"
|
||||
# include "../Helpers/Hardware_I2C.h"
|
||||
# include "../Helpers/Hardware_SPI.h"
|
||||
# include "../Helpers/SPI_Helper.h"
|
||||
# include "../Helpers/StringConverter.h"
|
||||
# include "../Helpers/StringGenerator_GPIO.h"
|
||||
|
||||
# if FEATURE_I2C_MULTIPLE
|
||||
# include "../Helpers/I2C_access.h"
|
||||
# include "../Helpers/Hardware_device_info.h"
|
||||
# endif // if FEATURE_I2C_MULTIPLE
|
||||
|
||||
|
||||
void save_interfaces() {
|
||||
|
||||
String error;
|
||||
bool updated{};
|
||||
|
||||
if (isFormItem(F("pi2csp0"))) {
|
||||
updated = true;
|
||||
# if FEATURE_PLUGIN_PRIORITY
|
||||
|
||||
if (!isI2CPriorityTaskActive(0))
|
||||
# endif // if FEATURE_PLUGIN_PRIORITY
|
||||
{
|
||||
update_whenset_FormItemInt(F("psda0"), Settings.Pin_i2c_sda);
|
||||
update_whenset_FormItemInt(F("pscl0"), Settings.Pin_i2c_scl);
|
||||
}
|
||||
Settings.I2C_clockSpeed = getFormItemInt(F("pi2csp0"), DEFAULT_I2C_CLOCK_SPEED);
|
||||
Settings.I2C_clockSpeed_Slow = getFormItemInt(F("pi2cspslow0"), DEFAULT_I2C_CLOCK_SPEED_SLOW);
|
||||
Settings.WireClockStretchLimit = getFormItemInt(F("wirestretch"));
|
||||
# if FEATURE_I2CMULTIPLEXER
|
||||
Settings.I2C_Multiplexer_Type = getFormItemInt(F("pi2cmuxtype0"));
|
||||
|
||||
if (Settings.I2C_Multiplexer_Type != I2C_MULTIPLEXER_NONE) {
|
||||
Settings.I2C_Multiplexer_Addr = getFormItemInt(F("pi2cmuxaddr0"));
|
||||
} else {
|
||||
Settings.I2C_Multiplexer_Addr = -1;
|
||||
}
|
||||
Settings.I2C_Multiplexer_ResetPin = getFormItemInt(F("pi2cmuxreset0"));
|
||||
# endif // if FEATURE_I2CMULTIPLEXER
|
||||
}
|
||||
# if FEATURE_I2C_MULTIPLE // No loop used here, to avoid adding setters to the SettingsStruct template code
|
||||
|
||||
if ((getI2CBusCount() > 1) && isFormItem(F("pi2csp1"))) {
|
||||
updated = true;
|
||||
# if FEATURE_PLUGIN_PRIORITY
|
||||
|
||||
if (!isI2CPriorityTaskActive(1))
|
||||
# endif // if FEATURE_PLUGIN_PRIORITY
|
||||
{
|
||||
update_whenset_FormItemInt(F("psda1"), Settings.Pin_i2c2_sda);
|
||||
update_whenset_FormItemInt(F("pscl1"), Settings.Pin_i2c2_scl);
|
||||
}
|
||||
Settings.I2C2_clockSpeed = getFormItemInt(F("pi2csp1"), DEFAULT_I2C_CLOCK_SPEED);
|
||||
Settings.I2C2_clockSpeed_Slow = getFormItemInt(F("pi2cspslow1"), DEFAULT_I2C_CLOCK_SPEED_SLOW);
|
||||
# if FEATURE_I2CMULTIPLEXER
|
||||
Settings.I2C2_Multiplexer_Type = getFormItemInt(F("pi2cmuxtype1"));
|
||||
|
||||
if (Settings.I2C2_Multiplexer_Type != I2C_MULTIPLEXER_NONE) {
|
||||
Settings.I2C2_Multiplexer_Addr = getFormItemInt(F("pi2cmuxaddr1"));
|
||||
} else {
|
||||
Settings.I2C2_Multiplexer_Addr = -1;
|
||||
}
|
||||
Settings.I2C2_Multiplexer_ResetPin = getFormItemInt(F("pi2cmuxreset1"));
|
||||
# endif // if FEATURE_I2CMULTIPLEXER
|
||||
}
|
||||
|
||||
|
||||
# if FEATURE_I2C_INTERFACE_3
|
||||
|
||||
if ((getI2CBusCount() > 2) && isFormItem(F("pi2csp2"))) {
|
||||
updated = true;
|
||||
# if FEATURE_PLUGIN_PRIORITY
|
||||
|
||||
if (!isI2CPriorityTaskActive(2))
|
||||
# endif // if FEATURE_PLUGIN_PRIORITY
|
||||
{
|
||||
update_whenset_FormItemInt(F("psda2"), Settings.Pin_i2c3_sda);
|
||||
update_whenset_FormItemInt(F("pscl2"), Settings.Pin_i2c3_scl);
|
||||
}
|
||||
Settings.I2C3_clockSpeed = getFormItemInt(F("pi2csp2"), DEFAULT_I2C_CLOCK_SPEED);
|
||||
Settings.I2C3_clockSpeed_Slow = getFormItemInt(F("pi2cspslow2"), DEFAULT_I2C_CLOCK_SPEED_SLOW);
|
||||
# if FEATURE_I2CMULTIPLEXER
|
||||
Settings.I2C3_Multiplexer_Type = getFormItemInt(F("pi2cmuxtype2"));
|
||||
|
||||
if (Settings.I2C3_Multiplexer_Type != I2C_MULTIPLEXER_NONE) {
|
||||
Settings.I2C3_Multiplexer_Addr = getFormItemInt(F("pi2cmuxaddr2"));
|
||||
} else {
|
||||
Settings.I2C3_Multiplexer_Addr = -1;
|
||||
}
|
||||
Settings.I2C3_Multiplexer_ResetPin = getFormItemInt(F("pi2cmuxreset2"));
|
||||
# endif // if FEATURE_I2CMULTIPLEXER
|
||||
}
|
||||
# endif // if FEATURE_I2C_INTERFACE_3
|
||||
|
||||
if (isFormItem(F("pi2cbuspcf"))) {
|
||||
updated = true;
|
||||
set3BitToUL(Settings.I2C_peripheral_bus, I2C_PERIPHERAL_BUS_PCFMCP, getFormItemInt(F("pi2cbuspcf")));
|
||||
}
|
||||
# endif // if FEATURE_I2C_MULTIPLE
|
||||
|
||||
{
|
||||
# ifdef ESP32
|
||||
bool SPI_updated{};
|
||||
|
||||
if (update_whenset_FormItemInt(F("initspi0"), Settings.InitSPI)) {
|
||||
SPI_updated = true;
|
||||
|
||||
// User-defined SPI bus 0 GPIO pins
|
||||
Settings.SPI_SCLK_pin = getFormItemInt(F("spipinsclk0"), -1);
|
||||
Settings.SPI_MISO_pin = getFormItemInt(F("spipinmiso0"), -1);
|
||||
Settings.SPI_MOSI_pin = getFormItemInt(F("spipinmosi0"), -1);
|
||||
}
|
||||
|
||||
if (update_whenset_FormItemInt(F("initspi1"), Settings.InitSPI1)) {
|
||||
SPI_updated = true;
|
||||
|
||||
// User-defined SPI bus 1 GPIO pins
|
||||
Settings.SPI1_SCLK_pin = getFormItemInt(F("spipinsclk1"), -1);
|
||||
Settings.SPI1_MISO_pin = getFormItemInt(F("spipinmiso1"), -1);
|
||||
Settings.SPI1_MOSI_pin = getFormItemInt(F("spipinmosi1"), -1);
|
||||
}
|
||||
|
||||
if (SPI_updated) {
|
||||
updated = true;
|
||||
|
||||
for (uint8_t spi_bus = 0; spi_bus < getSPIBusCount(); ++spi_bus) {
|
||||
if (Settings.isSPI_enabled(spi_bus) && !Settings.isSPI_valid(spi_bus)) { // Checks
|
||||
error += strformat(F("SPI bus %u pins not configured correctly!<BR>"), spi_bus);
|
||||
}
|
||||
}
|
||||
}
|
||||
# else // for ESP8266 we keep the old UI
|
||||
Settings.InitSPI = isFormItemChecked(F("initspi")); // SPI Init
|
||||
updated = true;
|
||||
# endif // ifdef ESP32
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
error += SaveSettings();
|
||||
addHtmlError(error);
|
||||
|
||||
if (error.isEmpty()) {
|
||||
// Apply I2C settings.
|
||||
initI2C();
|
||||
|
||||
// Apply SPI settings
|
||||
initializeSPIBuses();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ********************************************************************************
|
||||
// Web Interface hardware page
|
||||
// ********************************************************************************
|
||||
void handle_interfaces() {
|
||||
# ifndef BUILD_NO_RAM_TRACKER
|
||||
checkRAM(F("handle_interfaces"));
|
||||
# endif
|
||||
|
||||
if (!isLoggedIn()) { return; }
|
||||
navMenuIndex = MENU_INDEX_INTERFACES;
|
||||
TXBuffer.startStream();
|
||||
sendHeadandTail_stdtemplate(_HEAD);
|
||||
|
||||
save_interfaces();
|
||||
|
||||
|
||||
addHtml(F("<form method='post'>"));
|
||||
html_table_class_normal();
|
||||
addFormHeader(F("Interfaces Settings"), F(""), F("Interfaces/Interfaces.html"));
|
||||
|
||||
|
||||
# if FEATURE_I2CMULTIPLEXER
|
||||
const __FlashStringHelper *i2c_muxtype_options[] = {
|
||||
F("- None -"),
|
||||
F("TCA9548a - 8 channel"),
|
||||
F("TCA9546a - 4 channel"),
|
||||
F("TCA9543a - 2 channel"),
|
||||
F("PCA9540 - 2 channel (experimental)")
|
||||
};
|
||||
const int i2c_muxtype_choices[] = {
|
||||
I2C_MULTIPLEXER_NONE,
|
||||
I2C_MULTIPLEXER_TCA9548A,
|
||||
I2C_MULTIPLEXER_TCA9546A,
|
||||
I2C_MULTIPLEXER_TCA9543A,
|
||||
I2C_MULTIPLEXER_PCA9540
|
||||
};
|
||||
const FormSelectorOptions muxSelector(NR_ELEMENTS(i2c_muxtype_choices),
|
||||
i2c_muxtype_options, i2c_muxtype_choices);
|
||||
|
||||
// Select the I2C address for a port multiplexer
|
||||
|
||||
String i2c_mux_options[9];
|
||||
int i2c_mux_choices[9];
|
||||
uint8_t mux_opt = 0;
|
||||
i2c_mux_options[mux_opt] = F("- None -");
|
||||
i2c_mux_choices[mux_opt] = I2C_MULTIPLEXER_NONE;
|
||||
mux_opt++;
|
||||
|
||||
for (int8_t x = 0; x < 8; x++) {
|
||||
i2c_mux_options[mux_opt] = formatToHex_decimal(0x70 + x);
|
||||
|
||||
if (x == 0) { // PCA9540 has a fixed address 0f 0x70
|
||||
i2c_mux_options[mux_opt] += F(" [TCA9543a/6a/8a, PCA9540]");
|
||||
} else if (x < 4) {
|
||||
i2c_mux_options[mux_opt] += F(" [TCA9543a/6a/8a]");
|
||||
} else {
|
||||
i2c_mux_options[mux_opt] += F(" [TCA9546a/8a]");
|
||||
}
|
||||
i2c_mux_choices[mux_opt] = 0x70 + x;
|
||||
mux_opt++;
|
||||
}
|
||||
const FormSelectorOptions addrSelector(mux_opt, i2c_mux_options, i2c_mux_choices);
|
||||
# endif // if FEATURE_I2CMULTIPLEXER
|
||||
|
||||
uint8_t i2cBus = 0;
|
||||
# if FEATURE_I2C_MULTIPLE
|
||||
|
||||
for (uint8_t i2cBus = 0; i2cBus < getI2CBusCount(); ++i2cBus)
|
||||
# endif // if FEATURE_I2C_MULTIPLE
|
||||
{
|
||||
# if !FEATURE_I2C_MULTIPLE
|
||||
addFormSubHeader(F("I2C Bus"));
|
||||
# else
|
||||
addFormSubHeader(strformat(F("I2C Bus %u"), i2cBus));
|
||||
# endif // if !FEATURE_I2C_MULTIPLE
|
||||
# if FEATURE_PLUGIN_PRIORITY
|
||||
|
||||
if (isI2CPriorityTaskActive(i2cBus)) {
|
||||
I2CShowSdaSclReadonly(Settings.getI2CSdaPin(i2cBus), Settings.getI2CSclPin(i2cBus), i2cBus);
|
||||
} else
|
||||
# endif // if FEATURE_PLUGIN_PRIORITY
|
||||
{
|
||||
addFormPinSelectI2C(formatGpioName_bidirectional(F("SDA")), strformat(F("psda%u"), i2cBus), i2cBus, Settings.getI2CSdaPin(i2cBus));
|
||||
addFormPinSelectI2C(formatGpioName_output(F("SCL")), strformat(F("pscl%u"), i2cBus), i2cBus, Settings.getI2CSclPin(i2cBus));
|
||||
}
|
||||
addFormNumericBox(F("Clock Speed"), strformat(F("pi2csp%u"), i2cBus), Settings.getI2CClockSpeed(i2cBus), 100, 3400000);
|
||||
addUnit(F("Hz"));
|
||||
addFormNote(F("Use 100 kHz for old I2C devices, 400 kHz is max for most."));
|
||||
addFormNumericBox(F("Slow device Clock Speed"), strformat(F("pi2cspslow%u"), i2cBus), Settings.getI2CClockSpeedSlow(i2cBus), 100,
|
||||
3400000);
|
||||
addUnit(F("Hz"));
|
||||
|
||||
if (0 == i2cBus) { // Only support Clock-stretching on Bus 1
|
||||
addFormNumericBox(F("I2C ClockStretchLimit"), F("wirestretch"), Settings.WireClockStretchLimit, 0);
|
||||
# ifdef ESP8266
|
||||
addUnit(F("usec"));
|
||||
# endif
|
||||
# ifdef ESP32
|
||||
addUnit(F("1/80 usec"));
|
||||
# endif
|
||||
}
|
||||
|
||||
# if FEATURE_I2CMULTIPLEXER
|
||||
# if !FEATURE_I2C_MULTIPLE
|
||||
addFormSubHeader(F("I2C Multiplexer"));
|
||||
# else // if !FEATURE_I2C_MULTIPLE
|
||||
addFormSubHeader(strformat(F("I2C Multiplexer %u"), i2cBus));
|
||||
# endif // if !FEATURE_I2C_MULTIPLE
|
||||
|
||||
// Select the type of multiplexer to use
|
||||
{
|
||||
muxSelector.addFormSelector(F("I2C Multiplexer type"), strformat(F("pi2cmuxtype%u"), i2cBus), Settings.getI2CMultiplexerType(i2cBus));
|
||||
addrSelector.addFormSelector(F("I2C Multiplexer address"), strformat(F("pi2cmuxaddr%u"), i2cBus),
|
||||
Settings.getI2CMultiplexerAddr(i2cBus));
|
||||
|
||||
// addFormPinSelect(PinSelectPurpose::Generic_output, formatGpioName_output_optional(F("Reset")), strformat(F("pi2cmuxreset%u"),
|
||||
// i2cBus), Settings.getI2CMultiplexerResetPin(i2cBus));
|
||||
const String id = strformat(F("pi2cmuxreset%u"), i2cBus);
|
||||
addRowLabel_tr_id(formatGpioName_output_optional(F("Reset")), id);
|
||||
addPinSelect(PinSelectPurpose::Generic_output, id, Settings.getI2CMultiplexerResetPin(i2cBus));
|
||||
addFormNote(F("Will be pulled low to force a reset. Reset is not available on PCA9540."));
|
||||
}
|
||||
# endif // if FEATURE_I2CMULTIPLEXER
|
||||
}
|
||||
# if FEATURE_I2C_MULTIPLE
|
||||
const uint8_t i2cMaxBusCount = Settings.getNrConfiguredI2C_buses();
|
||||
|
||||
if (i2cMaxBusCount > 1) {
|
||||
addFormSubHeader(F("PCF & MCP Direct I/O"));
|
||||
const uint8_t i2cBus = Settings.getI2CInterfacePCFMCP();
|
||||
I2CInterfaceSelector(F("I2C Bus"),
|
||||
F("pi2cbuspcf"),
|
||||
i2cBus,
|
||||
false);
|
||||
|
||||
}
|
||||
# endif // if FEATURE_I2C_MULTIPLE
|
||||
|
||||
# ifdef ESP32
|
||||
|
||||
for (uint8_t spi_bus = 0; spi_bus < getSPIBusCount(); ++spi_bus) {
|
||||
// SPI Init
|
||||
addFormSubHeader(concat(F("SPI Bus "), spi_bus));
|
||||
{
|
||||
// Script to show GPIO pins for User-defined SPI GPIOs
|
||||
// html_add_script(F("function spiOptionChanged(elem) {var spipinstyle = elem.value == 9 ? '' :
|
||||
// 'none';document.getElementById('tr_spipinsclk').style.display = spipinstyle;document.getElementById('tr_spipinmiso').style.display
|
||||
// = spipinstyle;document.getElementById('tr_spipinmosi').style.display = spipinstyle;}"),
|
||||
// Minified:
|
||||
html_add_script(strformat(F("function spi%uOptionChanged(e){var i=9==e.value?'':'none';"
|
||||
"document.getElementById('tr_spipinsclk%u').style.display=i,"
|
||||
"document.getElementById('tr_spipinmiso%u').style.display=i,"
|
||||
"document.getElementById('tr_spipinmosi%u').style.display=i"
|
||||
"}"), spi_bus, spi_bus, spi_bus, spi_bus, spi_bus),
|
||||
false);
|
||||
const __FlashStringHelper *spi_options[] = {
|
||||
getSPI_optionToString(SPI_Options_e::None),
|
||||
getSPI_optionToString(SPI_Options_e::Vspi_Fspi),
|
||||
# ifdef ESP32_CLASSIC
|
||||
getSPI_optionToString(SPI_Options_e::Hspi),
|
||||
# endif
|
||||
getSPI_optionToString(SPI_Options_e::UserDefined_VSPI)
|
||||
# if SOC_SPI_PERIPH_NUM > 2
|
||||
, getSPI_optionToString(SPI_Options_e::UserDefined_HSPI)
|
||||
# endif
|
||||
};
|
||||
const int spi_index[] = {
|
||||
static_cast<int>(SPI_Options_e::None),
|
||||
static_cast<int>(SPI_Options_e::Vspi_Fspi),
|
||||
# ifdef ESP32_CLASSIC
|
||||
static_cast<int>(SPI_Options_e::Hspi),
|
||||
# endif
|
||||
static_cast<int>(SPI_Options_e::UserDefined_VSPI)
|
||||
# if SOC_SPI_PERIPH_NUM > 2
|
||||
, static_cast<int>(SPI_Options_e::UserDefined_HSPI)
|
||||
# endif
|
||||
};
|
||||
constexpr size_t nrOptions = NR_ELEMENTS(spi_index);
|
||||
FormSelectorOptions selector(nrOptions, spi_options, spi_index);
|
||||
selector.onChangeCall = strformat(F("spi%uOptionChanged(this)"), spi_bus);
|
||||
selector.addFormSelector(concat(F("Init SPI Bus "), spi_bus),
|
||||
concat(F("initspi"), spi_bus),
|
||||
0 == spi_bus ? Settings.InitSPI : Settings.InitSPI1);
|
||||
int8_t spi_gpio[3];
|
||||
Settings.getSPI_pins(spi_gpio, spi_bus, true); // Load GPIO pins even if wrongly configured
|
||||
// User-defined pins
|
||||
addFormPinSelect(PinSelectPurpose::SPI, formatGpioName_output(F("CLK")), concat(F("spipinsclk"), spi_bus), spi_gpio[0]);
|
||||
addFormPinSelect(PinSelectPurpose::SPI_MISO, formatGpioName_input(F("MISO")), concat(F("spipinmiso"), spi_bus), spi_gpio[1]);
|
||||
addFormPinSelect(PinSelectPurpose::SPI, formatGpioName_output(F("MOSI")), concat(F("spipinmosi"), spi_bus), spi_gpio[2]);
|
||||
html_add_script(strformat(F("document.getElementById('initspi%u').onchange();"), spi_bus), false); // Initial trigger onchange script
|
||||
// addFormNote(F("Changing SPI settings requires to press the hardware-reset button or power off-on!"));
|
||||
addFormNote(F("Chip Select (CS) config must be done in the plugin"));
|
||||
}
|
||||
}
|
||||
# else // for ESP8266 we keep the existing UI
|
||||
addFormSubHeader(F("SPI Bus 0"));
|
||||
addFormCheckBox(F("Init SPI"), F("initspi"), Settings.InitSPI > static_cast<int>(SPI_Options_e::None));
|
||||
addFormNote(F("CLK=GPIO-14 (D5), MISO=GPIO-12 (D6), MOSI=GPIO-13 (D7)"));
|
||||
addFormNote(F("Chip Select (CS) config must be done in the plugin"));
|
||||
# endif // ifdef ESP32
|
||||
|
||||
addFormSeparator(2);
|
||||
|
||||
html_TR_TD();
|
||||
html_TD();
|
||||
addSubmitButton();
|
||||
html_TR_TD();
|
||||
html_end_table();
|
||||
html_end_form();
|
||||
|
||||
sendHeadandTail_stdtemplate(_TAIL);
|
||||
TXBuffer.endStream();
|
||||
}
|
||||
|
||||
# if FEATURE_PLUGIN_PRIORITY
|
||||
|
||||
bool isI2CPriorityTaskActive(uint8_t i2cBus) {
|
||||
bool hasI2CPriorityTask = false;
|
||||
|
||||
for (taskIndex_t taskIndex = 0; taskIndex < TASKS_MAX && !hasI2CPriorityTask; taskIndex++) {
|
||||
hasI2CPriorityTask |= isPluginI2CPowerManager_from_TaskIndex(taskIndex, i2cBus);
|
||||
}
|
||||
return hasI2CPriorityTask;
|
||||
}
|
||||
|
||||
void I2CShowSdaSclReadonly(int8_t i2c_sda, int8_t i2c_scl, uint8_t i2cBus) {
|
||||
int pinnr = -1;
|
||||
bool input, output, warning = false;
|
||||
|
||||
addFormNote(strformat(F("I2C (%d) GPIO pins can't be changed when an I2C Priority task is configured."), i2cBus));
|
||||
addRowLabel(formatGpioName_bidirectional(F("SDA")));
|
||||
getGpioInfo(i2c_sda, pinnr, input, output, warning);
|
||||
addHtml(createGPIO_label(i2c_sda, pinnr, true, true, false));
|
||||
addRowLabel(formatGpioName_output(F("SCL")));
|
||||
getGpioInfo(i2c_scl, pinnr, input, output, warning);
|
||||
addHtml(createGPIO_label(i2c_scl, pinnr, true, true, false));
|
||||
}
|
||||
|
||||
# endif // if FEATURE_PLUGIN_PRIORITY
|
||||
|
||||
#endif // ifdef WEBSERVER_INTERFACES
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "../WebServer/common.h"
|
||||
|
||||
#ifdef WEBSERVER_INTERFACES
|
||||
|
||||
// ********************************************************************************
|
||||
// Web Interface hardware page
|
||||
// ********************************************************************************
|
||||
void handle_interfaces();
|
||||
|
||||
# if FEATURE_PLUGIN_PRIORITY
|
||||
bool isI2CPriorityTaskActive(uint8_t i2cBus);
|
||||
void I2CShowSdaSclReadonly(int8_t i2c_sda,
|
||||
int8_t i2c_scl,
|
||||
uint8_t i2cBus);
|
||||
# endif
|
||||
#endif
|
||||
@@ -247,6 +247,7 @@ void handle_json()
|
||||
LabelType::FLASH_CHIP_SPEED,
|
||||
LabelType::FLASH_IDE_MODE,
|
||||
LabelType::FS_SIZE,
|
||||
LabelType::FS_FREE,
|
||||
|
||||
LabelType::SUNRISE,
|
||||
LabelType::SUNSET,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "../WebServer/JSON.h"
|
||||
#include "../WebServer/Markup.h"
|
||||
#include "../WebServer/Markup_Buttons.h"
|
||||
#include "../WebServer/Markup_Forms.h"
|
||||
|
||||
#include "../DataStructs/LogBuffer.h"
|
||||
#include "../DataStructs/TimingStats.h"
|
||||
@@ -35,6 +36,7 @@ void handle_log() {
|
||||
"</TR></table><div id='current_loglevel' style='font-weight: bold;'>Logging: </div><div class='logviewer' id='copyText_1'></div>"));
|
||||
addHtml(F("Autoscroll: "));
|
||||
addCheckBox(F("autoscroll"), true);
|
||||
addFormTextBox(F("Filter"), F("logfilter"), "", 30);
|
||||
addHtml(F("<BR></body>"));
|
||||
|
||||
serve_JS(JSfiles_e::FetchAndParseLog);
|
||||
|
||||
@@ -660,6 +660,16 @@ bool getCheckWebserverArg_int(const String& key, int& value) {
|
||||
return res;
|
||||
}
|
||||
|
||||
bool getCheckWebserverArg_int(const String& key,
|
||||
uint32_t & value) {
|
||||
const String valueStr = webArg(key);
|
||||
if (valueStr.isEmpty()) return false;
|
||||
uint32_t tmp{};
|
||||
const bool res = validUIntFromString(valueStr, tmp);
|
||||
value = tmp;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool update_whenset_FormItemInt(const __FlashStringHelper * key,
|
||||
int & value)
|
||||
{
|
||||
@@ -676,6 +686,25 @@ bool update_whenset_FormItemInt(const String& key, int& value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool update_whenset_FormItemInt(const __FlashStringHelper * key,
|
||||
uint32_t & value)
|
||||
{
|
||||
return update_whenset_FormItemInt(String(key), value);
|
||||
}
|
||||
|
||||
bool update_whenset_FormItemInt(const String& key,
|
||||
uint32_t & value)
|
||||
{
|
||||
uint32_t tmpVal;
|
||||
|
||||
if (getCheckWebserverArg_int(key, tmpVal)) {
|
||||
value = tmpVal;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool update_whenset_FormItemInt(const __FlashStringHelper * key,
|
||||
int8_t& value)
|
||||
{
|
||||
|
||||
@@ -318,12 +318,21 @@ int getFormItemInt(const String& key, int defaultValue);
|
||||
bool getCheckWebserverArg_int(const String& key,
|
||||
int & value);
|
||||
|
||||
bool getCheckWebserverArg_int(const String& key,
|
||||
uint32_t & value);
|
||||
|
||||
bool update_whenset_FormItemInt(const __FlashStringHelper * key,
|
||||
int & value);
|
||||
|
||||
bool update_whenset_FormItemInt(const String& key,
|
||||
int & value);
|
||||
|
||||
bool update_whenset_FormItemInt(const __FlashStringHelper * key,
|
||||
uint32_t & value);
|
||||
|
||||
bool update_whenset_FormItemInt(const String& key,
|
||||
uint32_t & value);
|
||||
|
||||
bool update_whenset_FormItemInt(const __FlashStringHelper * key,
|
||||
int8_t & value);
|
||||
|
||||
|
||||
@@ -640,6 +640,7 @@ void handle_sysinfo_Storage() {
|
||||
LabelType::OTA_2STEP,
|
||||
# endif // ifdef ESP8266
|
||||
LabelType::FS_SIZE,
|
||||
LabelType::FS_FREE,
|
||||
|
||||
LabelType::MAX_LABEL
|
||||
};
|
||||
|
||||
@@ -55,6 +55,14 @@
|
||||
#endif
|
||||
#endif // ifndef MENU_INDEX_HARDWARE_VISIBLE
|
||||
|
||||
#ifndef MENU_INDEX_INTERFACES_VISIBLE
|
||||
#ifdef WEBSERVER_INTERFACES
|
||||
# define MENU_INDEX_INTERFACES_VISIBLE true
|
||||
#else
|
||||
# define MENU_INDEX_INTERFACES_VISIBLE false
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MENU_INDEX_DEVICES_VISIBLE
|
||||
#ifdef WEBSERVER_DEVICES
|
||||
# define MENU_INDEX_DEVICES_VISIBLE true
|
||||
@@ -107,6 +115,7 @@ const __FlashStringHelper* getGpMenuIcon(uint8_t index) {
|
||||
case MENU_INDEX_NETWORK: return ICON("🌐"); // Alternative 🖧 (not working on Apple)
|
||||
case MENU_INDEX_CONTROLLERS: return ICON("✆");
|
||||
case MENU_INDEX_HARDWARE: return ICON("☷");
|
||||
case MENU_INDEX_INTERFACES: return ICON("❉");
|
||||
case MENU_INDEX_DEVICES: return ICON("❖");
|
||||
case MENU_INDEX_RULES: return ICON("⧴");
|
||||
case MENU_INDEX_NOTIFICATIONS: return ICON("✉");
|
||||
@@ -122,6 +131,7 @@ const __FlashStringHelper* getGpMenuLabel(uint8_t index) {
|
||||
case MENU_INDEX_NETWORK: return F("Network");
|
||||
case MENU_INDEX_CONTROLLERS: return F("Controllers");
|
||||
case MENU_INDEX_HARDWARE: return F("Hardware");
|
||||
case MENU_INDEX_INTERFACES:return F("Interfaces");
|
||||
case MENU_INDEX_DEVICES: return F("Devices");
|
||||
case MENU_INDEX_RULES: return F("Rules");
|
||||
case MENU_INDEX_NOTIFICATIONS: return F("Notifications");
|
||||
@@ -137,6 +147,7 @@ const __FlashStringHelper* getGpMenuURL(uint8_t index) {
|
||||
case MENU_INDEX_NETWORK: return F("/network");
|
||||
case MENU_INDEX_CONTROLLERS: return F("/controllers");
|
||||
case MENU_INDEX_HARDWARE: return F("/hardware");
|
||||
case MENU_INDEX_INTERFACES: return F("/interfaces");
|
||||
case MENU_INDEX_DEVICES: return F("/devices");
|
||||
case MENU_INDEX_RULES: return F("/rules");
|
||||
case MENU_INDEX_NOTIFICATIONS: return F("/notifications");
|
||||
@@ -152,6 +163,7 @@ bool GpMenuVisible(uint8_t index) {
|
||||
case MENU_INDEX_NETWORK: return MENU_INDEX_NETWORK_VISIBLE;
|
||||
case MENU_INDEX_CONTROLLERS: return MENU_INDEX_CONTROLLERS_VISIBLE;
|
||||
case MENU_INDEX_HARDWARE: return MENU_INDEX_HARDWARE_VISIBLE;
|
||||
case MENU_INDEX_INTERFACES: return MENU_INDEX_INTERFACES_VISIBLE;
|
||||
case MENU_INDEX_DEVICES: return MENU_INDEX_DEVICES_VISIBLE;
|
||||
case MENU_INDEX_RULES: return MENU_INDEX_RULES_VISIBLE;
|
||||
case MENU_INDEX_NOTIFICATIONS: return MENU_INDEX_NOTIFICATIONS_VISIBLE;
|
||||
|
||||
@@ -12,13 +12,14 @@
|
||||
#define MENU_INDEX_MAIN 0
|
||||
#define MENU_INDEX_CONFIG 1
|
||||
#define MENU_INDEX_HARDWARE 2
|
||||
#define MENU_INDEX_NETWORK 3
|
||||
#define MENU_INDEX_CONTROLLERS 4
|
||||
#define MENU_INDEX_BUSES 5
|
||||
#define MENU_INDEX_DEVICES 6
|
||||
#define MENU_INDEX_RULES 7
|
||||
#define MENU_INDEX_NOTIFICATIONS 8
|
||||
#define MENU_INDEX_TOOLS 9
|
||||
#define MENU_INDEX_INTERFACES 3
|
||||
#define MENU_INDEX_NETWORK 4
|
||||
#define MENU_INDEX_CONTROLLERS 5
|
||||
#define MENU_INDEX_BUSES 6
|
||||
#define MENU_INDEX_DEVICES 7
|
||||
#define MENU_INDEX_RULES 8
|
||||
#define MENU_INDEX_NOTIFICATIONS 9
|
||||
#define MENU_INDEX_TOOLS 10
|
||||
#define MENU_INDEX_SETUP 254
|
||||
#define MENU_INDEX_CUSTOM_PAGE 255
|
||||
|
||||
|
||||
@@ -457,7 +457,7 @@ textarea,
|
||||
display: flex;
|
||||
position: inherit;
|
||||
top: 54px;
|
||||
max-width: 960px;
|
||||
max-width: 1180px;
|
||||
}
|
||||
|
||||
a.menu {
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+206
-117
@@ -1,124 +1,213 @@
|
||||
//---------------no need to be included into WebStaticData.h---------------------------------------------
|
||||
// if no filter input exists, create it
|
||||
document.getElementById("logfilter") ||
|
||||
(document.querySelector("section").innerHTML +=
|
||||
'<label>Filter: <input id="logfilter" size="35"></label>');
|
||||
//------------------------------------------------------------
|
||||
function elId(e) {
|
||||
return document.getElementById(e);
|
||||
return document.getElementById(e);
|
||||
}
|
||||
function getBrowser() {
|
||||
var ua = navigator.userAgent,
|
||||
tem, M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
|
||||
if (/trident/i.test(M[1])) {
|
||||
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
|
||||
return {
|
||||
name: 'IE',
|
||||
version: (tem[1] || '')
|
||||
};
|
||||
}
|
||||
if (M[1] === 'Chrome') {
|
||||
tem = ua.match(/\bOPR|Edge\/(\d+)/);
|
||||
if (tem != null) {
|
||||
return {
|
||||
name: 'Opera',
|
||||
version: tem[1]
|
||||
};
|
||||
}
|
||||
}
|
||||
M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
|
||||
if ((tem = ua.match(/version\/(\d+)/i)) != null) {
|
||||
M.splice(1, 1, tem[1]);
|
||||
}
|
||||
return {
|
||||
name: M[0],
|
||||
version: M[1]
|
||||
};
|
||||
}
|
||||
var browser = getBrowser();
|
||||
var currentBrowser = browser.name + browser.version;
|
||||
if (browser.name = 'IE' && browser.version < 12) {
|
||||
textToDisplay = 'Error: ' + currentBrowser + ' is not supported! Please try a modern web browser.'
|
||||
} else {
|
||||
textToDisplay = 'Fetching log entries...';
|
||||
}
|
||||
elId('copyText_1').innerHTML = textToDisplay;
|
||||
loopDeLoop(1000, 0);
|
||||
var logLevel = new Array('Unused', 'Error', 'Info', 'Debug', 'Debug More', 'Undefined', 'Undefined', 'Undefined', 'Undefined', 'Debug Dev');
|
||||
|
||||
function loopDeLoop(timeForNext, activeRequests) {
|
||||
var maximumRequests = 1;
|
||||
const ct1 = elId('copyText_1');
|
||||
|
||||
if (!window.fetch) {
|
||||
ct1.textContent = 'Error: This browser is not supported. Please use a modern browser.';
|
||||
} else {
|
||||
ct1.textContent = 'Fetching log entries...';
|
||||
}
|
||||
|
||||
const logLevel = {
|
||||
0: 'Unused',
|
||||
1: 'Error',
|
||||
2: 'Info',
|
||||
3: 'Debug',
|
||||
4: 'Debug More',
|
||||
9: 'Debug Dev'
|
||||
};
|
||||
|
||||
loopDeLoop(1000);
|
||||
|
||||
function loopDeLoop(timeForNext = 1000) {
|
||||
const url = '/logjson';
|
||||
const ct1 = 'copyText_1';
|
||||
if (isNaN(activeRequests)) {
|
||||
activeRequests = maximumRequests;
|
||||
}
|
||||
if (timeForNext == null) {
|
||||
timeForNext = 1000;
|
||||
}
|
||||
if (timeForNext <= 500) {
|
||||
scrolling_type = 'auto';
|
||||
} else {
|
||||
scrolling_type = 'smooth';
|
||||
}
|
||||
var c;
|
||||
var logEntriesChunk;
|
||||
var currentIDtoScrollTo = '';
|
||||
var check = 0;
|
||||
var i = setInterval(function() {
|
||||
if (check > 0) {
|
||||
clearInterval(i);
|
||||
return;
|
||||
}
|
||||
++activeRequests;
|
||||
if (activeRequests > maximumRequests) {
|
||||
check = 1;
|
||||
} else {
|
||||
fetch(url).then(function(response) {
|
||||
if (response.status !== 200) {
|
||||
console.log('Looks like there was a problem. Status Code: ' + response.status);
|
||||
return;
|
||||
|
||||
setTimeout(function () {
|
||||
fetch(url)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(response.status);
|
||||
}
|
||||
response.json().then(function(data) {
|
||||
var logEntry;
|
||||
if (logEntriesChunk == null) {
|
||||
logEntriesChunk = '';
|
||||
}
|
||||
for (c = 0; c < data.Log.nrEntries; ++c) {
|
||||
try {
|
||||
logEntry = data.Log.Entries[c].timestamp;
|
||||
} catch (err) {
|
||||
logEntry = err.name;
|
||||
} finally {
|
||||
if (logEntry !== "TypeError") {
|
||||
currentIDtoScrollTo = data.Log.Entries[c].timestamp;
|
||||
logEntriesChunk += '<div class=level_' + data.Log.Entries[c].level + ' id=' + currentIDtoScrollTo + '><font color="gray">' + data.Log.Entries[c].timestamp + ':</font> ' + data.Log.Entries[c].text + '</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
timeForNext = data.Log.TTL;
|
||||
if (logEntriesChunk !== '') {
|
||||
if (elId(ct1).innerHTML == 'Fetching log entries...') {
|
||||
elId(ct1).innerHTML = '';
|
||||
}
|
||||
elId(ct1).innerHTML += logEntriesChunk;
|
||||
}
|
||||
logEntriesChunk = '';
|
||||
autoscroll_on = elId('autoscroll').checked;
|
||||
if (autoscroll_on == true && currentIDtoScrollTo !== '') {
|
||||
elId(currentIDtoScrollTo).scrollIntoView({
|
||||
behavior: scrolling_type
|
||||
});
|
||||
}
|
||||
elId('current_loglevel').innerHTML = 'Logging: ' + logLevel[data.Log.SettingsWebLogLevel] + ' (' + data.Log.SettingsWebLogLevel + ')';
|
||||
clearInterval(i);
|
||||
loopDeLoop(timeForNext, 0);
|
||||
return;
|
||||
})
|
||||
}).catch(function(err) {
|
||||
elId(ct1).innerHTML += '<div>>> ' + err.message + ' <<</div>';
|
||||
autoscroll_on = elId('autoscroll').checked;
|
||||
elId(ct1).scrollTop = elId(ct1).scrollHeight;
|
||||
timeForNext = 5000;
|
||||
clearInterval(i);
|
||||
loopDeLoop(timeForNext, 0);
|
||||
return;
|
||||
return response.json();
|
||||
})
|
||||
};
|
||||
check = 1;
|
||||
.then(data => {
|
||||
let logEntriesChunk = '';
|
||||
|
||||
for (let c = 0; c < data.Log.nrEntries; c++) {
|
||||
const entry = data.Log.Entries[c];
|
||||
if (!entry || !entry.timestamp) continue;
|
||||
|
||||
logEntriesChunk +=
|
||||
`<div class="level_${entry.level}">
|
||||
<font color="gray">${entry.timestamp}:</font> ${entry.text}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
timeForNext = data.Log.TTL || timeForNext;
|
||||
|
||||
if (logEntriesChunk) {
|
||||
if (ct1.textContent === 'Fetching log entries...') {
|
||||
ct1.innerHTML = '';
|
||||
}
|
||||
ct1.innerHTML += logEntriesChunk;
|
||||
}
|
||||
|
||||
applyLogFilter();
|
||||
|
||||
if (elId('autoscroll')?.checked) {
|
||||
ct1.scrollTo({
|
||||
top: ct1.scrollHeight,
|
||||
behavior: timeForNext <= 500 ? 'auto' : 'smooth'
|
||||
});
|
||||
}
|
||||
|
||||
const level = data.Log.SettingsWebLogLevel;
|
||||
const levelName = logLevel[level] ?? 'Undefined';
|
||||
|
||||
elId('current_loglevel').textContent =
|
||||
`Logging: ${levelName} (${level})`;
|
||||
|
||||
loopDeLoop(timeForNext);
|
||||
})
|
||||
.catch(err => {
|
||||
ct1.innerHTML += `<div>>> ${err.message} <<</div>`;
|
||||
ct1.scrollTop = ct1.scrollHeight;
|
||||
loopDeLoop(5000);
|
||||
});
|
||||
}, timeForNext);
|
||||
}
|
||||
}
|
||||
|
||||
function applyLogFilter() {
|
||||
const filterGroups = elId('logfilter').value
|
||||
.split(';').map(s => s.trim()).filter(Boolean);
|
||||
|
||||
const entries = document.querySelectorAll('#copyText_1 > div');
|
||||
const hasPositiveFilter = filterGroups.some(g => !g.startsWith('!'));
|
||||
|
||||
for (const entry of entries) {
|
||||
if (!entry.dataset.originalHtml) entry.dataset.originalHtml = entry.innerHTML;
|
||||
let html = entry.dataset.originalHtml;
|
||||
|
||||
const textLower = entry.textContent.toLowerCase();
|
||||
let matched = [];
|
||||
let hiddenByExclusion = false;
|
||||
|
||||
let isMatch = !hasPositiveFilter;
|
||||
|
||||
for (const group of filterGroups) {
|
||||
|
||||
// exclusion rule with ordered AND
|
||||
if (group.startsWith('!')) {
|
||||
const g = group.slice(1);
|
||||
|
||||
if (g.includes('&') && !g.startsWith('&') && !g.endsWith('&')) {
|
||||
const parts = g.split('&').map(s => s.trim()).filter(Boolean);
|
||||
let lastIndex = -1;
|
||||
let ok = true;
|
||||
|
||||
for (const p of parts) {
|
||||
const idx = textLower.indexOf(p.toLowerCase(), lastIndex + 1);
|
||||
if (idx === -1) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
lastIndex = idx;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
hiddenByExclusion = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (g && textLower.includes(g.toLowerCase())) {
|
||||
hiddenByExclusion = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// ordered AND: a&b&c
|
||||
if (group.includes('&') && !group.startsWith('&') && !group.endsWith('&')) {
|
||||
const parts = group.split('&').map(s => s.trim()).filter(Boolean);
|
||||
if (parts.length >= 2) {
|
||||
let lastIndex = -1;
|
||||
let ok = true;
|
||||
|
||||
for (const p of parts) {
|
||||
const idx = textLower.indexOf(p.toLowerCase(), lastIndex + 1);
|
||||
if (idx === -1) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
lastIndex = idx;
|
||||
}
|
||||
if (ok) {
|
||||
matched.push(...parts);
|
||||
isMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// normal include
|
||||
if (textLower.includes(group.toLowerCase())) {
|
||||
matched.push(group);
|
||||
isMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hiddenByExclusion || !isMatch) {
|
||||
entry.style.display = 'none';
|
||||
continue;
|
||||
}
|
||||
entry.style.display = '';
|
||||
entry.innerHTML = highlightOutsideTags(html, matched);
|
||||
}
|
||||
}
|
||||
|
||||
function highlightOutsideTags(html, terms) {
|
||||
if (!terms.length) return html;
|
||||
let result = '';
|
||||
let insideTag = false;
|
||||
let i = 0;
|
||||
|
||||
while (i < html.length) {
|
||||
const char = html[i];
|
||||
if (char === '<') insideTag = true;
|
||||
if (char === '>') {
|
||||
insideTag = false;
|
||||
result += char;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!insideTag) {
|
||||
let matched = false;
|
||||
for (const term of terms) {
|
||||
const slice = html.slice(i, i + term.length);
|
||||
if (slice.toLowerCase() === term.toLowerCase()) {
|
||||
result += `<span style="background-color: #bb9300;color: black;">${slice}</span>`;
|
||||
i += term.length;
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matched) continue;
|
||||
}
|
||||
result += char;
|
||||
i++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const input = document.getElementById("logfilter");
|
||||
input && (input.placeholder = '"!"=exclude ";"=or "&"=and (e.g. !act)');
|
||||
@@ -11,7 +11,16 @@ function setGithubClipboard() {
|
||||
if (i % 2 == 0) {
|
||||
separatorSymbol += '\n'
|
||||
}
|
||||
clipboard += test.innerHTML.replace(/<[Bb][Rr]\s*\/?>/gim, '\n') + separatorSymbol;
|
||||
// collect only visible log entry divs
|
||||
const visibleLines = Array.from(test.children)
|
||||
.filter(div => div.offsetParent !== null) // visible only
|
||||
.map(div => div.innerHTML);
|
||||
|
||||
if (visibleLines.length > 0) {
|
||||
clipboard +=
|
||||
visibleLines.join('\n').replace(/<[Bb][Rr]\s*\/?>/gim, '\n') +
|
||||
separatorSymbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
clipboard = clipboard.replace(/<\/[Dd][Ii][Vv]\s*\/?>/gim, '\n');
|
||||
|
||||
@@ -1,88 +1,64 @@
|
||||
loopDeLoop(1000, 0);
|
||||
loopDeLoop(1000);
|
||||
|
||||
function elId(e) {
|
||||
return document.getElementById(e);
|
||||
return document.getElementById(e);
|
||||
}
|
||||
|
||||
function loopDeLoop(timeForNext, activeRequests) {
|
||||
var maximumRequests = 1;
|
||||
var c;
|
||||
var k;
|
||||
var err = '';
|
||||
var url = '/json?view=sensorupdate';
|
||||
var check = 0;
|
||||
if (isNaN(activeRequests)) {
|
||||
activeRequests = maximumRequests;
|
||||
}
|
||||
if (timeForNext == null) {
|
||||
timeForNext = 1000;
|
||||
}
|
||||
i = setInterval(function() {
|
||||
if (check > 0) {
|
||||
clearInterval(i);
|
||||
return;
|
||||
}
|
||||
++activeRequests;
|
||||
if (activeRequests > maximumRequests) {
|
||||
check = 1;
|
||||
} else {
|
||||
fetch(url).then(function(response) {
|
||||
var valueEntry;
|
||||
if (response.status !== 200) {
|
||||
console.log('Looks like there was a problem. Status Code: ' + response.status);
|
||||
return;
|
||||
const SENSOR_URL = '/json?view=sensorupdate';
|
||||
|
||||
function loopDeLoop(timeForNext = 1000) {
|
||||
setTimeout(function () {
|
||||
fetch(SENSOR_URL)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(response.status);
|
||||
}
|
||||
response.json().then(function(data) {
|
||||
timeForNext = data.TTL;
|
||||
var showUoM = data.ShowUoM === undefined || (data.ShowUoM && data.ShowUoM !== 'false');
|
||||
for (c = 0; c < data.Sensors.length; c++) {
|
||||
if (data.Sensors[c].hasOwnProperty('TaskValues')) {
|
||||
for (k = 0; k < data.Sensors[c].TaskValues.length; k++) {
|
||||
try {
|
||||
valueEntry = data.Sensors[c].TaskValues[k].Value;
|
||||
} catch (err) {
|
||||
valueEntry = err.name;
|
||||
} finally {
|
||||
if (valueEntry !== 'TypeError') {
|
||||
var tempValue = data.Sensors[c].TaskValues[k].Value;
|
||||
var decimalsValue = data.Sensors[c].TaskValues[k].NrDecimals;
|
||||
if (decimalsValue < 255) {
|
||||
tempValue = parseFloat(tempValue).toFixed(decimalsValue);
|
||||
}
|
||||
var tempUoM = data.Sensors[c].TaskValues[k].UoM;
|
||||
var tempPres = data.Sensors[c].TaskValues[k].Presentation;
|
||||
if (tempPres) {
|
||||
tempValue = tempPres;
|
||||
} else
|
||||
if (tempUoM && showUoM) {
|
||||
tempValue += ' ' + tempUoM;
|
||||
}
|
||||
var valueID = 'value_' + (data.Sensors[c].TaskNumber - 1) + '_' + (data.Sensors[c].TaskValues[k].ValueNumber - 1);
|
||||
var valueNameID = 'valuename_' + (data.Sensors[c].TaskNumber - 1) + '_' + (data.Sensors[c].TaskValues[k].ValueNumber - 1);
|
||||
var valueElement = elId(valueID);
|
||||
var valueNameElement = elId(valueNameID);
|
||||
if (valueElement) {
|
||||
valueElement.innerHTML = tempValue;
|
||||
}
|
||||
if (valueNameElement) {
|
||||
valueNameElement.innerHTML = data.Sensors[c].TaskValues[k].Name + ':';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
timeForNext = data.TTL || timeForNext;
|
||||
const showUoM = data.ShowUoM === undefined || (data.ShowUoM && data.ShowUoM !== 'false');
|
||||
|
||||
for (let c = 0; c < data.Sensors.length; c++) {
|
||||
const sensor = data.Sensors[c];
|
||||
if (!sensor.TaskValues) continue;
|
||||
|
||||
for (let k = 0; k < sensor.TaskValues.length; k++) {
|
||||
const taskValue = sensor.TaskValues[k];
|
||||
if (!taskValue || taskValue.Value == null) continue;
|
||||
|
||||
let tempValue = taskValue.Value;
|
||||
const decimals = taskValue.NrDecimals;
|
||||
|
||||
if (decimals < 255) {
|
||||
tempValue = parseFloat(tempValue).toFixed(decimals);
|
||||
}
|
||||
|
||||
if (taskValue.Presentation) {
|
||||
tempValue = taskValue.Presentation;
|
||||
} else if (taskValue.UoM && showUoM) {
|
||||
tempValue += ' ' + taskValue.UoM;
|
||||
}
|
||||
|
||||
const baseId = (sensor.TaskNumber - 1) + '_' + (taskValue.ValueNumber - 1);
|
||||
|
||||
const valueEl = elId('value_' + baseId);
|
||||
if (valueEl) {
|
||||
valueEl.innerHTML = tempValue;
|
||||
}
|
||||
|
||||
const nameEl = elId('valuename_' + baseId);
|
||||
if (nameEl) {
|
||||
nameEl.innerHTML = taskValue.Name + ':';
|
||||
}
|
||||
}
|
||||
clearInterval(i);
|
||||
loopDeLoop(timeForNext, 0);
|
||||
return;
|
||||
});
|
||||
}).catch(function(err) {
|
||||
}
|
||||
|
||||
loopDeLoop(timeForNext);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err.message);
|
||||
timeForNext = 5000;
|
||||
clearInterval(i);
|
||||
loopDeLoop(timeForNext, 0);
|
||||
return;
|
||||
loopDeLoop(5000);
|
||||
});
|
||||
check = 1;
|
||||
}
|
||||
}, timeForNext);
|
||||
}
|
||||
@@ -2,7 +2,6 @@ import argparse
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import collections
|
||||
|
||||
manifest_binfiles = {}
|
||||
|
||||
@@ -35,14 +34,14 @@ def create_display_text(description, version, families):
|
||||
esp32_split.append('C3')
|
||||
if 'ESP32-C5' in families:
|
||||
esp32_split.append('C5')
|
||||
if 'ESP32-C6' in families:
|
||||
esp32_split.append('C6')
|
||||
if 'ESP32-C61' in families:
|
||||
esp32_split.append('C61')
|
||||
elif 'ESP32-C6' in families:
|
||||
esp32_split.append('C6')
|
||||
if 'ESP32-H2' in families:
|
||||
esp32_split.append('H2')
|
||||
if 'ESP32-H21' in families:
|
||||
esp32_split.append('H21')
|
||||
elif 'ESP32-H2' in families:
|
||||
esp32_split.append('H2')
|
||||
if 'ESP32-P4' in families:
|
||||
esp32_split.append('P4')
|
||||
|
||||
@@ -383,7 +382,7 @@ def generate_manifest_files(bin_folder, output_prefix):
|
||||
' </style>\n',
|
||||
' <script\n',
|
||||
' type="module"\n',
|
||||
' src="https://unpkg.com/tasmota-esp-web-tools@10.0.3/dist/web/install-button.js?module"\n',
|
||||
' src="https://unpkg.com/tasmota-esp-web-tools@11.1.2/dist/web/install-button.js?module"\n',
|
||||
' ></script>\n',
|
||||
' </head>\n',
|
||||
' <body>\n',
|
||||
|
||||
Reference in New Issue
Block a user