From 80dd16740d7e57ae4e6ebe91f3a51f56425fb639 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 17 Nov 2025 23:00:45 +0100 Subject: [PATCH] some fixes on https://github.com/emsesp/EMS-ESP32/pull/2750 --- .../src/app/main/SensorsAnalogDialog.tsx | 25 +++++++--- interface/src/app/main/types.ts | 2 +- .../components/inputs/ValidatedTextField.tsx | 17 +++++-- src/core/analogsensor.cpp | 7 +-- src/core/system.cpp | 48 ++++++++++--------- src/core/system.h | 4 +- src/web/WebCustomizationService.cpp | 7 +++ src/web/WebDataService.cpp | 3 +- 8 files changed, 75 insertions(+), 38 deletions(-) diff --git a/interface/src/app/main/SensorsAnalogDialog.tsx b/interface/src/app/main/SensorsAnalogDialog.tsx index 179d1fc2b..83e29b635 100644 --- a/interface/src/app/main/SensorsAnalogDialog.tsx +++ b/interface/src/app/main/SensorsAnalogDialog.tsx @@ -115,6 +115,23 @@ const SensorsAnalogDialog = ({ [] ); + const analogGPIOMenuItems = () => + // add selectedItem.g to the list + [ + ...(analogGPIOList?.includes(selectedItem.g) || selectedItem.g === undefined + ? analogGPIOList + : [selectedItem.g, ...analogGPIOList]) + ] + .filter((gpio, idx, arr) => arr.indexOf(gpio) === idx) + .sort((a, b) => a - b) + .map((gpio: number) => { + return ( + + {gpio} + + ); + }); + // Reset form when dialog opens or selectedItem changes useEffect(() => { if (open) { @@ -162,15 +179,11 @@ const SensorsAnalogDialog = ({ label="GPIO" value={editItem.g} sx={{ width: '9ch' }} - disabled={editItem.s} + disabled={editItem.s || !creating} select onChange={updateFormValue} > - {analogGPIOList?.map((gpio: number) => ( - - {gpio} - - ))} + {analogGPIOMenuItems()} = ({ error={!!errors} {...rest} aria-label="Error" - slotProps={{ - inputLabel: { - style: rest.disabled ? { color: 'grey' } : undefined + sx={{ + '& .MuiInputBase-input.Mui-disabled': { + WebkitTextFillColor: 'grey' } }} + {...(rest.disabled && { + slotProps: { + select: { + IconComponent: () => null + }, + inputLabel: { + style: { color: 'grey' } + } + } + })} + color={rest.disabled ? 'secondary' : 'primary'} /> {errors?.map((e) => ( diff --git a/src/core/analogsensor.cpp b/src/core/analogsensor.cpp index 988cca9a6..2a06ef9b5 100644 --- a/src/core/analogsensor.cpp +++ b/src/core/analogsensor.cpp @@ -472,8 +472,9 @@ void AnalogSensor::loop() { measure(); // take the measurements } -// update analog information name and offset +// update analog information name, offset, factor, uom, type, deleted, is_system // a type value of -1 is used to delete the sensor +// the gpio is the key bool AnalogSensor::update(uint8_t gpio, std::string & name, double offset, double factor, uint8_t uom, int8_t type, bool deleted, bool is_system) { // first see if we can find the sensor in our customization list bool found_sensor = false; @@ -521,7 +522,7 @@ bool AnalogSensor::update(uint8_t gpio, std::string & name, double offset, doubl } // we didn't find it, it's new, so create and store it in the customization list - // gpio is already checked in web interface, should never trigger. + // gpio is already checked in web interface if (!found_sensor && EMSESP::system_.is_valid_gpio(gpio)) { found_sensor = true; EMSESP::webCustomizationService.update([&](WebCustomization & settings) { @@ -534,7 +535,7 @@ bool AnalogSensor::update(uint8_t gpio, std::string & name, double offset, doubl newSensor.type = type; newSensor.is_system = is_system; settings.analogCustomizations.push_back(newSensor); - LOG_DEBUG("Adding new customization for analog sensor GPIO %02d", gpio); + LOG_DEBUG("Adding customization for analog sensor GPIO %02d", gpio); return StateUpdateResult::CHANGED; // persist the change }); } diff --git a/src/core/system.cpp b/src/core/system.cpp index f24a3f9e1..f78560fdc 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -415,8 +415,8 @@ void System::reload_settings() { EMSESP::webSettingsService.read([&](WebSettings & settings) { version_ = settings.version; // first check gpios, priority to rx and tx - rx_gpio_ = is_valid_gpio(settings.rx_gpio) ? settings.rx_gpio : 0; - tx_gpio_ = is_valid_gpio(settings.tx_gpio) ? settings.tx_gpio : 0; + rx_gpio_ = is_valid_gpio(settings.rx_gpio); + tx_gpio_ = is_valid_gpio(settings.tx_gpio); pbutton_gpio_ = is_valid_gpio(settings.pbutton_gpio) ? settings.pbutton_gpio : 0; dallas_gpio_ = is_valid_gpio(settings.dallas_gpio) ? settings.dallas_gpio : 0; led_gpio_ = is_valid_gpio(settings.led_gpio) ? settings.led_gpio : 0; @@ -456,9 +456,9 @@ void System::reload_settings() { }); } -// check for valid ESP32 pins -bool System::is_valid_gpio(uint8_t pin) { - auto valid_gpios = valid_gpio_list(); +// check if a pin is valid ESP32 pin and not used by application settings +bool System::is_valid_gpio(uint8_t pin, bool exclude_used) { + auto valid_gpios = valid_gpio_list(exclude_used); return std::find(valid_gpios.begin(), valid_gpios.end(), pin) != valid_gpios.end(); } @@ -2356,12 +2356,12 @@ std::vector System::string_range_to_vector(const std::string & range) { return valid_gpios; } -// return a list of valid GPIOs for the ESP32 board +// return a list of valid GPIOs for the ESP32 board that can be used // notes: -// - we allow 0, which is used sometimes to indicate a disabled pin -// - also allow input only pins are accepted (34-39) on some boards +// - we allow 0, which is used sometimes to indicate a disabled pin (e.g. button, led) +// - we also allow input only pins are accepted (34-39) on some boards, excluding 39 // - and allow pins 33-38 for octal SPI for 32M vchip version on some boards -std::vector System::valid_gpio_list() { +std::vector System::valid_gpio_list(bool exclude_used) { // get free gpios based on board/platform type #if CONFIG_IDF_TARGET_ESP32C3 // https://www.wemos.cc/en/latest/c3/c3_mini.html @@ -2390,21 +2390,25 @@ std::vector System::valid_gpio_list() { valid_gpios.erase(std::remove(valid_gpios.begin(), valid_gpios.end(), 22), valid_gpios.end()); } - // filter out GPIOs already used in application settings, gpio 0 means disabled, except for pbutton - for (const auto & gpio : valid_gpios) { - if (gpio == EMSESP::system_.pbutton_gpio_ - || (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 application settings and analog sensors, if enabled + if (exclude_used) { + // application settings + for (const auto & gpio : valid_gpios) { + if (gpio == EMSESP::system_.pbutton_gpio_ + || (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 (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())); + // analog sensors + if (EMSESP::system_.analog_enabled_) { + // TODO: check if core_voltage and supply_voltage are already used + 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 a73b9700c..bd6e6500f 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -141,7 +141,7 @@ class System { static void extractSettings(const char * filename, const char * section, JsonObject output); static bool saveSettings(const char * filename, const char * section, JsonObject input); - bool is_valid_gpio(uint8_t pin); + bool is_valid_gpio(uint8_t pin, bool exclude_used = false); static bool load_board_profile(std::vector & data, const std::string & board_profile); static bool readCommand(const char * data); @@ -342,7 +342,7 @@ class System { test_set_all_active_ = n; } - static std::vector valid_gpio_list(); + static std::vector valid_gpio_list(bool exclude_used = false); #if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 float temperature() { diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp index b05e20947..1005a2ae8 100644 --- a/src/web/WebCustomizationService.cpp +++ b/src/web/WebCustomizationService.cpp @@ -117,6 +117,13 @@ StateUpdateResult WebCustomization::update(JsonObject root, WebCustomization & c auto analogJsons = root["as"].as(); for (const JsonObject analogJson : analogJsons) { // create each of the sensor, overwriting any previous settings + // if the gpio is invalid skip the sensor + if (!EMSESP::system_.is_valid_gpio(analogJson["gpio"].as(), true)) { + EMSESP::logger().warning("Invalid GPIO %d for Sensor %s. Skipping.", + analogJson["gpio"].as(), + analogJson["name"].as().c_str()); + continue; + } auto analog = AnalogCustomization(); analog.gpio = analogJson["gpio"]; analog.name = analogJson["name"].as(); diff --git a/src/web/WebDataService.cpp b/src/web/WebDataService.cpp index 3db967c7d..f040b883b 100644 --- a/src/web/WebDataService.cpp +++ b/src/web/WebDataService.cpp @@ -157,8 +157,9 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) { root["analog_enabled"] = EMSESP::analog_enabled(); root["platform"] = EMSESP_PLATFORM; + // send back a list of valid GPIOs that can be used for analog sensors, excluding those already used JsonArray valid_gpio_list = root["valid_gpio_list"].to(); - for (const auto & gpio : EMSESP::system_.valid_gpio_list()) { + for (const auto & gpio : EMSESP::system_.valid_gpio_list(true)) { valid_gpio_list.add(gpio); }