Instruction file imported from jantielens/esp32-macropad (
.github/instructions/adding-config-settings.instructions.md). Copyright stays with the author.
Adding New Configuration Settings
When adding new configuration settings (e.g., MQTT, custom features), follow this complete checklist. For more details on the web portal architecture and REST API, see docs/dev/web-portal.md.
1. Backend: Configuration Storage
Update config_manager.h:
- Add
#defineconstants for maximum field lengths (e.g.,CONFIG_MQTT_BROKER_MAX_LEN) - Add new fields to the
DeviceConfigstruct - For strings: Use
char field_name[CONFIG_XXX_MAX_LEN] - For numbers: Use appropriate types (
uint16_t,int,float, etc.)
Update config_manager.cpp:
- Add
#definekeys for NVS storage (e.g.,KEY_MQTT_BROKER "mqtt_broker") - Update
config_manager_load()to load new fields from NVS- Use
preferences.getString()for strings - Use
preferences.getUShort(),preferences.getInt(), etc. for numbers - Provide sensible defaults (second parameter)
- Use
- Update
config_manager_save()to save new fields to NVS- Use
preferences.putString()for strings - Use
preferences.putUShort(),preferences.putInt(), etc. for numbers
- Use
- Update
config_manager_print()to log new settings for debugging
2. Backend: Web API
Update web_portal.cpp:
- In
handleGetConfig(): Add new fields to JSON response- Use
doc["field_name"] = config->field_name - For passwords: Return empty string (
doc["password_field"] = "")
- Use
- In
handlePostConfig(): Handle new fields from JSON request- Use
if (doc.containsKey("field_name"))for partial updates - Use
doc["field_name"] | default_valuesyntax for safe extraction - Handle passwords specially (only update if non-empty)
- Use
3. Frontend: HTML Form
Update appropriate HTML page (e.g., network.html, home.html):
- Add form section with descriptive heading
- Add input fields with proper attributes:
idandnamemust match the backend field name exactlytype(text, number, password, etc.)maxlengthshould match the backend max length constantplaceholderwith helpful examplesrequiredattribute if field is mandatory
- Add
<small>helper text under each field - Use
.grid-2colclass for side-by-side layout on desktop
4. Frontend: JavaScript
Update portal.js:
- In
buildConfigFromForm()function:- Add new field names to the
fieldsarray - Fields are automatically read from form inputs by the existing code
- Add new field names to the
- In
loadConfig()function:- Add
setValueIfExists('field_name', config.field_name)calls - For passwords: Set placeholder text if saved, leave value empty
- For numbers: Use
setValueIfExists()with numeric values
- Add
- Optionally add validation in
validateConfig()if needed
5. Usage in Application Code
Initialize with loaded config:
// In setup() or after config_manager_load()
if (strlen(device_config.mqtt_broker) > 0) {
some_manager_init(&device_config);
}
Access configuration:
Serial.printf("Broker: %s:%d\n", device_config.mqtt_broker, device_config.mqtt_port);
Common Mistakes to Avoid
- Forgetting to update
portal.jsfields array — settings won't be saved - Mismatched field names between HTML
id, JS, and backend — data won't transfer - Not rebuilding after HTML/JS changes — old code still embedded in firmware
- Missing default values in load function — uninitialized data
- Not using
doc.containsKey()in POST handler — can't do partial updates