diff --git a/esphome/components/version/text_sensor.py b/esphome/components/version/text_sensor.py index ba8c493d4b..a55e18a5a7 100644 --- a/esphome/components/version/text_sensor.py +++ b/esphome/components/version/text_sensor.py @@ -1,7 +1,12 @@ import esphome.codegen as cg from esphome.components import text_sensor import esphome.config_validation as cv -from esphome.const import CONF_HIDE_TIMESTAMP, ENTITY_CATEGORY_DIAGNOSTIC, ICON_NEW_BOX +from esphome.const import ( + CONF_HIDE_HASH, + CONF_HIDE_TIMESTAMP, + ENTITY_CATEGORY_DIAGNOSTIC, + ICON_NEW_BOX, +) version_ns = cg.esphome_ns.namespace("version") VersionTextSensor = version_ns.class_( @@ -16,6 +21,9 @@ CONFIG_SCHEMA = ( .extend( { cv.GenerateID(): cv.declare_id(VersionTextSensor), + # Hide the config hash suffix and restore the pre-2026.1 + # version text format when set to true. + cv.Optional(CONF_HIDE_HASH, default=False): cv.boolean, cv.Optional(CONF_HIDE_TIMESTAMP, default=False): cv.boolean, } ) @@ -26,4 +34,5 @@ CONFIG_SCHEMA = ( async def to_code(config): var = await text_sensor.new_text_sensor(config) await cg.register_component(var, config) + cg.add(var.set_hide_hash(config[CONF_HIDE_HASH])) cg.add(var.set_hide_timestamp(config[CONF_HIDE_TIMESTAMP])) diff --git a/esphome/components/version/version_text_sensor.cpp b/esphome/components/version/version_text_sensor.cpp index 4a08001cc4..8aec98d2da 100644 --- a/esphome/components/version/version_text_sensor.cpp +++ b/esphome/components/version/version_text_sensor.cpp @@ -1,37 +1,53 @@ #include "version_text_sensor.h" #include "esphome/core/application.h" #include "esphome/core/build_info_data.h" -#include "esphome/core/log.h" -#include "esphome/core/version.h" #include "esphome/core/helpers.h" +#include "esphome/core/log.h" #include "esphome/core/progmem.h" +#include "esphome/core/version.h" namespace esphome::version { static const char *const TAG = "version.text_sensor"; void VersionTextSensor::setup() { - static const char PREFIX[] PROGMEM = ESPHOME_VERSION " (config hash 0x"; + static const char HASH_PREFIX[] PROGMEM = ESPHOME_VERSION " (config hash 0x"; + static const char VERSION_PREFIX[] PROGMEM = ESPHOME_VERSION; static const char BUILT_STR[] PROGMEM = ", built "; - // Buffer size: PREFIX + 8 hex chars + BUILT_STR + BUILD_TIME_STR_SIZE + ")" + null - constexpr size_t buf_size = sizeof(PREFIX) + 8 + sizeof(BUILT_STR) + esphome::Application::BUILD_TIME_STR_SIZE + 2; + + // Buffer size: HASH_PREFIX + 8 hex chars + BUILT_STR + BUILD_TIME_STR_SIZE + ")" + null + constexpr size_t buf_size = + sizeof(HASH_PREFIX) + 8 + sizeof(BUILT_STR) + esphome::Application::BUILD_TIME_STR_SIZE + 2; char version_str[buf_size]; - ESPHOME_strncpy_P(version_str, PREFIX, sizeof(version_str)); + // hide_hash restores the pre-2026.1 base format by omitting + // the " (config hash 0x...)" suffix entirely. + if (this->hide_hash_) { + ESPHOME_strncpy_P(version_str, VERSION_PREFIX, sizeof(version_str)); + } else { + ESPHOME_strncpy_P(version_str, HASH_PREFIX, sizeof(version_str)); - size_t len = strlen(version_str); - snprintf(version_str + len, sizeof(version_str) - len, "%08" PRIx32, App.get_config_hash()); + size_t len = strlen(version_str); + snprintf(version_str + len, sizeof(version_str) - len, "%08" PRIx32, App.get_config_hash()); + } + // Keep hide_timestamp behavior independent from hide_hash so all + // combinations remain available to users. if (!this->hide_timestamp_) { size_t len = strlen(version_str); ESPHOME_strncat_P(version_str, BUILT_STR, sizeof(version_str) - len - 1); ESPHOME_strncat_P(version_str, ESPHOME_BUILD_TIME_STR, sizeof(version_str) - strlen(version_str) - 1); } - strncat(version_str, ")", sizeof(version_str) - strlen(version_str) - 1); + // The closing parenthesis is part of the config-hash suffix and must + // only be appended when that suffix is present. + if (!this->hide_hash_) { + strncat(version_str, ")", sizeof(version_str) - strlen(version_str) - 1); + } version_str[sizeof(version_str) - 1] = '\0'; this->publish_state(version_str); } +void VersionTextSensor::set_hide_hash(bool hide_hash) { this->hide_hash_ = hide_hash; } void VersionTextSensor::set_hide_timestamp(bool hide_timestamp) { this->hide_timestamp_ = hide_timestamp; } void VersionTextSensor::dump_config() { LOG_TEXT_SENSOR("", "Version Text Sensor", this); } diff --git a/esphome/components/version/version_text_sensor.h b/esphome/components/version/version_text_sensor.h index 6153c5dd7c..fec898ae03 100644 --- a/esphome/components/version/version_text_sensor.h +++ b/esphome/components/version/version_text_sensor.h @@ -7,11 +7,13 @@ namespace esphome::version { class VersionTextSensor : public text_sensor::TextSensor, public Component { public: + void set_hide_hash(bool hide_hash); void set_hide_timestamp(bool hide_timestamp); void setup() override; void dump_config() override; protected: + bool hide_hash_{false}; bool hide_timestamp_{false}; }; diff --git a/esphome/const.py b/esphome/const.py index 0b1037d091..1611aeb101 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -463,6 +463,7 @@ CONF_HEAT_OVERRUN = "heat_overrun" CONF_HEATER = "heater" CONF_HEIGHT = "height" CONF_HIDDEN = "hidden" +CONF_HIDE_HASH = "hide_hash" CONF_HIDE_TIMESTAMP = "hide_timestamp" CONF_HIGH = "high" CONF_HIGH_VOLTAGE_REFERENCE = "high_voltage_reference" diff --git a/tests/components/version/common.yaml b/tests/components/version/common.yaml index 7713afc37c..f9ff778e14 100644 --- a/tests/components/version/common.yaml +++ b/tests/components/version/common.yaml @@ -1,3 +1,16 @@ text_sensor: - platform: version - name: "ESPHome Version" + name: "ESPHome Version Full" + + - platform: version + name: "ESPHome Version No Timestamp" + hide_timestamp: true + + - platform: version + name: "ESPHome Version No Hash" + hide_hash: true + + - platform: version + name: "ESPHome Version Shortest" + hide_timestamp: true + hide_hash: true