updated gpio test logic

This commit is contained in:
proddy
2025-11-20 22:58:26 +01:00
parent c9bddba446
commit 23a660aabb
15 changed files with 1879 additions and 1870 deletions

View File

@@ -360,7 +360,7 @@ const Sensors = () => {
v: 0, v: 0,
o: 0, o: 0,
f: 1, f: 1,
t: AnalogType.NOTUSED, t: AnalogType.DIGITAL_IN, // default to digital in 1
d: false, d: false,
s: false, s: false,
o_n: '' o_n: ''
@@ -462,7 +462,7 @@ const Sensors = () => {
> >
<Cell stiff>{as.g}</Cell> <Cell stiff>{as.g}</Cell>
<Cell>{as.n}</Cell> <Cell>{as.n}</Cell>
<Cell stiff>{AnalogTypeNames[as.t]} </Cell> <Cell stiff>{AnalogTypeNames[as.t - 1]} </Cell>
{(as.t === AnalogType.DIGITAL_OUT && {(as.t === AnalogType.DIGITAL_OUT &&
as.g !== GPIO_25 && as.g !== GPIO_25 &&
as.g !== GPIO_26) || as.g !== GPIO_26) ||
@@ -470,9 +470,7 @@ const Sensors = () => {
as.t === AnalogType.PULSE ? ( as.t === AnalogType.PULSE ? (
<Cell stiff>{as.v ? LL.ON() : LL.OFF()}</Cell> <Cell stiff>{as.v ? LL.ON() : LL.OFF()}</Cell>
) : ( ) : (
<Cell stiff> <Cell stiff>{formatValue(as.v, as.u)}</Cell>
{as.t !== AnalogType.NOTUSED ? formatValue(as.v, as.u) : ''}
</Cell>
)} )}
</Row> </Row>
))} ))}

View File

