diff --git a/platformio.ini b/platformio.ini index d238b747c..198d52911 100644 --- a/platformio.ini +++ b/platformio.ini @@ -106,7 +106,7 @@ board_build.filesystem = littlefs lib_deps = bblanchon/ArduinoJson @ 7.4.2 ESP32Async/AsyncTCP @ 3.4.9 - ESP32Async/ESPAsyncWebServer @ 3.8.1 + ESP32Async/ESPAsyncWebServer @ 3.9.0 https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8 diff --git a/src/core/analogsensor.cpp b/src/core/analogsensor.cpp index c385258aa..8345e6b2c 100644 --- a/src/core/analogsensor.cpp +++ b/src/core/analogsensor.cpp @@ -187,8 +187,8 @@ void AnalogSensor::reload(bool get_nvs) { for (auto & sensor : sensors_) { sensor.ha_registered = false; // force HA configs to be re-created - // first check if the GPIO is valid. If not, force set it to disabled - if (!System::is_valid_gpio(sensor.gpio())) { + // first check if the GPIO is valid. If not, force set the sensor to disabled, but don't remove it + if (!EMSESP::system_.is_valid_gpio(sensor.gpio())) { LOG_WARNING("Bad GPIO %d for Sensor %s. Disabling.", sensor.gpio(), sensor.name().c_str()); sensor.set_type(AnalogType::NOTUSED); // set disabled continue; // skip this loop pass @@ -542,7 +542,7 @@ bool AnalogSensor::update(uint8_t gpio, std::string & name, double offset, doubl // return false if it's an invalid GPIO, an error will show in WebUI // and reported as an error in the log - return System::is_valid_gpio(gpio); + return EMSESP::system_.is_valid_gpio(gpio); } // check to see if values have been updated diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index a01b8907b..0b4f90ec8 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -255,7 +255,7 @@ void EMSESP::uart_init() { EMSuart::stop(); // don't start UART if we have invalid GPIOs - if (System::is_valid_gpio(rx_gpio) && System::is_valid_gpio(tx_gpio)) { + if (EMSESP::system_.is_valid_gpio(rx_gpio) && EMSESP::system_.is_valid_gpio(tx_gpio)) { EMSuart::start(tx_mode, rx_gpio, tx_gpio); // start UART } else { LOG_WARNING("Invalid UART Rx/Tx GPIOs. Check config."); diff --git a/src/core/system.cpp b/src/core/system.cpp index 4064ca4cd..85182a611 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -448,31 +448,9 @@ void System::reload_settings() { }); } -// check for valid ESP32 pins. This is very dependent on which ESP32 board is being used. -// Typically you can't use 1, 6-11, 20, 24, 28-31 and 40+ -// we allow 0 as it has a special function on the NodeMCU apparently -// See https://diyprojects.io/esp32-how-to-use-gpio-digital-io-arduino-code/#.YFpVEq9KhjG -// and https://nodemcu.readthedocs.io/en/dev-esp32/modules/gpio/ -bool System::is_valid_gpio(uint8_t pin, bool has_psram) { -#if CONFIG_IDF_TARGET_ESP32 || defined(EMSESP_STANDALONE) - if ((pin == 1) || (pin >= 6 && pin <= 11) || (pin == 20) || (pin == 24) || (pin >= 28 && pin <= 31) || (pin > 40) - || ((EMSESP::system_.PSram() > 0 || has_psram) && pin >= 16 && pin <= 17)) { -#elif CONFIG_IDF_TARGET_ESP32S2 - if ((pin >= 19 && pin <= 20) || (pin >= 22 && pin <= 32) || (pin > 40)) { -#elif CONFIG_IDF_TARGET_ESP32C3 - // https://www.wemos.cc/en/latest/c3/c3_mini.html - if ((pin >= 11 && pin <= 19) || (pin > 21)) { -#elif CONFIG_IDF_TARGET_ESP32S3 - if ((pin >= 19 && pin <= 20) || (pin >= 22 && pin <= 37) || (pin >= 39 && pin <= 42) || (pin > 48)) { -#endif - return false; // bad pin - } - - // extra check for pins 21 and 22 (I2C) when ethernet is onboard - if ((EMSESP::system_.ethernet_connected() || EMSESP::system_.phy_type_ != PHY_type::PHY_TYPE_NONE) && (pin >= 21 && pin <= 22)) { - return false; // bad pin - } - return true; +// check for valid ESP32 pins +bool System::is_valid_gpio(uint8_t pin) { + return std::find(valid_gpio_list().begin(), valid_gpio_list().end(), pin) != valid_gpio_list().end(); } // Starts up the UART Serial bridge @@ -2320,30 +2298,60 @@ uint8_t System::systemStatus() { return systemStatus_; } +// take a string range like "6-11, 1, 23, 24-48" which has optional ranges and single values convert to a vector of ints +std::vector System::string_range_to_vector(const std::string & range) { + std::vector valid_gpios; + std::string::size_type pos = 0; + std::string::size_type prev = 0; + while ((pos = range.find(',', prev)) != std::string::npos) { + valid_gpios.push_back(std::stoi(range.substr(prev, pos - prev))); + prev = pos + 1; + } + valid_gpios.push_back(std::stoi(range.substr(prev))); + return valid_gpios; +} + // return the list of valid GPIOs -std::vector System::valid_gpio_list() const { - // get free gpios based on board type +// note: we do not allow 0, which is used sometimes to indicate a disabled pin +std::vector System::valid_gpio_list() { + // get free gpios based on board/platform type #if CONFIG_IDF_TARGET_ESP32C3 - std::vector valid_gpios = {11, 19, 21}; + // https://www.wemos.cc/en/latest/c3/c3_mini.html + std::vector valid_gpios = string_range_to_vector("11-19, 21"); // can go higher than 21 on some boards #elif CONFIG_IDF_TARGET_ESP32S2 - std::vector valid_gpios = {19, 20, 22, 32, 40}; + std::vector valid_gpios = string_range_to_vector("19-20, 22-32, 40"); #elif CONFIG_IDF_TARGET_ESP32S3 - std::vector valid_gpios = {19, 20, 22, 37, 39, 42, 48}; -#elif CONFIG_IDF_TARGET_ESP32 - std::vector valid_gpios = {6, 11, 20, 24, 28, 31, 1, 40}; + std::vector valid_gpios = string_range_to_vector("19-20, 22-37, 39-42, 48"); +#elif CONFIG_IDF_TARGET_ESP32 || defined(EMSESP_STANDALONE) + std::vector valid_gpios = string_range_to_vector("1, 6-11, 16-17, 20, 24, 28-31, 40"); #else std::vector valid_gpios = {}; #endif +#if CONFIG_IDF_TARGET_ESP32 + // if psram is enabled remove pins 16 and 17 from the list + if (ESP.getPsramSize() > 0) { + valid_gpios.erase(std::remove(valid_gpios.begin(), valid_gpios.end(), 16), valid_gpios.end()); + valid_gpios.erase(std::remove(valid_gpios.begin(), valid_gpios.end(), 17), valid_gpios.end()); + } +#endif + + // if ethernet is enabled, remove pins 21 and 22 (I2C) + if ((EMSESP::system_.ethernet_connected() || EMSESP::system_.phy_type_ != PHY_type::PHY_TYPE_NONE)) { + valid_gpios.erase(std::remove(valid_gpios.begin(), valid_gpios.end(), 21), valid_gpios.end()); + valid_gpios.erase(std::remove(valid_gpios.begin(), valid_gpios.end(), 22), valid_gpios.end()); + } + // filter out GPIOs already used in application settings for (const auto & gpio : valid_gpios) { - if (gpio == pbutton_gpio_ || gpio == led_gpio_ || gpio == dallas_gpio_ || gpio == rx_gpio_ || gpio == tx_gpio_) { + if (gpio == EMSESP::system_.pbutton_gpio_ || gpio == EMSESP::system_.led_gpio_ || gpio == EMSESP::system_.dallas_gpio_ + || gpio == EMSESP::system_.rx_gpio_ || gpio == EMSESP::system_.tx_gpio_) { valid_gpios.erase(std::remove(valid_gpios.begin(), valid_gpios.end(), gpio), valid_gpios.end()); } } // filter out GPIOs already used in analog sensors, if enabled - if (analog_enabled_) { + if (EMSESP::system_.analog_enabled_) { for (const auto & sensor : EMSESP::analogsensor_.sensors()) { if (std::find(valid_gpios.begin(), valid_gpios.end(), sensor.gpio()) != valid_gpios.end()) { valid_gpios.erase(std::find(valid_gpios.begin(), valid_gpios.end(), sensor.gpio())); diff --git a/src/core/system.h b/src/core/system.h index 7e4e08f32..fb53eb231 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -137,12 +137,10 @@ class System { void systemStatus(uint8_t status_code); uint8_t systemStatus(); - std::vector valid_gpio_list() const; - static void extractSettings(const char * filename, const char * section, JsonObject output); static bool saveSettings(const char * filename, const char * section, JsonObject input); - static bool is_valid_gpio(uint8_t pin, bool has_psram = false); + bool is_valid_gpio(uint8_t pin); static bool load_board_profile(std::vector & data, const std::string & board_profile); static bool readCommand(const char * data); @@ -305,6 +303,7 @@ class System { uint32_t PSram() { return psram_; } + uint32_t appFree() { return appfree_; } @@ -338,6 +337,8 @@ class System { test_set_all_active_ = n; } + static std::vector valid_gpio_list(); + #if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 float temperature() { return temperature_; @@ -383,6 +384,8 @@ class System { void led_monitor(); void system_check(); + static std::vector string_range_to_vector(const std::string & range); + int8_t wifi_quality(int8_t dBm); uint8_t healthcheck_ = HEALTHCHECK_NO_NETWORK | HEALTHCHECK_NO_BUS; // start with all flags set, no wifi and no ems bus connection diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index f83475a1a..46135d9b3 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -90,12 +90,6 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { // load the version from the settings config. This can be blank and later used in System::check_upgrade() settings.version = root["version"] | EMSESP_DEFAULT_VERSION; -#ifndef EMSESP_STANDALONE - bool psram = ESP.getPsramSize() > 0; // System::PSram() is initialized later -#else - bool psram = false; -#endif - #if defined(EMSESP_DEBUG) EMSESP::logger().debug("NVS boot value=[%s], board profile=[%s], EMSESP_DEFAULT_BOARD_PROFILE=[%s]", EMSESP::nvs_.getString("boot").c_str(), @@ -143,8 +137,8 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { #endif } // check valid pins in this board profile - if (!System::is_valid_gpio(data[0], psram) || !System::is_valid_gpio(data[1], psram) || !System::is_valid_gpio(data[2], psram) - || !System::is_valid_gpio(data[3], psram) || !System::is_valid_gpio(data[4], psram) || !System::is_valid_gpio(data[6], psram)) { + if (!EMSESP::system_.is_valid_gpio(data[0]) || !EMSESP::system_.is_valid_gpio(data[1]) || !EMSESP::system_.is_valid_gpio(data[2]) + || !EMSESP::system_.is_valid_gpio(data[3]) || !EMSESP::system_.is_valid_gpio(data[4]) || !EMSESP::system_.is_valid_gpio(data[6])) { settings.board_profile = "default"; // reset to factory default } } else { @@ -161,8 +155,8 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { #if defined(EMSESP_STANDALONE) settings.board_profile = "S32"; #elif CONFIG_IDF_TARGET_ESP32 - // check for no PSRAM, could be a E32 or S32 - if (!psram) { + // check for no PSRAM, could be a E32 or S32? + if (!ESP.getPsramSize()) { #if ESP_ARDUINO_VERSION_MAJOR < 3 if (ETH.begin(1, 16, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_IN)) { #else