Skip to content

File espos_config.h

FileList > espos_config > include > espos_config.h

Go to the source code of this file

  • #include <stdbool.h>
  • #include <stddef.h>
  • #include <stdint.h>
  • #include "esp_err.h"
  • #include "espos_config_desc.h"
  • #include "espos_config_backend.h"

Classes

Type Name
struct espos_config_import_result_t

Public Types

Type Name
typedef void(* espos_config_change_cb_t
typedef struct espos_config_migrate_ctx espos_config_migrate_ctx_t
Migration step callback: move namespace ns fromfrom_version tofrom_version + 1 using the raw accessors below.
typedef esp_err_t(* espos_config_migrate_fn_t

Public Functions

Type Name
void espos_config_deinit (void)
Close namespaces and release resources (tests).
esp_err_t espos_config_export_json (const char * only_ns, bool include_secrets, char ** out_json)
Serialise the effective configuration: {"ns": {"key": value, ...}, ...} Blobs are base64 strings.
esp_err_t espos_config_factory_reset (void)
Erase the whole store.
const espos_cfg_key_t * espos_config_find_key (const espos_cfg_ns_t * ns, const char * key)
const espos_cfg_ns_t * espos_config_find_ns (const char * ns)
esp_err_t espos_config_flow_ns_name (const char * id, char * out, size_t out_size)
Build the NVS namespace name for a flow node id: "f_" + id.
esp_err_t espos_config_get_blob (const char * ns, const char * key, void * buf, size_t * len)
Blob: *len is buf size in, bytes out.
esp_err_t espos_config_get_bool (const char * ns, const char * key, bool * out)
esp_err_t espos_config_get_float (const char * ns, const char * key, float * out)
esp_err_t espos_config_get_i32 (const char * ns, const char * key, int32_t * out)
esp_err_t espos_config_get_str (const char * ns, const char * key, char * buf, size_t buf_size, size_t * out_len)
Copies the string into buf (always NUL-terminated if buf_size > 0).
esp_err_t espos_config_get_version (const char * ns, uint16_t * stored, uint16_t * current)
Stored schema version of a namespace (0 = never stamped).
esp_err_t espos_config_import_json (const char * json, size_t json_len, bool ignore_unknown, espos_config_import_result_t * result, char ** out_report_json)
Apply a JSON document of the same shape as the export.
esp_err_t espos_config_init (const espos_config_backend_t * backend, void * backend_ctx)
Initialise the store.
bool espos_config_is_ready (void)
true once espos_config_init() has succeeded (until deinit).
bool espos_config_is_set (const char * ns, const char * key)
true if the key currently has a stored (non-default) value.
esp_err_t espos_config_migrate_erase (espos_config_migrate_ctx_t * ctx, const char * key)
uint16_t espos_config_migrate_from_version (const espos_config_migrate_ctx_t * ctx)
esp_err_t espos_config_migrate_get (espos_config_migrate_ctx_t * ctx, const char * key, espos_cfg_type_t type, void * buf, size_t * len)
esp_err_t espos_config_migrate_set (espos_config_migrate_ctx_t * ctx, const char * key, espos_cfg_type_t type, const void * buf, size_t len)
esp_err_t espos_config_register_migration (const char * ns, uint16_t from_version, espos_config_migrate_fn_t fn, void * arg)
Register a migration for ns fromfrom_version →from_version + 1 .
esp_err_t espos_config_register_ns (const espos_cfg_ns_t * ns)
Add a namespace that no build-time descriptor declares.
esp_err_t espos_config_reset_key (const char * ns, const char * key)
Erase a key so it reads its default again.
esp_err_t espos_config_reset_ns (const char * ns)
Erase every key of a namespace (keeps the version stamp).
size_t espos_config_runtime_ns_count (void)
How many runtime namespaces are registered right now.
void espos_config_schema_etag (char etag)
Just the current ETag text (no quotes), for callers that only compare.
esp_err_t espos_config_schema_json (char ** out, char etag)
esp_err_t espos_config_set_blob (const char * ns, const char * key, const void * buf, size_t len)
esp_err_t espos_config_set_bool (const char * ns, const char * key, bool v)
esp_err_t espos_config_set_float (const char * ns, const char * key, float v)
esp_err_t espos_config_set_i32 (const char * ns, const char * key, int32_t v)
esp_err_t espos_config_set_str (const char * ns, const char * key, const char * v)
bool espos_config_storage_was_reset (void)
true if the backend had to wipe storage during init (values are defaults).
esp_err_t espos_config_subscribe (espos_config_change_cb_t cb, void * arg)
Called after each committed change (per key), on the writer's task, with the store lock released (a callback may read or write config).
esp_err_t espos_config_unregister_ns (const char * ns)
Remove a runtime namespace.
esp_err_t espos_config_unsubscribe (espos_config_change_cb_t cb, void * arg)

Macros

Type Name
define ESPOS_CFG_ETAG_MAX 24
The JSON Schema of the whole configuration document, static namespaces and runtime ones merged.
define ESPOS_CONFIG_SECRET_SENTINEL "\*\*\*\*\*\*\*\*"

Public Types Documentation

typedef espos_config_change_cb_t

typedef void(* espos_config_change_cb_t) (const char *ns, const char *key, void *arg);

typedef espos_config_migrate_ctx_t

Migration step callback: move namespace ns fromfrom_version tofrom_version + 1 using the raw accessors below.

typedef struct espos_config_migrate_ctx espos_config_migrate_ctx_t;

Return ESP_OK on success; anything else aborts the chain (the stored version stays at from_version and a warning is logged; reads still work via defaults on type mismatch). Only the espos_config_migrate_* accessors may be used inside; the public getters/setters return ESP_ERR_INVALID_STATE (the store is not up yet).


typedef espos_config_migrate_fn_t

typedef esp_err_t(* espos_config_migrate_fn_t) (espos_config_migrate_ctx_t *ctx, void *arg);

Public Functions Documentation

function espos_config_deinit

Close namespaces and release resources (tests).

void espos_config_deinit (
    void
) 


function espos_config_export_json

Serialise the effective configuration: {"ns": {"key": value, ...}, ...} Blobs are base64 strings.

esp_err_t espos_config_export_json (
    const char * only_ns,
    bool include_secrets,
    char ** out_json
) 

Secret values become ESPOS_CONFIG_SECRET_SENTINEL unless include_secrets. only_ns restricts to one namespace (NULL = all). The returned string is malloc'ed; caller frees.


function espos_config_factory_reset

Erase the whole store.

esp_err_t espos_config_factory_reset (
    void
) 

Does NOT reboot; the caller should call esp_restart() promptly since the in-RAM state no longer matches storage.


function espos_config_find_key

const espos_cfg_key_t * espos_config_find_key (
    const espos_cfg_ns_t * ns,
    const char * key
) 

function espos_config_find_ns

const espos_cfg_ns_t * espos_config_find_ns (
    const char * ns
) 

function espos_config_flow_ns_name

Build the NVS namespace name for a flow node id: "f_" + id.

esp_err_t espos_config_flow_ns_name (
    const char * id,
    char * out,
    size_t out_size
) 

Parameters:

  • id node id, 1..ESPOS_CFG_RUNTIME_ID_MAX characters of [a-z0-9_] (the NVS 15-character limit minus the prefix).
  • out receives the name; needs ESPOS_CFG_NS_NAME_MAX + 1 bytes.

Returns:

ESP_ERR_INVALID_ARG if the id is empty, too long, or has a character NVS/the schema cannot carry.


function espos_config_get_blob

Blob: *len is buf size in, bytes out.

esp_err_t espos_config_get_blob (
    const char * ns,
    const char * key,
    void * buf,
    size_t * len
) 

buf==NULL → size query (ESP_OK, *len set). An absent blob is ESP_OK with *len = 0.


function espos_config_get_bool

esp_err_t espos_config_get_bool (
    const char * ns,
    const char * key,
    bool * out
) 

function espos_config_get_float

esp_err_t espos_config_get_float (
    const char * ns,
    const char * key,
    float * out
) 

function espos_config_get_i32

esp_err_t espos_config_get_i32 (
    const char * ns,
    const char * key,
    int32_t * out
) 

function espos_config_get_str

Copies the string into buf (always NUL-terminated if buf_size > 0).

esp_err_t espos_config_get_str (
    const char * ns,
    const char * key,
    char * buf,
    size_t buf_size,
    size_t * out_len
) 

*out_len, if non-NULL, receives the full length (excluding NUL). If the value does not fit, returns ESP_ERR_INVALID_SIZE and buf holds a truncated copy.


function espos_config_get_version

Stored schema version of a namespace (0 = never stamped).

esp_err_t espos_config_get_version (
    const char * ns,
    uint16_t * stored,
    uint16_t * current
) 


function espos_config_import_json

Apply a JSON document of the same shape as the export.

esp_err_t espos_config_import_json (
    const char * json,
    size_t json_len,
    bool ignore_unknown,
    espos_config_import_result_t * result,
    char ** out_report_json
) 

Semantics: * namespaces/keys not present are left untouched * a key set to null is reset to its default * a secret whose value is the sentinel is left untouched * the whole document is validated first; on any error nothing is written and ESP_ERR_INVALID_ARG is returned with result->error_* filled in * unknown namespaces/keys are errors (unless ignore_unknown) out_report_json (optional) receives a malloc'ed JSON report of the form {"changed":["ns.key",...],"restart_required":false} on success, or {"error":"validation","path":"ns.key","message":"..."} on ESP_ERR_INVALID_ARG. Caller frees.


function espos_config_init

Initialise the store.

esp_err_t espos_config_init (
    const espos_config_backend_t * backend,
    void * backend_ctx
) 

Opens every declared namespace, then runs schema migrations (see espos_config_register_migration) and stamps the current version. Must be called before any other function.

Parameters:

  • backend NULL for the NVS backend, or an injected backend (tests).
  • backend_ctx passed through to the backend.

function espos_config_is_ready

true once espos_config_init() has succeeded (until deinit).

bool espos_config_is_ready (
    void
) 

The order guard the other components use: espos_httpd_start() refuses to run before the store is up, because every handler it registers reads from it.


function espos_config_is_set

true if the key currently has a stored (non-default) value.

bool espos_config_is_set (
    const char * ns,
    const char * key
) 


function espos_config_migrate_erase

esp_err_t espos_config_migrate_erase (
    espos_config_migrate_ctx_t * ctx,
    const char * key
) 

function espos_config_migrate_from_version

uint16_t espos_config_migrate_from_version (
    const espos_config_migrate_ctx_t * ctx
) 

function espos_config_migrate_get

esp_err_t espos_config_migrate_get (
    espos_config_migrate_ctx_t * ctx,
    const char * key,
    espos_cfg_type_t type,
    void * buf,
    size_t * len
) 

function espos_config_migrate_set

esp_err_t espos_config_migrate_set (
    espos_config_migrate_ctx_t * ctx,
    const char * key,
    espos_cfg_type_t type,
    const void * buf,
    size_t len
) 

function espos_config_register_migration

Register a migration for ns fromfrom_version →from_version + 1 .

esp_err_t espos_config_register_migration (
    const char * ns,
    uint16_t from_version,
    espos_config_migrate_fn_t fn,
    void * arg
) 

Call before espos_config_init(). Steps without a registered function are treated as additive (no-op) — new keys simply read their defaults.

Returns:

ESP_ERR_NO_MEM if the table is full, ESP_ERR_INVALID_ARG if ns is unknown or from_version >= current version.


function espos_config_register_ns

Add a namespace that no build-time descriptor declares.

esp_err_t espos_config_register_ns (
    const espos_cfg_ns_t * ns
) 

A graph node built at run time — Linear("cal", …) with its own multiplier and offset — has no CMake of its own to register a descriptor from, yet its settings must be editable in the web UI and survive a reboot like any other. It builds an espos_cfg_ns_t (typically a static ParamSet inside the node class) and registers it here; from that moment the namespace behaves exactly like a compiled one: typed access, validation, export/import, and a section in the JSON Schema.

Ownership: the descriptor, its key array, every string it points at and any enum/column table must outlive the registration. Nothing is copied — a table on the stack, or one freed while registered, is a use-after-free. Static storage in the registering node is the intended shape.

ns->name must be a valid NVS namespace: 1..15 characters of [a-z0-9_], not already taken by a static or runtime namespace. Use espos_config_flow_ns_name() to build one from a node id.

Calling this after espos_config_init() is the normal case (the graph is built once the store is up); before init works too, and the namespace is opened along with the static ones. Every failure is logged with the offending name and raises the flowConfig health condition, because a node whose settings silently do not appear is far worse than a loud error.

Returns:

ESP_OK, ESP_ERR_INVALID_ARG malformed descriptor or name, ESP_ERR_INVALID_STATE name already registered, ESP_ERR_NO_MEM table full (CONFIG_ESPOS_CONFIG_MAX_RUNTIME_NS), or a backend error if the namespace could not be opened. Thread-safe; may be called from any task.


function espos_config_reset_key

Erase a key so it reads its default again.

esp_err_t espos_config_reset_key (
    const char * ns,
    const char * key
) 


function espos_config_reset_ns

Erase every key of a namespace (keeps the version stamp).

esp_err_t espos_config_reset_ns (
    const char * ns
) 


function espos_config_runtime_ns_count

How many runtime namespaces are registered right now.

size_t espos_config_runtime_ns_count (
    void
) 


function espos_config_schema_etag

Just the current ETag text (no quotes), for callers that only compare.

void espos_config_schema_etag (
    char etag
) 


function espos_config_schema_json

esp_err_t espos_config_schema_json (
    char ** out,
    char etag
) 

function espos_config_set_blob

esp_err_t espos_config_set_blob (
    const char * ns,
    const char * key,
    const void * buf,
    size_t len
) 

function espos_config_set_bool

esp_err_t espos_config_set_bool (
    const char * ns,
    const char * key,
    bool v
) 

function espos_config_set_float

esp_err_t espos_config_set_float (
    const char * ns,
    const char * key,
    float v
) 

function espos_config_set_i32

esp_err_t espos_config_set_i32 (
    const char * ns,
    const char * key,
    int32_t v
) 

function espos_config_set_str

esp_err_t espos_config_set_str (
    const char * ns,
    const char * key,
    const char * v
) 

function espos_config_storage_was_reset

true if the backend had to wipe storage during init (values are defaults).

bool espos_config_storage_was_reset (
    void
) 


function espos_config_subscribe

Called after each committed change (per key), on the writer's task, with the store lock released (a callback may read or write config).

esp_err_t espos_config_subscribe (
    espos_config_change_cb_t cb,
    void * arg
) 

Small fixed table. A callback that is already in flight on another task may still complete after espos_config_unsubscribe() returns.


function espos_config_unregister_ns

Remove a runtime namespace.

esp_err_t espos_config_unregister_ns (
    const char * ns
) 

Stored values are left in NVS untouched (the node may come back on the next boot) — use espos_config_reset_ns() first to discard them. Only namespaces added by espos_config_register_ns() can be removed; a compiled one returns ESP_ERR_INVALID_ARG.

The caller must ensure no other task is reading that namespace: after this returns, the descriptor memory may be freed.


function espos_config_unsubscribe

esp_err_t espos_config_unsubscribe (
    espos_config_change_cb_t cb,
    void * arg
) 

Macro Definition Documentation

define ESPOS_CFG_ETAG_MAX

The JSON Schema of the whole configuration document, static namespaces and runtime ones merged.

#define ESPOS_CFG_ETAG_MAX `24`

With no runtime namespace registered this is byte-for-byte the compiled espos_cfg_schema_json and the compiled ETag, so the common case costs one strdup and nothing else changes downstream.

Parameters:

  • out receives a malloc'ed NUL-terminated document; caller frees.
  • etag receives the ETag text (no quotes), or NULL if not wanted. Needs ESPOS_CFG_ETAG_MAX bytes. It changes whenever a namespace is registered or unregistered, so a browser holding the old schema revalidates instead of rendering a stale form.

define ESPOS_CONFIG_SECRET_SENTINEL

#define ESPOS_CONFIG_SECRET_SENTINEL `"********"`


The documentation for this class was generated from the following file espos_config/include/espos_config.h