ESPHome 2026.9.0-dev
Loading...
Searching...
No Matches
preference_backend.h
Go to the documentation of this file.
1#pragma once
2
3#include <concepts>
4#include <cstdint>
5
8
9// Include the concrete preference backend for the active platform.
10// Each header defines its backend class, forward-declares its manager class,
11// declares get_preferences(), and provides the PreferenceBackend alias.
12#ifdef USE_ESP32
14#elif defined(USE_ESP8266)
16#elif defined(USE_RP2)
18#elif defined(USE_LIBRETINY)
20#elif defined(USE_HOST)
22#elif defined(USE_ZEPHYR) && defined(CONFIG_SETTINGS)
24#endif
25
26// Key-lookup preference backends find stored data by key; their platforms add the
27// USE_PREFERENCE_KEY_LOOKUP define from Python codegen, which enables one-shot reads
28// of stored data by key (the primitive preference key migrations need). Slot-based
29// backends (ESP8266, RP2040) instead allocate a storage slot for every
30// make_preference() call and use the key only as a validity tag on that slot;
31// migration is not possible there, and key collisions cannot corrupt data.
32
33namespace esphome {
34
35// The PreferenceBackend method surface, asserted on the alias each platform
36// header binds. save() persists len bytes; load() fills dest only when the
37// stored data exists and matches len. Both report success as their return.
38template<typename T>
39concept PreferenceBackendContract = requires(T backend, const uint8_t *src, uint8_t *dest, size_t len) {
40 { backend.save(src, len) } -> std::same_as<bool>;
41 { backend.load(dest, len) } -> std::same_as<bool>;
42};
43
44#if !defined(USE_ESP32) && !defined(USE_ESP8266) && !defined(USE_RP2) && !defined(USE_LIBRETINY) && \
45 !defined(USE_HOST) && !(defined(USE_ZEPHYR) && defined(CONFIG_SETTINGS))
46// Stub for static analysis when no platform is defined.
48 bool save(const uint8_t *, size_t) { return false; }
49 bool load(uint8_t *, size_t) { return false; }
50};
51#endif
52
55 "The platform's preference backend is missing part of the PreferenceBackend surface");
56
58 public:
60 explicit ESPPreferenceObject(PreferenceBackend *backend) : backend_(backend) {}
61
62 template<typename T> bool save(const T *src) { return this->save(reinterpret_cast<const uint8_t *>(src), sizeof(T)); }
63
64 template<typename T> bool load(T *dest) { return this->load(reinterpret_cast<uint8_t *>(dest), sizeof(T)); }
65
67 bool save(const uint8_t *src, size_t len) {
68 if (this->backend_ == nullptr)
69 return false;
70 return this->backend_->save(src, len);
71 }
72
74 bool load(uint8_t *dest, size_t len) {
75 if (this->backend_ == nullptr)
76 return false;
77 return this->backend_->load(dest, len);
78 }
79
80 protected:
82};
83
84// The preferences manager method surface, asserted in esphome/core/preferences.h
85// on the ESPPreferences alias each platform's preferences.h binds through
86// DECLARE_PREFERENCE_ALIASES. Semantics beyond the signatures:
87// - make_preference: the two-argument form applies the platform's historic
88// default storage; in_flash=false may fall back to flash where the platform
89// has no faster storage.
90// - sync: commit pending writes to flash, true on success.
91// - reset: forget unsaved changes and re-initialize the permanent storage
92// (usually followed by a restart), true on success.
93// The template forms are what component call sites use; PreferencesMixin
94// supplies them, but the derived class's non-template overloads hide them
95// unless it also declares `using PreferencesMixin<X>::make_preference;`, so
96// the concept pins those too.
97template<typename T>
98concept PreferencesContract = requires(T prefs, size_t len, uint32_t type, bool in_flash) {
99 { prefs.make_preference(len, type, in_flash) } -> std::same_as<ESPPreferenceObject>;
100 { prefs.make_preference(len, type) } -> std::same_as<ESPPreferenceObject>;
101 { prefs.template make_preference<uint32_t>(type, in_flash) } -> std::same_as<ESPPreferenceObject>;
102 { prefs.template make_preference<uint32_t>(type) } -> std::same_as<ESPPreferenceObject>;
103 { prefs.sync() } -> std::same_as<bool>;
104 { prefs.reset() } -> std::same_as<bool>;
105};
106
107// Key-lookup platforms additionally provide load_from_key(), a one-shot read
108// of a stored preference by key; see the key-lookup note at the top of this
109// file. Not part of PreferencesContract, so it is asserted in preferences.h
110// only where USE_PREFERENCE_KEY_LOOKUP is set.
111template<typename T>
112concept PreferencesKeyLookupContract = requires(T prefs, uint32_t type, uint8_t *data, size_t len) {
113 { prefs.load_from_key(type, data, len) } -> std::same_as<bool>;
114};
115
118template<typename Derived> class PreferencesMixin {
119 public:
120 template<typename T, enable_if_t<is_trivially_copyable<T>::value, bool> = true>
122 return static_cast<Derived *>(this)->make_preference(sizeof(T), type, in_flash);
123 }
124
125 template<typename T, enable_if_t<is_trivially_copyable<T>::value, bool> = true>
127 return static_cast<Derived *>(this)->make_preference(sizeof(T), type);
128 }
129
130 private:
131 PreferencesMixin() = default;
132 friend Derived;
133};
134
135// Macro for platform preferences.h headers to declare the standard aliases.
136// Must be used at file scope (outside any namespace).
137#define DECLARE_PREFERENCE_ALIASES(platform_class) \
138 namespace esphome { \
139 using Preferences = platform_class; \
140 using ESPPreferences = Preferences; \
141 extern ESPPreferences *global_preferences; /* NOLINT(cppcoreguidelines-avoid-non-const-global-variables) */ \
142 }
143
144} // namespace esphome
ESPPreferenceObject(PreferenceBackend *backend)
bool save(const uint8_t *src, size_t len)
Raw save with explicit length, for callers that only know the size at runtime.
bool load(uint8_t *dest, size_t len)
Raw load with explicit length, for callers that only know the size at runtime.
CRTP mixin providing type-safe template make_preference<T>() helpers.
ESPPreferenceObject make_preference(uint32_t type)
ESPPreferenceObject make_preference(uint32_t type, bool in_flash)
uint16_t type
const void size_t len
Definition hal.h:64
esp32::ESP32PreferenceBackend PreferenceBackend
const void * src
Definition hal.h:64
static void uint32_t
bool save(const uint8_t *, size_t)
bool load(uint8_t *, size_t)