@@ -98,7 +98,7 @@ const SensorsAnalogDialog = ({
const analogTypeMenuItems = useMemo( const analogTypeMenuItems = useMemo(
() => () =>
AnalogTypeNames.map((val, i) => ( AnalogTypeNames.map((val, i) => (
<MenuItem key={val} value={i}> <MenuItem key={val} value={i + 1}>
{val} {val}
</MenuItem> </MenuItem>
)), )),

View File

@@ -231,7 +231,6 @@ export const DeviceValueUOM_s = [
export enum AnalogType { export enum AnalogType {
REMOVED = -1, REMOVED = -1,
NOTUSED = 0,
DIGITAL_IN = 1, DIGITAL_IN = 1,
COUNTER = 2, COUNTER = 2,
ADC = 3, ADC = 3,
@@ -250,22 +249,21 @@ export enum AnalogType {
} }
export const AnalogTypeNames = [ export const AnalogTypeNames = [
'(disabled)', 'Digital In', // 1
'Digital In', 'Counter', // 2
'Counter', 'ADC In', // 3
'ADC In', 'Timer', // 4
'Timer', 'Rate', // 5
'Rate', 'Digital Out', // 6
'Digital Out', 'PWM 0', // 7
'PWM 0', 'PWM 1', // 8
'PWM 1', 'PWM 2', // 9
'PWM 2', 'NTC Temp.', // 10
'NTC Temp.', 'RGB Led', // 11
'RGB Led', 'Pulse', // 12
'Pulse', 'Freq 0', // 13
'Freq 0', 'Freq 1', // 14
'Freq 1', 'Freq 2', // 15
'Freq 2'
] as const; ] as const;
export const BOARD_PROFILES = { export const BOARD_PROFILES = {

View File

@@ -984,7 +984,7 @@ const emsesp_sensordata = {
], ],
// as: [], // as: [],
as: [ as: [
{ id: 1, g: 35, n: 'motor', v: 0, u: 0, o: 17, f: 0, t: 0, d: false, s: false }, { id: 1, g: 35, n: 'motor', v: 0, u: 0, o: 17, f: 0, t: 7, d: false, s: false },
{ {
id: 2, id: 2,
g: 34, g: 34,

View File

@@ -831,7 +831,6 @@ notoken
NOTOKEN NOTOKEN
NOTRANSLATION NOTRANSLATION
NOTSET NOTSET
NOTUSED
NOTYPE NOTYPE
nrgconscomp nrgconscomp
nrgconscompcooling nrgconscompcooling

View File

@@ -155,12 +155,12 @@ void AnalogSensor::reload(bool get_nvs) {
} }
} }
if (!found) { if (!found) {
// it's new
// check if the GPIO is valid before registering. If not, force set the sensor to disabled, but don't remove it // 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. // should only trigger if uploading a customization file with invalid gpios.
AnalogType type = static_cast<AnalogType>(sensor.type); AnalogType type = static_cast<AnalogType>(sensor.type);
if (!EMSESP::system_.is_valid_gpio(sensor.gpio)) { if (!EMSESP::system_.check_valid_gpio(sensor.gpio, "Analog Sensor")) {
LOG_WARNING("Bad GPIO %d for Sensor %s. Disabling.", sensor.gpio, sensor.name.c_str()); continue;
type = AnalogType::NOTUSED;
} }
sensors_.emplace_back(sensor.gpio, sensor.name, sensor.offset, sensor.factor, sensor.uom, type, sensor.is_system); sensors_.emplace_back(sensor.gpio, sensor.name, sensor.offset, sensor.factor, sensor.uom, type, sensor.is_system);
@@ -171,6 +171,8 @@ void AnalogSensor::reload(bool get_nvs) {
sensors_.back().set_value(0); // reset value only for new sensors sensors_.back().set_value(0); // reset value only for new sensors
} }
} }
// add the command to set the value of the sensor
if (sensor.type == AnalogType::COUNTER || (sensor.type >= AnalogType::DIGITAL_OUT && sensor.type <= AnalogType::PWM_2) if (sensor.type == AnalogType::COUNTER || (sensor.type >= AnalogType::DIGITAL_OUT && sensor.type <= AnalogType::PWM_2)
|| sensor.type == AnalogType::RGB || sensor.type == AnalogType::PULSE) { || sensor.type == AnalogType::RGB || sensor.type == AnalogType::PULSE) {
Command::add( Command::add(
@@ -522,8 +524,8 @@ 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 // we didn't find it, it's new, so create and store it in the customization list
// gpio is already checked in web interface // gpio is already checked if valid in the webUI
if (!found_sensor && EMSESP::system_.is_valid_gpio(gpio)) { if (!found_sensor) {
found_sensor = true; found_sensor = true;
EMSESP::webCustomizationService.update([&](WebCustomization & settings) { EMSESP::webCustomizationService.update([&](WebCustomization & settings) {
auto newSensor = AnalogCustomization(); auto newSensor = AnalogCustomization();
@@ -626,7 +628,6 @@ void AnalogSensor::publish_values(const bool force) {
JsonDocument doc; JsonDocument doc;
for (auto & sensor : sensors_) { for (auto & sensor : sensors_) {
if (sensor.type() != AnalogType::NOTUSED) {
if (Mqtt::is_nested()) { if (Mqtt::is_nested()) {
char s[10]; char s[10];
JsonObject dataSensor = doc[Helpers::smallitoa(s, sensor.gpio())].to<JsonObject>(); JsonObject dataSensor = doc[Helpers::smallitoa(s, sensor.gpio())].to<JsonObject>();
@@ -779,7 +780,6 @@ void AnalogSensor::publish_values(const bool force) {
sensor.ha_registered = Mqtt::queue_ha(topic, config.as<JsonObject>()); sensor.ha_registered = Mqtt::queue_ha(topic, config.as<JsonObject>());
} }
} }
}
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "%s_data", F_(analogsensor)); snprintf(topic, sizeof(topic), "%s_data", F_(analogsensor));

View File

@@ -118,7 +118,6 @@ class AnalogSensor {
~AnalogSensor() = default; ~AnalogSensor() = default;
enum AnalogType : int8_t { enum AnalogType : int8_t {
NOTUSED = 0, // 0 = disabled
DIGITAL_IN = 1, DIGITAL_IN = 1,
COUNTER = 2, COUNTER = 2,
ADC = 3, ADC = 3,
@@ -164,12 +163,10 @@ class AnalogSensor {
return (!sensors_.empty()); return (!sensors_.empty());
} }
// count number of items in sensors_ where type is not set to disabled and not a system sensor
size_t count_entities(bool exclude_disabled_system = false) const { size_t count_entities(bool exclude_disabled_system = false) const {
if (exclude_disabled_system) { if (exclude_disabled_system) {
// count number of items in sensors_ where type is not set to disabled and not a system sensor return std::count_if(sensors_.begin(), sensors_.end(), [](const Sensor & sensor) { return !sensor.is_system(); });
return std::count_if(sensors_.begin(), sensors_.end(), [](const Sensor & sensor) {
return sensor.type() != AnalogSensor::AnalogType::NOTUSED && !sensor.is_system();
});
} }
return sensors_.size(); return sensors_.size();
} }

View File

@@ -321,7 +321,7 @@ static void setup_commands(std::shared_ptr<Commands> const & commands) {
return StateUpdateResult::CHANGED; return StateUpdateResult::CHANGED;
}); });
shell.printfln("Loaded board profile %s", board_profile.c_str()); shell.printfln("Loaded board profile %s", board_profile.c_str());
EMSESP::system_.network_init(true); EMSESP::system_.network_init();
}); });
commands->add_command( commands->add_command(
@@ -357,7 +357,7 @@ static void setup_commands(std::shared_ptr<Commands> const & commands) {
shell.printfln(F_(tx_mode_fmt), settings.tx_mode); shell.printfln(F_(tx_mode_fmt), settings.tx_mode);
return StateUpdateResult::CHANGED; return StateUpdateResult::CHANGED;
}); });
EMSESP::system_.uart_init(false); EMSESP::system_.uart_init();
}); });
// //

View File

@@ -1665,6 +1665,9 @@ void EMSESP::start() {
bool factory_settings = false; bool factory_settings = false;
#endif #endif
// set valid GPIOs list based on ESP32 board/platform type
system_.set_valid_system_gpios();
// start web log service. now we can start capturing logs to the web log // start web log service. now we can start capturing logs to the web log
webLogService.begin(); webLogService.begin();
@@ -1714,7 +1717,7 @@ void EMSESP::start() {
}; };
LOG_INFO("Library loaded: %d EMS devices, %d device entities, %s", device_library_.size(), EMSESP_TRANSLATION_COUNT, system_.languages_string().c_str()); LOG_INFO("Library loaded: %d EMS devices, %d device entities, %s", device_library_.size(), EMSESP_TRANSLATION_COUNT, system_.languages_string().c_str());
system_.reload_settings(); // ... and store some of the settings locally system_.get_settings(); // ... and store some of the settings locally
webCustomizationService.begin(); // load the customizations webCustomizationService.begin(); // load the customizations
webSchedulerService.begin(); // load the scheduler events webSchedulerService.begin(); // load the scheduler events
@@ -1806,6 +1809,14 @@ void EMSESP::loop() {
} }
} }
if (EMSESP::system_.systemStatus() == SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO) {
static bool only_once = false;
if (!only_once) {
LOG_ERROR("Invalid GPIOs used in settings. Please check your settings.");
only_once = true;
}
}
uuid::loop(); uuid::loop();
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE

View File

@@ -91,6 +91,8 @@ PButton System::myPButton_;
bool System::test_set_all_active_ = false; bool System::test_set_all_active_ = false;
uint32_t System::max_alloc_mem_; uint32_t System::max_alloc_mem_;
uint32_t System::heap_mem_; uint32_t System::heap_mem_;
std::vector<uint8_t> System::valid_system_gpios_;
std::vector<uint8_t> System::used_gpios_;
// find the index of the language // find the index of the language
// 0 = EN, 1 = DE, etc... // 0 = EN, 1 = DE, etc...
@@ -404,19 +406,18 @@ void System::syslog_init() {
#endif #endif
} }
// read some specific system settings to store locally for faster access // read specific major system settings to store locally for faster access
void System::reload_settings() { // this also verifies all the assigned GPIOs are valid
void System::get_settings() {
EMSESP::webSettingsService.read([&](WebSettings & settings) { EMSESP::webSettingsService.read([&](WebSettings & settings) {
version_ = settings.version; version_ = settings.version;
// rx and tx pins are validated in uart_init() // GPIOs
rx_gpio_ = settings.rx_gpio; rx_gpio_ = settings.rx_gpio;
tx_gpio_ = settings.tx_gpio; tx_gpio_ = settings.tx_gpio;
pbutton_gpio_ = settings.pbutton_gpio;
pbutton_gpio_ = settings.pbutton_gpio; // validated in System::button_init() dallas_gpio_ = settings.dallas_gpio;
led_gpio_ = settings.led_gpio;
dallas_gpio_ = is_valid_gpio(settings.dallas_gpio) ? settings.dallas_gpio : 0; // we use 0 for disabled
led_gpio_ = is_valid_gpio(settings.led_gpio) ? settings.led_gpio : 0; // we use 0 for disabled
analog_enabled_ = settings.analog_enabled; analog_enabled_ = settings.analog_enabled;
low_clock_ = settings.low_clock; low_clock_ = settings.low_clock;
@@ -451,13 +452,7 @@ void System::reload_settings() {
locale_ = settings.locale; locale_ = settings.locale;
developer_mode_ = settings.developer_mode; developer_mode_ = settings.developer_mode;
}); });
}
// 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();
}
// Starts up the UART Serial bridge // Starts up the UART Serial bridge
void System::start() { void System::start() {
@@ -499,10 +494,10 @@ void System::start() {
}); });
commands_init(); // console & api commands commands_init(); // console & api commands
led_init(false); // init LED led_init(); // init LED
button_init(false); // the special button button_init(); // button
network_init(false); // network network_init(); // network
uart_init(false); // start UART uart_init(); // start UART
syslog_init(); // start syslog syslog_init(); // start syslog
} }
@@ -549,17 +544,7 @@ void System::button_OnVLongPress(PButton & b) {
} }
// push button // push button
void System::button_init(bool refresh) { void System::button_init() {
if (refresh) {
reload_settings();
}
// validate button gpio
if (!is_valid_gpio(pbutton_gpio_)) {
LOG_WARNING("Invalid button GPIO. Check config.");
return;
}
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
if (!myPButton_.init(pbutton_gpio_, HIGH)) { if (!myPButton_.init(pbutton_gpio_, HIGH)) {
LOG_WARNING("Multi-functional button not detected"); LOG_WARNING("Multi-functional button not detected");
@@ -575,18 +560,13 @@ void System::button_init(bool refresh) {
} }
// set the LED to on or off when in normal operating mode // set the LED to on or off when in normal operating mode
void System::led_init(bool refresh) { void System::led_init() {
if (refresh) {
// disabled old led port before setting new one // disabled old led port before setting new one
if (led_gpio_) {
#if ESP_ARDUINO_VERSION_MAJOR < 3 #if ESP_ARDUINO_VERSION_MAJOR < 3
led_type_ ? neopixelWrite(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); led_type_ ? neopixelWrite(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON);
#else #else
led_type_ ? rgbLedWrite(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON); led_type_ ? rgbLedWrite(led_gpio_, 0, 0, 0) : digitalWrite(led_gpio_, !LED_ON);
#endif #endif
}
reload_settings();
}
if ((led_gpio_)) { // 0 means disabled if ((led_gpio_)) { // 0 means disabled
if (led_type_) { if (led_type_) {
@@ -605,18 +585,11 @@ void System::led_init(bool refresh) {
} }
} }
void System::uart_init(bool refresh) { void System::uart_init() {
if (refresh) {
reload_settings();
}
EMSuart::stop(); EMSuart::stop();
// start UART if we have valid rx and tx GPIOs // start UART, GPIOs have already been checked
if (is_valid_gpio(rx_gpio_) && is_valid_gpio(tx_gpio_)) { EMSuart::start(tx_mode_, rx_gpio_, tx_gpio_);
EMSuart::start(tx_mode_, rx_gpio_, tx_gpio_); // start UART
} else {
LOG_WARNING("Invalid UART Rx/Tx GPIOs. Check config.");
}
EMSESP::txservice_.start(); // reset counters and send devices request EMSESP::txservice_.start(); // reset counters and send devices request
} }
@@ -778,11 +751,7 @@ void System::send_heartbeat() {
} }
// initializes network // initializes network
void System::network_init(bool refresh) { void System::network_init() {
if (refresh) {
reload_settings();
}
last_system_check_ = 0; // force the LED to go from fast flash to pulse last_system_check_ = 0; // force the LED to go from fast flash to pulse
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
@@ -1266,7 +1235,7 @@ bool System::check_upgrade(bool factory_settings) {
version::Semver200_version settings_version(settingsVersion); version::Semver200_version settings_version(settingsVersion);
if (!missing_version) { if (!missing_version) {
LOG_DEBUG("Checking for version upgrades (settings file has v%d.%d.%d-%s)", LOG_DEBUG("Checking for version upgrades (settings file is from v%d.%d.%d-%s)",
settings_version.major(), settings_version.major(),
settings_version.minor(), settings_version.minor(),
settings_version.patch(), settings_version.patch(),
@@ -2325,11 +2294,11 @@ uint8_t System::systemStatus() {
// takes a string range like "6-11, 1, 23, 24-48" which has optional ranges and single values and converts to a vector of ints // takes a string range like "6-11, 1, 23, 24-48" which has optional ranges and single values and converts to a vector of ints
std::vector<uint8_t> System::string_range_to_vector(const std::string & range) { std::vector<uint8_t> System::string_range_to_vector(const std::string & range) {
std::vector<uint8_t> valid_gpios; std::vector<uint8_t> gpios;
std::string::size_type pos = 0; std::string::size_type pos = 0;
std::string::size_type prev = 0; std::string::size_type prev = 0;
auto process_part = [&valid_gpios](std::string part) { auto process_part = [&gpios](std::string part) {
// trim whitespace // trim whitespace
part.erase(0, part.find_first_not_of(" \t")); part.erase(0, part.find_first_not_of(" \t"));
part.erase(part.find_last_not_of(" \t") + 1); part.erase(part.find_last_not_of(" \t") + 1);
@@ -2341,10 +2310,10 @@ std::vector<uint8_t> System::string_range_to_vector(const std::string & range) {
int start = std::stoi(part.substr(0, dash_pos)); int start = std::stoi(part.substr(0, dash_pos));
int end = std::stoi(part.substr(dash_pos + 1)); int end = std::stoi(part.substr(dash_pos + 1));
for (int i = start; i <= end; i++) { for (int i = start; i <= end; i++) {
valid_gpios.push_back(static_cast<uint8_t>(i)); gpios.push_back(static_cast<uint8_t>(i));
} }
} else { } else {
valid_gpios.push_back(static_cast<uint8_t>(std::stoi(part))); gpios.push_back(static_cast<uint8_t>(std::stoi(part)));
} }
}; };
@@ -2356,71 +2325,106 @@ std::vector<uint8_t> System::string_range_to_vector(const std::string & range) {
// handle the last part // handle the last part
process_part(range.substr(prev)); process_part(range.substr(prev));
return valid_gpios; return gpios;
} }
// return a list of valid GPIOs for the ESP32 board that can be used // initialize a list of valid GPIOs based on the ESP32 board
// notes: // notes:
// - we allow 0, which is used on some board for the button // - we allow 0, which is used on some board for the button
// - we also allow input only pins are accepted (34-39) on some boards, excluding 39 // - we also allow input only pins are accepted (34-39) on some boards
// - and allow pins 33-38 for octal SPI for 32M vchip version on some boards // - and allow pins 33-38 for octal SPI for 32M vchip version on some boards
std::vector<uint8_t> System::valid_gpio_list(bool exclude_used) { void System::set_valid_system_gpios(bool exclude_used) {
valid_system_gpios_.clear(); // reset system list
used_gpios_.clear(); // reset used list
// get free gpios based on board/platform type // get free gpios based on board/platform type
#if CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32C3
// https://www.wemos.cc/en/latest/c3/c3_mini.html // https://www.wemos.cc/en/latest/c3/c3_mini.html
std::vector<uint8_t> valid_gpios = string_range_to_vector("0-10"); valid_gpios_ = string_range_to_vector("0-10");
#elif CONFIG_IDF_TARGET_ESP32S2 #elif CONFIG_IDF_TARGET_ESP32S2
std::vector<uint8_t> valid_gpios = string_range_to_vector("0-14, 19, 20, 21, 33-38, 45, 46"); valid_gpios_ = string_range_to_vector("0-14, 19, 20, 21, 33-38, 45, 46");
#elif CONFIG_IDF_TARGET_ESP32S3 #elif CONFIG_IDF_TARGET_ESP32S3
std::vector<uint8_t> valid_gpios = string_range_to_vector("2, 4-14, 17, 18, 21, 33-38, 45, 46"); valid_gpios_ = string_range_to_vector("0-2, 4-14, 17, 18, 21, 33-38, 45, 46");
#elif CONFIG_IDF_TARGET_ESP32 || defined(EMSESP_STANDALONE) #elif CONFIG_IDF_TARGET_ESP32 || defined(EMSESP_STANDALONE)
std::vector<uint8_t> valid_gpios = string_range_to_vector("0, 2, 4, 5, 12-15, 18, 19, 23, 25-27, 32-39"); valid_system_gpios_ = string_range_to_vector("0, 2, 4, 5, 12-15, 18, 19, 23, 25-27, 32-39");
#else #else
std::vector<uint8_t> valid_gpios = {};
#endif #endif
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
// if psram is enabled remove pins 16 and 17 from the list
if (ESP.getPsramSize() > 0) { if (ESP.getPsramSize() > 0) {
valid_gpios.erase(std::remove(valid_gpios.begin(), valid_gpios.end(), 16), valid_gpios.end()); // if psram is enabled remove pins 16 and 17 from the list, if set
valid_gpios.erase(std::remove(valid_gpios.begin(), valid_gpios.end(), 17), valid_gpios.end()); valid_system_gpios_.erase(std::remove(valid_system_gpios_.begin(), valid_system_gpios_.end(), 16), valid_system_gpios_.end());
valid_system_gpios_.erase(std::remove(valid_system_gpios_.begin(), valid_system_gpios_.end(), 17), valid_system_gpios_.end());
} }
#endif #endif
}
// if ethernet is enabled, remove pins 21 and 22 (I2C) // check if a pin is valid ESP32 pin and if not already used, add to the used gpio list
bool System::check_valid_gpio(uint8_t pin, const char * source_name) {
bool ok = false;
// check if we're allowed to use this pin
if (std::find(valid_system_gpios_.begin(), valid_system_gpios_.end(), pin) != valid_system_gpios_.end()) {
// It's OK, now check if it's already in the used list
if (std::find(used_gpios_.begin(), used_gpios_.end(), pin) != used_gpios_.end()) {
LOG_DEBUG("GPIO %d for %s is already used", pin, source_name);
ok = false; // Pin is already used, not OK
} else {
ok = true;
}
}
if (ok) {
LOG_DEBUG("Adding GPIO %d for %s to used list", pin, source_name);
used_gpios_.push_back(pin); // add to used list
} else {
LOG_DEBUG("GPIO %d for %s is not valid", pin, source_name);
}
return ok;
}
// return a list of valid and unused GPIOs still available for use
std::vector<uint8_t> System::valid_gpio_list() {
std::vector<uint8_t> gpios;
for (const auto & gpio : valid_system_gpios_) {
if (std::find(used_gpios_.begin(), used_gpios_.end(), gpio) == used_gpios_.end()) {
gpios.push_back(gpio);
}
}
return gpios;
}
} // namespace emsesp
/*
// if ethernet is enabled, remove pins 21 and 22 (I2C) and 1 (ETH.power)
if ((EMSESP::system_.ethernet_connected() || EMSESP::system_.phy_type_ != PHY_type::PHY_TYPE_NONE)) { 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()); gpios_to_remove.push_back(21);
valid_gpios.erase(std::remove(valid_gpios.begin(), valid_gpios.end(), 22), valid_gpios.end()); gpios_to_remove.push_back(22);
gpios_to_remove.push_back(1);
} }
// filter out GPIOs already used in application settings and analog sensors, if enabled // filter out GPIOs already used in application settings and analog sensors, if enabled
// if dallas_gpio or led_gpio is disabled (0), don't remove it from the list (as it could be gpio 0 and valid) // if dallas_gpio or led_gpio is disabled (0), don't remove it from the list (as it could be gpio 0 and valid)
if (exclude_used) { if (exclude_used) {
// application settings // application settings
for (const auto & gpio : valid_gpios) { gpios_to_remove.push_back(EMSESP::system_.pbutton_gpio_);
if (gpio == EMSESP::system_.pbutton_gpio_ if (EMSESP::system_.led_gpio_ != 0) {
|| (gpio gpios_to_remove.push_back(EMSESP::system_.led_gpio_);
&& ((EMSESP::system_.led_gpio_ != 0 && gpio == EMSESP::system_.led_gpio_)
|| (EMSESP::system_.dallas_gpio_ != 0 && 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());
} }
if (EMSESP::system_.dallas_gpio_ != 0) {
gpios_to_remove.push_back(EMSESP::system_.dallas_gpio_);
} }
gpios_to_remove.push_back(EMSESP::system_.rx_gpio_);
gpios_to_remove.push_back(EMSESP::system_.tx_gpio_);
// analog sensors // analog sensors
if (EMSESP::system_.analog_enabled_) {
for (const auto & sensor : EMSESP::analogsensor_.sensors()) { for (const auto & sensor : EMSESP::analogsensor_.sensors()) {
if (std::find(valid_gpios.begin(), valid_gpios.end(), sensor.gpio()) != valid_gpios.end()) { if (std::find(valid_system_gpios_.begin(), valid_system_gpios_.end(), sensor.gpio()) != valid_system_gpios_.end()) {
valid_gpios.erase(std::find(valid_gpios.begin(), valid_gpios.end(), sensor.gpio())); gpios_to_remove.push_back(sensor.gpio());
}
} }
} }
} }
// sort the list of valid GPIOs. This is also done in the web interface, so client side. */
std::sort(valid_gpios.begin(), valid_gpios.end());
return valid_gpios;
}
} // namespace emsesp

View File

@@ -67,7 +67,8 @@ enum SYSTEM_STATUS : uint8_t {
SYSTEM_STATUS_UPLOADING = 100, SYSTEM_STATUS_UPLOADING = 100,
SYSTEM_STATUS_ERROR_UPLOAD = 3, SYSTEM_STATUS_ERROR_UPLOAD = 3,
SYSTEM_STATUS_PENDING_RESTART = 4, SYSTEM_STATUS_PENDING_RESTART = 4,
SYSTEM_STATUS_RESTART_REQUESTED = 5 SYSTEM_STATUS_RESTART_REQUESTED = 5,
SYSTEM_STATUS_INVALID_GPIO = 6
}; };
enum FUSE_VALUE : uint8_t { ALL = 0, MFG = 1, MODEL = 2, BOARD = 3, REV = 4, BATCH = 5, FUSE = 6 }; enum FUSE_VALUE : uint8_t { ALL = 0, MFG = 1, MODEL = 2, BOARD = 3, REV = 4, BATCH = 5, FUSE = 6 };
@@ -103,7 +104,7 @@ class System {
void system_restart(const char * partition = nullptr); void system_restart(const char * partition = nullptr);
void show_mem(const char * note); void show_mem(const char * note);
void reload_settings(); void get_settings();
void syslog_init(); void syslog_init();
bool check_upgrade(bool factory_settings); bool check_upgrade(bool factory_settings);
bool check_restore(); bool check_restore();
@@ -129,11 +130,11 @@ class System {
static bool uploadFirmwareURL(const char * url = nullptr); static bool uploadFirmwareURL(const char * url = nullptr);
void led_init(bool refresh); void led_init();
void network_init(bool refresh); void network_init();
void button_init(bool refresh); void button_init();
void commands_init(); void commands_init();
void uart_init(bool refresh); void uart_init();
void systemStatus(uint8_t status_code); void systemStatus(uint8_t status_code);
uint8_t systemStatus(); uint8_t systemStatus();
@@ -141,7 +142,8 @@ class System {
static void extractSettings(const char * filename, const char * section, JsonObject output); static void extractSettings(const char * filename, const char * section, JsonObject output);
static bool saveSettings(const char * filename, const char * section, JsonObject input); static bool saveSettings(const char * filename, const char * section, JsonObject input);
bool is_valid_gpio(uint8_t pin, bool exclude_used = false); static bool check_valid_gpio(uint8_t pin, const char * source_name);
static std::vector<uint8_t> valid_gpio_list();
static bool load_board_profile(std::vector<int8_t> & data, const std::string & board_profile); static bool load_board_profile(std::vector<int8_t> & data, const std::string & board_profile);
static bool readCommand(const char * data); static bool readCommand(const char * data);
@@ -342,7 +344,7 @@ class System {
test_set_all_active_ = n; test_set_all_active_ = n;
} }
static std::vector<uint8_t> valid_gpio_list(bool exclude_used = false); static void set_valid_system_gpios(bool exclude_used = false);
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 #if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
float temperature() { float temperature() {
@@ -391,6 +393,9 @@ class System {
static std::vector<uint8_t> string_range_to_vector(const std::string & range); static std::vector<uint8_t> string_range_to_vector(const std::string & range);
static std::vector<uint8_t> valid_system_gpios_; // list of valid GPIOs for the ESP32 board that can be used
static std::vector<uint8_t> used_gpios_; // list of GPIOs used by the application
int8_t wifi_quality(int8_t dBm); 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 uint8_t healthcheck_ = HEALTHCHECK_NO_NETWORK | HEALTHCHECK_NO_BUS; // start with all flags set, no wifi and no ems bus connection
@@ -406,7 +411,6 @@ class System {
bool eth_present_ = false; bool eth_present_ = false;
// EMS-ESP settings // EMS-ESP settings
// copies from WebSettings class in WebSettingsService.h and loaded with reload_settings()
std::string hostname_; std::string hostname_;
String locale_; String locale_;
bool hide_led_; bool hide_led_;

View File

@@ -57,7 +57,7 @@ void TemperatureSensor::reload() {
// load the service settings // load the service settings
EMSESP::system_.dallas_gpio(0); // reset in system to check valid sensor EMSESP::system_.dallas_gpio(0); // reset in system to check valid sensor
EMSESP::webSettingsService.read([&](WebSettings const & settings) { EMSESP::webSettingsService.read([&](WebSettings const & settings) {
dallas_gpio_ = EMSESP::system_.is_valid_gpio(settings.dallas_gpio) ? settings.dallas_gpio : 0; // we use 0 for disabled dallas_gpio_ = settings.dallas_gpio;
parasite_ = settings.dallas_parasite; parasite_ = settings.dallas_parasite;
}); });
EMSESP::system_.dallas_gpio(dallas_gpio_); // set to system for checks EMSESP::system_.dallas_gpio(dallas_gpio_); // set to system for checks

View File

@@ -118,8 +118,8 @@ StateUpdateResult WebCustomization::update(JsonObject root, WebCustomization & c
for (const JsonObject analogJson : analogJsons) { for (const JsonObject analogJson : analogJsons) {
// create each of the sensor, overwriting any previous settings // create each of the sensor, overwriting any previous settings
// if the gpio is invalid skip the sensor // if the gpio is invalid skip the sensor
if (!EMSESP::system_.is_valid_gpio(analogJson["gpio"].as<uint8_t>(), true)) { if (!EMSESP::system_.check_valid_gpio(analogJson["gpio"].as<uint8_t>(), "Analog Sensor")) {
EMSESP::logger().warning("Invalid GPIO %d for Sensor %s. Skipping.", EMSESP::logger().warning("Analog sensor: Invalid GPIO %d for %s. Skipping.",
analogJson["gpio"].as<uint8_t>(), analogJson["gpio"].as<uint8_t>(),
analogJson["name"].as<std::string>().c_str()); analogJson["name"].as<std::string>().c_str());
continue; continue;

View File

@@ -145,21 +145,16 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) {
obj["f"] = sensor.factor(); obj["f"] = sensor.factor();
obj["t"] = sensor.type(); obj["t"] = sensor.type();
obj["s"] = sensor.is_system(); obj["s"] = sensor.is_system();
if (sensor.type() != AnalogSensor::AnalogType::NOTUSED) {
obj["v"] = Helpers::transformNumFloat(sensor.value()); // is optional and is a float 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
}
} }
} }
root["analog_enabled"] = EMSESP::analog_enabled(); root["analog_enabled"] = EMSESP::analog_enabled();
root["platform"] = EMSESP_PLATFORM; root["platform"] = EMSESP_PLATFORM;
// send back a list of valid GPIOs that can be used for analog sensors, excluding those already used // send back a list of valid and unused GPIOs still available for use
JsonArray valid_gpio_list = root["valid_gpio_list"].to<JsonArray>(); JsonArray valid_gpio_list = root["valid_gpio_list"].to<JsonArray>();
for (const auto & gpio : EMSESP::system_.valid_gpio_list(true)) { for (const auto & gpio : EMSESP::system_.valid_gpio_list()) {
valid_gpio_list.add(gpio); valid_gpio_list.add(gpio);
} }
@@ -437,7 +432,7 @@ void WebDataService::dashboard_data(AsyncWebServerRequest * request) {
uint8_t count = 0; uint8_t count = 0;
for (const auto & sensor : EMSESP::analogsensor_.sensors()) { for (const auto & sensor : EMSESP::analogsensor_.sensors()) {
// ignore system and disabled sensors // ignore system and disabled sensors
if (sensor.is_system() || sensor.type() == AnalogSensor::AnalogType::NOTUSED) { if (sensor.is_system()) {
continue; continue;
} }
JsonObject node = nodes.add<JsonObject>(); JsonObject node = nodes.add<JsonObject>();

View File

@@ -136,9 +136,12 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
(int8_t)(root["led_type"] | 0)}; // 0 = LED, 1 = RGB-LED (int8_t)(root["led_type"] | 0)}; // 0 = LED, 1 = RGB-LED
#endif #endif
} }
// check valid pins in this board profile // check valid pins for this board profile
if (!EMSESP::system_.is_valid_gpio(data[0]) || !EMSESP::system_.is_valid_gpio(data[1]) || !EMSESP::system_.is_valid_gpio(data[2]) if (!EMSESP::system_.check_valid_gpio(data[0], "LED") || !EMSESP::system_.check_valid_gpio(data[1], "Dallas")
|| !EMSESP::system_.is_valid_gpio(data[3]) || !EMSESP::system_.is_valid_gpio(data[4]) || !EMSESP::system_.is_valid_gpio(data[6])) { || !EMSESP::system_.check_valid_gpio(data[2], "UART Rx") || !EMSESP::system_.check_valid_gpio(data[3], "UART Tx")
|| !EMSESP::system_.check_valid_gpio(data[4], "Button") || !EMSESP::system_.check_valid_gpio(data[6], "Ethernet")) {
// set status
EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_INVALID_GPIO);
settings.board_profile = "default"; // reset to factory default settings.board_profile = "default"; // reset to factory default
} }
} else { } else {
@@ -417,7 +420,7 @@ void WebSettingsService::onUpdate() {
} }
if (WebSettings::has_flags(WebSettings::ChangeFlags::UART)) { if (WebSettings::has_flags(WebSettings::ChangeFlags::UART)) {
EMSESP::system_.uart_init(true); EMSESP::system_.uart_init();
} }
if (WebSettings::has_flags(WebSettings::ChangeFlags::SYSLOG)) { if (WebSettings::has_flags(WebSettings::ChangeFlags::SYSLOG)) {
@@ -429,11 +432,11 @@ void WebSettingsService::onUpdate() {
} }
if (WebSettings::has_flags(WebSettings::ChangeFlags::BUTTON)) { if (WebSettings::has_flags(WebSettings::ChangeFlags::BUTTON)) {
EMSESP::system_.button_init(true); EMSESP::system_.button_init();
} }
if (WebSettings::has_flags(WebSettings::ChangeFlags::LED)) { if (WebSettings::has_flags(WebSettings::ChangeFlags::LED)) {
EMSESP::system_.led_init(true); EMSESP::system_.led_init();
} }
if (WebSettings::has_flags(WebSettings::ChangeFlags::MQTT)) { if (WebSettings::has_flags(WebSettings::ChangeFlags::MQTT)) {