Add get_config_version_hash() and make hash functions constexpr

Add Application::get_config_version_hash() as a constexpr that returns
fnv1a_hash_extend(config_hash, ESPHOME_VERSION).

Make get_config_hash(), get_build_time(), fnv1a_hash(), and
fnv1a_hash_extend() constexpr inline functions.

Replace open-coded fnv1a_hash_extend(config_hash, ESPHOME_VERSION)
calls with get_config_version_hash() in sensor and wifi components.

Remove now-unnecessary version.h includes from component files.
This commit is contained in:
David Woodhouse
2025-12-16 17:15:19 +00:00
parent 7298db0a7e
commit 38167c268f
8 changed files with 21 additions and 30 deletions

View File

@@ -3,7 +3,6 @@
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include "esphome/core/version.h"
#include <cinttypes>
namespace esphome {
@@ -159,8 +158,7 @@ void SEN5XComponent::setup() {
// Hash with config hash, version, and serial number
// This ensures the baseline storage is cleared after OTA
// Serial numbers are unique to each sensor, so multiple sensors can be used without conflict
uint32_t hash = fnv1a_hash_extend(App.get_config_hash(), ESPHOME_VERSION);
hash = fnv1a_hash_extend(hash, std::to_string(combined_serial));
uint32_t hash = fnv1a_hash_extend(App.get_config_version_hash(), std::to_string(combined_serial));
this->pref_ = global_preferences->make_preference<Sen5xBaselines>(hash, true);
if (this->pref_.load(&this->voc_baselines_storage_)) {

View File

@@ -3,7 +3,6 @@
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include "esphome/core/version.h"
#include <cinttypes>
@@ -76,8 +75,7 @@ void SGP30Component::setup() {
// Hash with config hash, version, and serial number
// This ensures the baseline storage is cleared after OTA
// Serial numbers are unique to each sensor, so multiple sensors can be used without conflict
uint32_t hash = fnv1a_hash_extend(App.get_config_hash(), ESPHOME_VERSION);
hash = fnv1a_hash_extend(hash, std::to_string(this->serial_number_));
uint32_t hash = fnv1a_hash_extend(App.get_config_version_hash(), std::to_string(this->serial_number_));
this->pref_ = global_preferences->make_preference<SGP30Baselines>(hash, true);
if (this->store_baseline_ && this->pref_.load(&this->baselines_storage_)) {

View File

@@ -2,7 +2,6 @@
#include "esphome/core/application.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
#include "esphome/core/version.h"
#include <cinttypes>
namespace esphome {
@@ -61,8 +60,7 @@ void SGP4xComponent::setup() {
// Hash with config hash, version, and serial number
// This ensures the baseline storage is cleared after OTA
// Serial numbers are unique to each sensor, so multiple sensors can be used without conflict
uint32_t hash = fnv1a_hash_extend(App.get_config_hash(), ESPHOME_VERSION);
hash = fnv1a_hash_extend(hash, std::to_string(this->serial_number_));
uint32_t hash = fnv1a_hash_extend(App.get_config_version_hash(), std::to_string(this->serial_number_));
this->pref_ = global_preferences->make_preference<SGP4xBaselines>(hash, true);
if (this->pref_.load(&this->voc_baselines_storage_)) {

View File

@@ -28,7 +28,6 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include "esphome/core/util.h"
#include "esphome/core/version.h"
#ifdef USE_CAPTIVE_PORTAL
#include "esphome/components/captive_portal/captive_portal.h"
@@ -376,7 +375,7 @@ void WiFiComponent::start() {
get_mac_address_pretty_into_buffer(mac_s));
this->last_connected_ = millis();
uint32_t hash = this->has_sta() ? fnv1a_hash_extend(App.get_config_hash(), ESPHOME_VERSION) : 88491487UL;
uint32_t hash = this->has_sta() ? App.get_config_version_hash() : 88491487UL;
this->pref_ = global_preferences->make_preference<wifi::SavedWifiSettings>(hash, true);
#ifdef USE_WIFI_FAST_CONNECT

View File

@@ -719,10 +719,6 @@ void Application::wake_loop_threadsafe() {
}
#endif // defined(USE_SOCKET_SELECT_SUPPORT) && defined(USE_WAKE_LOOP_THREADSAFE)
uint32_t Application::get_config_hash() { return ESPHOME_CONFIG_HASH; }
time_t Application::get_build_time() { return ESPHOME_BUILD_TIME; }
void Application::get_build_time_string(std::span<char, BUILD_TIME_STR_SIZE> buffer) {
#ifdef USE_ESP8266
strncpy_P(buffer.data(), ESPHOME_BUILD_TIME_STR, buffer.size());

View File

@@ -6,6 +6,7 @@
#include <span>
#include <string>
#include <vector>
#include "esphome/core/build_info_data.h"
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"
@@ -13,6 +14,7 @@
#include "esphome/core/preferences.h"
#include "esphome/core/scheduler.h"
#include "esphome/core/string_ref.h"
#include "esphome/core/version.h"
#ifdef USE_DEVICES
#include "esphome/core/device.h"
@@ -266,10 +268,13 @@ class Application {
static constexpr size_t BUILD_TIME_STR_SIZE = 26;
/// Get the config hash as a 32-bit integer
uint32_t get_config_hash();
constexpr uint32_t get_config_hash() { return ESPHOME_CONFIG_HASH; }
/// Get the config hash extended with ESPHome version
constexpr uint32_t get_config_version_hash() { return fnv1a_hash_extend(ESPHOME_CONFIG_HASH, ESPHOME_VERSION); }
/// Get the build time as a Unix timestamp
time_t get_build_time();
constexpr time_t get_build_time() { return ESPHOME_BUILD_TIME; }
/// Copy the build time string into the provided buffer
/// Buffer must be BUILD_TIME_STR_SIZE bytes (compile-time enforced)

View File

@@ -155,17 +155,6 @@ uint32_t fnv1_hash(const char *str) {
return hash;
}
// FNV-1a hash - preferred for new code
uint32_t fnv1a_hash_extend(uint32_t hash, const char *str) {
if (str) {
while (*str) {
hash ^= *str++;
hash *= FNV1_PRIME;
}
}
return hash;
}
float random_float() { return static_cast<float>(random_uint32()) / static_cast<float>(UINT32_MAX); }
// Strings

View File

@@ -388,12 +388,20 @@ constexpr uint32_t FNV1_OFFSET_BASIS = 2166136261UL;
constexpr uint32_t FNV1_PRIME = 16777619UL;
/// Extend a FNV-1a hash with additional string data.
uint32_t fnv1a_hash_extend(uint32_t hash, const char *str);
constexpr uint32_t fnv1a_hash_extend(uint32_t hash, const char *str) {
if (str) {
while (*str) {
hash ^= *str++;
hash *= FNV1_PRIME;
}
}
return hash;
}
inline uint32_t fnv1a_hash_extend(uint32_t hash, const std::string &str) {
return fnv1a_hash_extend(hash, str.c_str());
}
/// Calculate a FNV-1a hash of \p str.
inline uint32_t fnv1a_hash(const char *str) { return fnv1a_hash_extend(FNV1_OFFSET_BASIS, str); }
constexpr uint32_t fnv1a_hash(const char *str) { return fnv1a_hash_extend(FNV1_OFFSET_BASIS, str); }
inline uint32_t fnv1a_hash(const std::string &str) { return fnv1a_hash(str.c_str()); }
/// Return a random 32-bit unsigned integer.