diff --git a/esphome/components/mqtt/mqtt_alarm_control_panel.cpp b/esphome/components/mqtt/mqtt_alarm_control_panel.cpp index dc8f75d8f5..a461a140ae 100644 --- a/esphome/components/mqtt/mqtt_alarm_control_panel.cpp +++ b/esphome/components/mqtt/mqtt_alarm_control_panel.cpp @@ -13,31 +13,12 @@ static const char *const TAG = "mqtt.alarm_control_panel"; using namespace esphome::alarm_control_panel; +// Alarm state MQTT strings indexed by AlarmControlPanelState enum (0-9) +PROGMEM_STRING_TABLE(AlarmMqttStateStrings, "disarmed", "armed_home", "armed_away", "armed_night", "armed_vacation", + "armed_custom_bypass", "pending", "arming", "disarming", "triggered", "unknown"); + static ProgmemStr alarm_state_to_mqtt_str(AlarmControlPanelState state) { - switch (state) { - case ACP_STATE_DISARMED: - return ESPHOME_F("disarmed"); - case ACP_STATE_ARMED_HOME: - return ESPHOME_F("armed_home"); - case ACP_STATE_ARMED_AWAY: - return ESPHOME_F("armed_away"); - case ACP_STATE_ARMED_NIGHT: - return ESPHOME_F("armed_night"); - case ACP_STATE_ARMED_VACATION: - return ESPHOME_F("armed_vacation"); - case ACP_STATE_ARMED_CUSTOM_BYPASS: - return ESPHOME_F("armed_custom_bypass"); - case ACP_STATE_PENDING: - return ESPHOME_F("pending"); - case ACP_STATE_ARMING: - return ESPHOME_F("arming"); - case ACP_STATE_DISARMING: - return ESPHOME_F("disarming"); - case ACP_STATE_TRIGGERED: - return ESPHOME_F("triggered"); - default: - return ESPHOME_F("unknown"); - } + return AlarmMqttStateStrings::get_progmem_str(static_cast(state), AlarmMqttStateStrings::LAST_INDEX); } MQTTAlarmControlPanelComponent::MQTTAlarmControlPanelComponent(AlarmControlPanel *alarm_control_panel) diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index 382b4a350f..cc3a4f3231 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -8,6 +8,7 @@ #include "esphome/core/entity_base.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" +#include "esphome/core/progmem.h" #include "esphome/core/version.h" #ifdef USE_LOGGER #include "esphome/components/logger/logger.h" @@ -27,6 +28,11 @@ namespace esphome::mqtt { static const char *const TAG = "mqtt"; +// Disconnect reason strings indexed by MQTTClientDisconnectReason enum (0-8) +PROGMEM_STRING_TABLE(MQTTDisconnectReasonStrings, "TCP disconnected", "Unacceptable Protocol Version", + "Identifier Rejected", "Server Unavailable", "Malformed Credentials", "Not Authorized", + "Not Enough Space", "TLS Bad Fingerprint", "DNS Resolve Error", "Unknown"); + MQTTClientComponent::MQTTClientComponent() { global_mqtt_client = this; char mac_addr[MAC_ADDRESS_BUFFER_SIZE]; @@ -348,36 +354,8 @@ void MQTTClientComponent::loop() { mqtt_backend_.loop(); if (this->disconnect_reason_.has_value()) { - const LogString *reason_s; - switch (*this->disconnect_reason_) { - case MQTTClientDisconnectReason::TCP_DISCONNECTED: - reason_s = LOG_STR("TCP disconnected"); - break; - case MQTTClientDisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION: - reason_s = LOG_STR("Unacceptable Protocol Version"); - break; - case MQTTClientDisconnectReason::MQTT_IDENTIFIER_REJECTED: - reason_s = LOG_STR("Identifier Rejected"); - break; - case MQTTClientDisconnectReason::MQTT_SERVER_UNAVAILABLE: - reason_s = LOG_STR("Server Unavailable"); - break; - case MQTTClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS: - reason_s = LOG_STR("Malformed Credentials"); - break; - case MQTTClientDisconnectReason::MQTT_NOT_AUTHORIZED: - reason_s = LOG_STR("Not Authorized"); - break; - case MQTTClientDisconnectReason::ESP8266_NOT_ENOUGH_SPACE: - reason_s = LOG_STR("Not Enough Space"); - break; - case MQTTClientDisconnectReason::TLS_BAD_FINGERPRINT: - reason_s = LOG_STR("TLS Bad Fingerprint"); - break; - default: - reason_s = LOG_STR("Unknown"); - break; - } + const LogString *reason_s = MQTTDisconnectReasonStrings::get_log_str( + static_cast(*this->disconnect_reason_), MQTTDisconnectReasonStrings::LAST_INDEX); if (!network::is_connected()) { reason_s = LOG_STR("WiFi disconnected"); } diff --git a/esphome/components/mqtt/mqtt_climate.cpp b/esphome/components/mqtt/mqtt_climate.cpp index 673593ef84..158cfb5552 100644 --- a/esphome/components/mqtt/mqtt_climate.cpp +++ b/esphome/components/mqtt/mqtt_climate.cpp @@ -13,109 +13,44 @@ static const char *const TAG = "mqtt.climate"; using namespace esphome::climate; +// Climate mode MQTT strings indexed by ClimateMode enum (0-6): OFF, HEAT_COOL, COOL, HEAT, FAN_ONLY, DRY, AUTO +PROGMEM_STRING_TABLE(ClimateMqttModeStrings, "off", "heat_cool", "cool", "heat", "fan_only", "dry", "auto", "unknown"); + static ProgmemStr climate_mode_to_mqtt_str(ClimateMode mode) { - switch (mode) { - case CLIMATE_MODE_OFF: - return ESPHOME_F("off"); - case CLIMATE_MODE_HEAT_COOL: - return ESPHOME_F("heat_cool"); - case CLIMATE_MODE_AUTO: - return ESPHOME_F("auto"); - case CLIMATE_MODE_COOL: - return ESPHOME_F("cool"); - case CLIMATE_MODE_HEAT: - return ESPHOME_F("heat"); - case CLIMATE_MODE_FAN_ONLY: - return ESPHOME_F("fan_only"); - case CLIMATE_MODE_DRY: - return ESPHOME_F("dry"); - default: - return ESPHOME_F("unknown"); - } + return ClimateMqttModeStrings::get_progmem_str(static_cast(mode), ClimateMqttModeStrings::LAST_INDEX); } +// Climate action MQTT strings indexed by ClimateAction enum (0,2-6): OFF, (gap), COOLING, HEATING, IDLE, DRYING, FAN +PROGMEM_STRING_TABLE(ClimateMqttActionStrings, "off", "unknown", "cooling", "heating", "idle", "drying", "fan", + "unknown"); + static ProgmemStr climate_action_to_mqtt_str(ClimateAction action) { - switch (action) { - case CLIMATE_ACTION_OFF: - return ESPHOME_F("off"); - case CLIMATE_ACTION_COOLING: - return ESPHOME_F("cooling"); - case CLIMATE_ACTION_HEATING: - return ESPHOME_F("heating"); - case CLIMATE_ACTION_IDLE: - return ESPHOME_F("idle"); - case CLIMATE_ACTION_DRYING: - return ESPHOME_F("drying"); - case CLIMATE_ACTION_FAN: - return ESPHOME_F("fan"); - default: - return ESPHOME_F("unknown"); - } + return ClimateMqttActionStrings::get_progmem_str(static_cast(action), ClimateMqttActionStrings::LAST_INDEX); } +// Climate fan mode MQTT strings indexed by ClimateFanMode enum (0-9) +PROGMEM_STRING_TABLE(ClimateMqttFanModeStrings, "on", "off", "auto", "low", "medium", "high", "middle", "focus", + "diffuse", "quiet", "unknown"); + static ProgmemStr climate_fan_mode_to_mqtt_str(ClimateFanMode fan_mode) { - switch (fan_mode) { - case CLIMATE_FAN_ON: - return ESPHOME_F("on"); - case CLIMATE_FAN_OFF: - return ESPHOME_F("off"); - case CLIMATE_FAN_AUTO: - return ESPHOME_F("auto"); - case CLIMATE_FAN_LOW: - return ESPHOME_F("low"); - case CLIMATE_FAN_MEDIUM: - return ESPHOME_F("medium"); - case CLIMATE_FAN_HIGH: - return ESPHOME_F("high"); - case CLIMATE_FAN_MIDDLE: - return ESPHOME_F("middle"); - case CLIMATE_FAN_FOCUS: - return ESPHOME_F("focus"); - case CLIMATE_FAN_DIFFUSE: - return ESPHOME_F("diffuse"); - case CLIMATE_FAN_QUIET: - return ESPHOME_F("quiet"); - default: - return ESPHOME_F("unknown"); - } + return ClimateMqttFanModeStrings::get_progmem_str(static_cast(fan_mode), + ClimateMqttFanModeStrings::LAST_INDEX); } +// Climate swing mode MQTT strings indexed by ClimateSwingMode enum (0-3): OFF, BOTH, VERTICAL, HORIZONTAL +PROGMEM_STRING_TABLE(ClimateMqttSwingModeStrings, "off", "both", "vertical", "horizontal", "unknown"); + static ProgmemStr climate_swing_mode_to_mqtt_str(ClimateSwingMode swing_mode) { - switch (swing_mode) { - case CLIMATE_SWING_OFF: - return ESPHOME_F("off"); - case CLIMATE_SWING_BOTH: - return ESPHOME_F("both"); - case CLIMATE_SWING_VERTICAL: - return ESPHOME_F("vertical"); - case CLIMATE_SWING_HORIZONTAL: - return ESPHOME_F("horizontal"); - default: - return ESPHOME_F("unknown"); - } + return ClimateMqttSwingModeStrings::get_progmem_str(static_cast(swing_mode), + ClimateMqttSwingModeStrings::LAST_INDEX); } +// Climate preset MQTT strings indexed by ClimatePreset enum (0-7) +PROGMEM_STRING_TABLE(ClimateMqttPresetStrings, "none", "home", "away", "boost", "comfort", "eco", "sleep", "activity", + "unknown"); + static ProgmemStr climate_preset_to_mqtt_str(ClimatePreset preset) { - switch (preset) { - case CLIMATE_PRESET_NONE: - return ESPHOME_F("none"); - case CLIMATE_PRESET_HOME: - return ESPHOME_F("home"); - case CLIMATE_PRESET_ECO: - return ESPHOME_F("eco"); - case CLIMATE_PRESET_AWAY: - return ESPHOME_F("away"); - case CLIMATE_PRESET_BOOST: - return ESPHOME_F("boost"); - case CLIMATE_PRESET_COMFORT: - return ESPHOME_F("comfort"); - case CLIMATE_PRESET_SLEEP: - return ESPHOME_F("sleep"); - case CLIMATE_PRESET_ACTIVITY: - return ESPHOME_F("activity"); - default: - return ESPHOME_F("unknown"); - } + return ClimateMqttPresetStrings::get_progmem_str(static_cast(preset), ClimateMqttPresetStrings::LAST_INDEX); } void MQTTClimateComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { diff --git a/esphome/components/mqtt/mqtt_component.cpp b/esphome/components/mqtt/mqtt_component.cpp index a77afd3f4e..bc9a556c90 100644 --- a/esphome/components/mqtt/mqtt_component.cpp +++ b/esphome/components/mqtt/mqtt_component.cpp @@ -14,6 +14,9 @@ namespace esphome::mqtt { static const char *const TAG = "mqtt.component"; +// Entity category MQTT strings indexed by EntityCategory enum: NONE(0) is skipped, CONFIG(1), DIAGNOSTIC(2) +PROGMEM_STRING_TABLE(EntityCategoryMqttStrings, "", "config", "diagnostic"); + // Helper functions for building topic strings on stack inline char *append_str(char *p, const char *s, size_t len) { memcpy(p, s, len); @@ -213,13 +216,9 @@ bool MQTTComponent::send_discovery_() { // NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks) const auto entity_category = this->get_entity()->get_entity_category(); - switch (entity_category) { - case ENTITY_CATEGORY_NONE: - break; - case ENTITY_CATEGORY_CONFIG: - case ENTITY_CATEGORY_DIAGNOSTIC: - root[MQTT_ENTITY_CATEGORY] = entity_category == ENTITY_CATEGORY_CONFIG ? "config" : "diagnostic"; - break; + if (entity_category != ENTITY_CATEGORY_NONE) { + root[MQTT_ENTITY_CATEGORY] = + EntityCategoryMqttStrings::get_progmem_str(static_cast(entity_category), 1); } if (config.state_topic) { diff --git a/esphome/components/mqtt/mqtt_number.cpp b/esphome/components/mqtt/mqtt_number.cpp index 7dc93eee0c..b2c814d34d 100644 --- a/esphome/components/mqtt/mqtt_number.cpp +++ b/esphome/components/mqtt/mqtt_number.cpp @@ -1,5 +1,6 @@ #include "mqtt_number.h" #include "esphome/core/log.h" +#include "esphome/core/progmem.h" #include "mqtt_const.h" @@ -12,6 +13,9 @@ static const char *const TAG = "mqtt.number"; using namespace esphome::number; +// Number mode MQTT strings indexed by NumberMode enum: AUTO(0) is skipped, BOX(1), SLIDER(2) +PROGMEM_STRING_TABLE(NumberMqttModeStrings, "", "box", "slider"); + MQTTNumberComponent::MQTTNumberComponent(Number *number) : number_(number) {} void MQTTNumberComponent::setup() { @@ -48,15 +52,9 @@ void MQTTNumberComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryCon if (!unit_of_measurement.empty()) { root[MQTT_UNIT_OF_MEASUREMENT] = unit_of_measurement; } - switch (this->number_->traits.get_mode()) { - case NUMBER_MODE_AUTO: - break; - case NUMBER_MODE_BOX: - root[MQTT_MODE] = "box"; - break; - case NUMBER_MODE_SLIDER: - root[MQTT_MODE] = "slider"; - break; + const auto mode = this->number_->traits.get_mode(); + if (mode != NUMBER_MODE_AUTO) { + root[MQTT_MODE] = NumberMqttModeStrings::get_progmem_str(static_cast(mode), 1); } const auto device_class = this->number_->traits.get_device_class_ref(); if (!device_class.empty()) { diff --git a/esphome/components/mqtt/mqtt_text.cpp b/esphome/components/mqtt/mqtt_text.cpp index 16293c0603..fa57fef10c 100644 --- a/esphome/components/mqtt/mqtt_text.cpp +++ b/esphome/components/mqtt/mqtt_text.cpp @@ -1,5 +1,6 @@ #include "mqtt_text.h" #include "esphome/core/log.h" +#include "esphome/core/progmem.h" #include "mqtt_const.h" @@ -12,6 +13,9 @@ static const char *const TAG = "mqtt.text"; using namespace esphome::text; +// Text mode MQTT strings indexed by TextMode enum (0-1): TEXT, PASSWORD +PROGMEM_STRING_TABLE(TextMqttModeStrings, "text", "password"); + MQTTTextComponent::MQTTTextComponent(Text *text) : text_(text) {} void MQTTTextComponent::setup() { @@ -34,14 +38,7 @@ const EntityBase *MQTTTextComponent::get_entity() const { return this->text_; } void MQTTTextComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson - switch (this->text_->traits.get_mode()) { - case TEXT_MODE_TEXT: - root[MQTT_MODE] = "text"; - break; - case TEXT_MODE_PASSWORD: - root[MQTT_MODE] = "password"; - break; - } + root[MQTT_MODE] = TextMqttModeStrings::get_progmem_str(static_cast(this->text_->traits.get_mode()), 0); config.command_topic = true; }