From ea75a34c82d2ceab4ce7fe9c4141272728ff6512 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Mon, 17 Nov 2025 13:28:00 +0100 Subject: [PATCH 1/2] fix gpio check --- interface/src/app/main/Sensors.tsx | 6 +++--- src/core/analogsensor.cpp | 34 ++++++++++++++++-------------- src/core/system.cpp | 14 ++++++------ src/web/WebDataService.cpp | 2 +- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/interface/src/app/main/Sensors.tsx b/interface/src/app/main/Sensors.tsx index 52fe701b5..61f83d263 100644 --- a/interface/src/app/main/Sensors.tsx +++ b/interface/src/app/main/Sensors.tsx @@ -447,7 +447,7 @@ const Sensors = () => { item={as} onClick={() => updateAnalogSensor(as)} > - {as.g} + {as.g !== 99 ? as.g : ''} {as.n} {AnalogTypeNames[as.t]} {(as.t === AnalogType.DIGITAL_OUT && @@ -455,10 +455,10 @@ const Sensors = () => { as.g !== GPIO_26) || as.t === AnalogType.DIGITAL_IN || as.t === AnalogType.PULSE ? ( - {as.v ? LL.ON() : LL.OFF()} + {as.g !== 99 ? as.v ? LL.ON() : LL.OFF() : ''} ) : ( - {as.t !== AnalogType.NOTUSED ? formatValue(as.v, as.u) : ''} + {as.t !== AnalogType.NOTUSED && as.g !== 99 ? formatValue(as.v, as.u) : ''} )} diff --git a/src/core/analogsensor.cpp b/src/core/analogsensor.cpp index 8345e6b2c..cfa19f91c 100644 --- a/src/core/analogsensor.cpp +++ b/src/core/analogsensor.cpp @@ -155,7 +155,14 @@ void AnalogSensor::reload(bool get_nvs) { } } if (!found) { - sensors_.emplace_back(sensor.gpio, sensor.name, sensor.offset, sensor.factor, sensor.uom, sensor.type, sensor.is_system); + // check if the GPIO is valid before registering. If not, force set the sensor to disabled, but don't remove it + // should only trigger if uploading a customization file with invalid gpios. + if (!EMSESP::system_.is_valid_gpio(sensor.gpio)) { + LOG_WARNING("Bad GPIO %d for Sensor %s. Disabling.", sensor.gpio, sensor.name.c_str()); + sensors_.emplace_back(99, sensor.name, sensor.offset, sensor.factor, sensor.uom, sensor.type, sensor.is_system); + } else { + sensors_.emplace_back(sensor.gpio, sensor.name, sensor.offset, sensor.factor, sensor.uom, sensor.type, sensor.is_system); + } sensors_.back().ha_registered = false; // this will trigger recreate of the HA config if (sensor.type == AnalogType::COUNTER || sensor.type >= AnalogType::DIGITAL_OUT) { sensors_.back().set_value(sensor.offset); @@ -187,16 +194,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 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 - } - - if ((sensor.gpio() == 25 || sensor.gpio() == 26) - && (sensor.type() == AnalogType::COUNTER || sensor.type() == AnalogType::DIGITAL_IN || sensor.type() == AnalogType::RATE - || sensor.type() == AnalogType::TIMER)) { + if (sensor.type() == AnalogType::COUNTER || sensor.type() == AnalogType::DIGITAL_IN || sensor.type() == AnalogType::RATE + || sensor.type() == AnalogType::TIMER) { // pullup is mapped to DAC, so set to 3.3V #if CONFIG_IDF_TARGET_ESP32 if (sensor.gpio() == 25 || sensor.gpio() == 26) { @@ -521,7 +520,9 @@ 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 - if (!found_sensor) { + // gpio is already checked in web interface, should never trigger. + if (!found_sensor && EMSESP::system_.is_valid_gpio(gpio)) { + found_sensor = true; EMSESP::webCustomizationService.update([&](WebCustomization & settings) { auto newSensor = AnalogCustomization(); newSensor.gpio = gpio; @@ -538,11 +539,12 @@ bool AnalogSensor::update(uint8_t gpio, std::string & name, double offset, doubl } // reloads the sensors in the customizations file into the sensors list - reload(); + if (found_sensor) { + reload(); + return true; + } - // return false if it's an invalid GPIO, an error will show in WebUI - // and reported as an error in the log - return EMSESP::system_.is_valid_gpio(gpio); + return false; } // check to see if values have been updated diff --git a/src/core/system.cpp b/src/core/system.cpp index 5f81b31ef..f30c53e83 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -414,13 +414,17 @@ void System::reload_settings() { dallas_gpio_ = 0; EMSESP::webSettingsService.read([&](WebSettings & settings) { version_ = settings.version; + // first check gpios, prioriy 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; + 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; - pbutton_gpio_ = is_valid_gpio(settings.pbutton_gpio) ? settings.pbutton_gpio : 0; analog_enabled_ = settings.analog_enabled; low_clock_ = settings.low_clock; hide_led_ = settings.hide_led; led_type_ = settings.led_type; - led_gpio_ = is_valid_gpio(settings.led_gpio) ? settings.led_gpio : 0; board_profile_ = settings.board_profile; telnet_enabled_ = settings.telnet_enabled; @@ -430,9 +434,6 @@ void System::reload_settings() { modbus_timeout_ = settings.modbus_timeout; tx_mode_ = settings.tx_mode; - rx_gpio_ = is_valid_gpio(settings.rx_gpio) ? settings.rx_gpio : 0; - tx_gpio_ = is_valid_gpio(settings.tx_gpio) ? settings.tx_gpio : 0; - dallas_gpio_ = is_valid_gpio(settings.dallas_gpio) ? settings.dallas_gpio : 0; syslog_enabled_ = settings.syslog_enabled; syslog_level_ = settings.syslog_level; syslog_mark_interval_ = settings.syslog_mark_interval; @@ -457,7 +458,8 @@ void System::reload_settings() { // 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(); + auto valid_gpios = valid_gpio_list(); + return std::find(valid_gpios.begin(), valid_gpios.end(), pin) != valid_gpios.end(); } // Starts up the UART Serial bridge diff --git a/src/web/WebDataService.cpp b/src/web/WebDataService.cpp index 4b78399f4..0e36e08b6 100644 --- a/src/web/WebDataService.cpp +++ b/src/web/WebDataService.cpp @@ -146,7 +146,7 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) { obj["t"] = sensor.type(); obj["s"] = sensor.is_system(); - if (sensor.type() != AnalogSensor::AnalogType::NOTUSED) { + if (sensor.type() != AnalogSensor::AnalogType::NOTUSED && sensor.gpio() != 99) { obj["v"] = Helpers::transformNumFloat(sensor.value()); // is optional and is a float } else { obj["v"] = 0; // must have a value for web sorting to work From f112e6f6cc34f44f99fc60d6e2a321e28c44b0f2 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Mon, 17 Nov 2025 13:57:30 +0100 Subject: [PATCH 2/2] exclude disabled sensors from dashboard --- src/web/WebDataService.cpp | 56 ++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/web/WebDataService.cpp b/src/web/WebDataService.cpp index 0e36e08b6..1ba81c416 100644 --- a/src/web/WebDataService.cpp +++ b/src/web/WebDataService.cpp @@ -435,41 +435,39 @@ void WebDataService::dashboard_data(AsyncWebServerRequest * request) { JsonArray nodes = obj["nodes"].to(); uint8_t count = 0; for (const auto & sensor : EMSESP::analogsensor_.sensors()) { - // ignore system sensors - if (sensor.is_system()) { + // ignore system and disabled sensors + if (sensor.is_system() || sensor.type() == AnalogSensor::AnalogType::NOTUSED || sensor.gpio() == 99) { continue; } - if (sensor.type() != AnalogSensor::AnalogType::NOTUSED) { // ignore disabled - JsonObject node = nodes.add(); - node["id"] = (EMSdevice::DeviceTypeUniqueID::ANALOGSENSOR_UID * 100) + count++; + JsonObject node = nodes.add(); + node["id"] = (EMSdevice::DeviceTypeUniqueID::ANALOGSENSOR_UID * 100) + count++; - JsonObject dv = node["dv"].to(); - dv["id"] = "00" + sensor.name(); + JsonObject dv = node["dv"].to(); + dv["id"] = "00" + sensor.name(); #if CONFIG_IDF_TARGET_ESP32 - if (sensor.type() == AnalogSensor::AnalogType::DIGITAL_OUT && (sensor.gpio() == 25 || sensor.gpio() == 26)) { - obj["v"] = Helpers::transformNumFloat(sensor.value()); - } else + if (sensor.type() == AnalogSensor::AnalogType::DIGITAL_OUT && (sensor.gpio() == 25 || sensor.gpio() == 26)) { + obj["v"] = Helpers::transformNumFloat(sensor.value()); + } else #elif CONFIG_IDF_TARGET_ESP32S2 - if (sensor.type() == AnalogSensor::AnalogType::DIGITAL_OUT && (sensor.gpio() == 17 || sensor.gpio() == 18)) { - obj["v"] = Helpers::transformNumFloat(sensor.value()); - } else + if (sensor.type() == AnalogSensor::AnalogType::DIGITAL_OUT && (sensor.gpio() == 17 || sensor.gpio() == 18)) { + obj["v"] = Helpers::transformNumFloat(sensor.value()); + } else #endif - if (sensor.type() == AnalogSensor::AnalogType::DIGITAL_OUT || sensor.type() == AnalogSensor::AnalogType::DIGITAL_IN - || sensor.type() == AnalogSensor::AnalogType::PULSE) { - char s[12]; - dv["v"] = Helpers::render_boolean(s, sensor.value() != 0, true); - JsonArray l = dv["l"].to(); - l.add(Helpers::render_boolean(s, false, true)); - l.add(Helpers::render_boolean(s, true, true)); - } else { - dv["v"] = Helpers::transformNumFloat(sensor.value()); - dv["u"] = sensor.uom(); - } - if (sensor.type() == AnalogSensor::AnalogType::COUNTER - || (sensor.type() >= AnalogSensor::AnalogType::DIGITAL_OUT && sensor.type() <= AnalogSensor::AnalogType::PWM_2) - || sensor.type() == AnalogSensor::AnalogType::RGB || sensor.type() == AnalogSensor::AnalogType::PULSE) { - dv["c"] = sensor.name(); - } + if (sensor.type() == AnalogSensor::AnalogType::DIGITAL_OUT || sensor.type() == AnalogSensor::AnalogType::DIGITAL_IN + || sensor.type() == AnalogSensor::AnalogType::PULSE) { + char s[12]; + dv["v"] = Helpers::render_boolean(s, sensor.value() != 0, true); + JsonArray l = dv["l"].to(); + l.add(Helpers::render_boolean(s, false, true)); + l.add(Helpers::render_boolean(s, true, true)); + } else { + dv["v"] = Helpers::transformNumFloat(sensor.value()); + dv["u"] = sensor.uom(); + } + if (sensor.type() == AnalogSensor::AnalogType::COUNTER + || (sensor.type() >= AnalogSensor::AnalogType::DIGITAL_OUT && sensor.type() <= AnalogSensor::AnalogType::PWM_2) + || sensor.type() == AnalogSensor::AnalogType::RGB || sensor.type() == AnalogSensor::AnalogType::PULSE) { + dv["c"] = sensor.name(); } } }