diff --git a/components/samsung_ac/__init__.py b/components/samsung_ac/__init__.py index da7c049d..d0238013 100644 --- a/components/samsung_ac/__init__.py +++ b/components/samsung_ac/__init__.py @@ -75,6 +75,7 @@ CONF_DEVICE_ERROR_CODE = "error_code" + CONF_CAPABILITIES = "capabilities" CONF_CAPABILITIES_HORIZONTAL_SWING = "horizontal_swing" CONF_CAPABILITIES_VERTICAL_SWING = "vertical_swing" @@ -280,41 +281,28 @@ async def to_code(config): device[CONF_DEVICE_ID], device[CONF_DEVICE_ADDRESS], var) # setup capabilities - if CONF_CAPABILITIES in device and CONF_CAPABILITIES_VERTICAL_SWING in device[CONF_CAPABILITIES]: - cg.add(var_dev.set_supports_vertical_swing( - device[CONF_CAPABILITIES][CONF_CAPABILITIES_VERTICAL_SWING])) - elif CONF_CAPABILITIES in config and CONF_CAPABILITIES_VERTICAL_SWING in config[CONF_CAPABILITIES]: - cg.add(var_dev.set_supports_vertical_swing( - config[CONF_CAPABILITIES][CONF_CAPABILITIES_VERTICAL_SWING])) - - if CONF_CAPABILITIES in device and CONF_CAPABILITIES_HORIZONTAL_SWING in device[CONF_CAPABILITIES]: - cg.add(var_dev.set_supports_horizontal_swing( - device[CONF_CAPABILITIES][CONF_CAPABILITIES_HORIZONTAL_SWING])) - elif CONF_CAPABILITIES in config and CONF_CAPABILITIES_HORIZONTAL_SWING in config[CONF_CAPABILITIES]: - cg.add(var_dev.set_supports_horizontal_swing( - config[CONF_CAPABILITIES][CONF_CAPABILITIES_HORIZONTAL_SWING])) + capabilities = device.get(CONF_CAPABILITIES, config.get(CONF_CAPABILITIES, {})) + + if capabilities.get(CONF_CAPABILITIES_VERTICAL_SWING): + cg.add(var_dev.set_supports_vertical_swing(True)) + + if capabilities.get(CONF_CAPABILITIES_HORIZONTAL_SWING): + cg.add(var_dev.set_supports_horizontal_swing(True)) none_added = False - for preset in PRESETS: - device_preset_conf = device[CONF_CAPABILITIES][CONF_PRESETS][preset] if ( - CONF_CAPABILITIES in device - and CONF_PRESETS in device[CONF_CAPABILITIES] - and preset in device[CONF_CAPABILITIES][CONF_PRESETS]) else None - global_preset_conf = config[CONF_CAPABILITIES][CONF_PRESETS][preset] if ( - CONF_CAPABILITIES in config - and CONF_PRESETS in config[CONF_CAPABILITIES] - and preset in config[CONF_CAPABILITIES][CONF_PRESETS]) else None - - preset_conf = global_preset_conf if device_preset_conf is None else device_preset_conf + presets = capabilities.get(CONF_PRESETS, {}) + + for preset, preset_info in PRESETS.items(): + preset_conf = presets.get(preset, None) preset_dict = isinstance(preset_conf, dict) - if preset_conf == True or (preset_dict and preset_conf[CONF_PRESET_ENABLED] == True): + if preset_conf == True or (preset_dict and preset_conf.get(CONF_PRESET_ENABLED, False)): if not none_added: none_added = True cg.add(var_dev.add_alt_mode("None", 0)) cg.add(var_dev.add_alt_mode( - preset_conf[CONF_PRESET_NAME] if preset_dict and CONF_PRESET_NAME in preset_conf else PRESETS[preset]["displayName"], - preset_conf[CONF_PRESET_VALUE] if preset_dict and CONF_PRESET_VALUE in preset_conf else PRESETS[preset]["value"] + preset_conf.get(CONF_PRESET_NAME, preset_info["displayName"]), + preset_conf.get(CONF_PRESET_VALUE, preset_info["value"]) )) # if CONF_CAPABILITIES in device and CONF_ALT_MODES in device[CONF_CAPABILITIES]: @@ -326,49 +314,28 @@ async def to_code(config): # for alt in config[CONF_CAPABILITIES][CONF_ALT_MODES]: # cg.add(var_dev.add_alt_mode(alt[CONF_ALT_MODE_NAME], alt[CONF_ALT_MODE_VALUE])) - if CONF_DEVICE_POWER in device: - conf = device[CONF_DEVICE_POWER] - sens = await switch.new_switch(conf) - cg.add(var_dev.set_power_switch(sens)) - - if CONF_DEVICE_AUTOMATIC_CLEANING in device: - conf = device[CONF_DEVICE_AUTOMATIC_CLEANING] - sens = await switch.new_switch(conf) - cg.add(var_dev.set_automatic_cleaning_switch(sens)) - - if CONF_DEVICE_WATER_HEATER_POWER in device: - conf = device[CONF_DEVICE_WATER_HEATER_POWER] - sens = await switch.new_switch(conf) - cg.add(var_dev.set_water_heater_power_switch(sens)) + # Mapping of config keys to their corresponding methods and types + device_actions = { + CONF_DEVICE_POWER: (switch.new_switch, var_dev.set_power_switch), + CONF_DEVICE_AUTOMATIC_CLEANING: (switch.new_switch, var_dev.set_automatic_cleaning_switch), + CONF_DEVICE_WATER_HEATER_POWER: (switch.new_switch, var_dev.set_water_heater_power_switch), + CONF_DEVICE_ROOM_TEMPERATURE: (sensor.new_sensor, var_dev.set_room_temperature_sensor), + CONF_DEVICE_OUTDOOR_TEMPERATURE: (sensor.new_sensor, var_dev.set_outdoor_temperature_sensor), + CONF_DEVICE_INDOOR_EVA_IN_TEMPERATURE: (sensor.new_sensor, var_dev.set_indoor_eva_in_temperature_sensor), + CONF_DEVICE_INDOOR_EVA_OUT_TEMPERATURE: (sensor.new_sensor, var_dev.set_indoor_eva_out_temperature_sensor), + CONF_DEVICE_ERROR_CODE: (sensor.new_sensor, var_dev.set_error_code_sensor), + } - if CONF_DEVICE_ROOM_TEMPERATURE in device: - conf = device[CONF_DEVICE_ROOM_TEMPERATURE] - sens = await sensor.new_sensor(conf) - cg.add(var_dev.set_room_temperature_sensor(sens)) + # Iterate over the actions + for key, (action, method) in device_actions.items(): + if key in device: + conf = device[key] + sens = await action(conf) + cg.add(method(sens)) if CONF_DEVICE_ROOM_TEMPERATURE_OFFSET in device: cg.add(var_dev.set_room_temperature_offset( device[CONF_DEVICE_ROOM_TEMPERATURE_OFFSET])) - - if CONF_DEVICE_OUTDOOR_TEMPERATURE in device: - conf = device[CONF_DEVICE_OUTDOOR_TEMPERATURE] - sens = await sensor.new_sensor(conf) - cg.add(var_dev.set_outdoor_temperature_sensor(sens)) - - if CONF_DEVICE_INDOOR_EVA_IN_TEMPERATURE in device: - conf = device[CONF_DEVICE_INDOOR_EVA_IN_TEMPERATURE] - sens = await sensor.new_sensor(conf) - cg.add(var_dev.set_indoor_eva_in_temperature_sensor(sens)) - - if CONF_DEVICE_INDOOR_EVA_OUT_TEMPERATURE in device: - conf = device[CONF_DEVICE_INDOOR_EVA_OUT_TEMPERATURE] - sens = await sensor.new_sensor(conf) - cg.add(var_dev.set_indoor_eva_out_temperature_sensor(sens)) - - if CONF_DEVICE_ERROR_CODE in device: - conf = device[CONF_DEVICE_ERROR_CODE] - sens = await sensor.new_sensor(conf) - cg.add(var_dev.set_error_code_sensor(sens)) if CONF_DEVICE_WATER_TARGET_TEMPERATURE in device: conf = device[CONF_DEVICE_WATER_TARGET_TEMPERATURE] @@ -452,6 +419,19 @@ async def to_code(config): if (CONF_DEBUG_LOG_UNDEFINED_MESSAGES in config): cg.add(var.set_debug_log_undefined_messages(config[CONF_DEBUG_LOG_UNDEFINED_MESSAGES])) - + + # Mapping of config keys to their corresponding methods + config_actions = { + CONF_DEBUG_LOG_MESSAGES: var.set_debug_log_messages, + CONF_DEBUG_LOG_MESSAGES_RAW: var.set_debug_log_messages_raw, + CONF_NON_NASA_KEEPALIVE: var.set_non_nasa_keepalive, + CONF_DEBUG_LOG_UNDEFINED_MESSAGES: var.set_debug_log_undefined_messages, + } + + # Iterate over the actions + for key, method in config_actions.items(): + if key in config: + cg.add(method(config[key])) + await cg.register_component(var, config) await uart.register_uart_device(var, config) diff --git a/components/samsung_ac/conversions.cpp b/components/samsung_ac/conversions.cpp index 73e0aa42..fd99ef38 100644 --- a/components/samsung_ac/conversions.cpp +++ b/components/samsung_ac/conversions.cpp @@ -34,7 +34,7 @@ namespace esphome case Mode::Heat: return "Heat"; default: - return ""; + return "Unknown"; }; } @@ -64,7 +64,7 @@ namespace esphome case WaterHeaterMode::Force: return "Force"; default: - return ""; + return "Unknown"; }; } diff --git a/components/samsung_ac/debug_mqtt.cpp b/components/samsung_ac/debug_mqtt.cpp index 0ea0bd2d..d4826feb 100644 --- a/components/samsung_ac/debug_mqtt.cpp +++ b/components/samsung_ac/debug_mqtt.cpp @@ -1,11 +1,10 @@ #include "esphome/core/log.h" #include "debug_mqtt.h" -#ifdef USE_ESP8266 +#if defined(USE_ESP8266) #include AsyncMqttClient *mqtt_client{nullptr}; -#endif -#ifdef USE_ESP32 +#elif defined(USE_ESP32) #include esp_mqtt_client_handle_t mqtt_client{nullptr}; #endif @@ -16,44 +15,40 @@ namespace esphome { bool debug_mqtt_connected() { -#ifdef USE_ESP8266 if (mqtt_client == nullptr) return false; +#if defined(USE_ESP8266) return mqtt_client->connected(); -#elif USE_ESP32 - if (mqtt_client == nullptr) - return false; - +#elif defined(USE_ESP32) return true; -#else - return false; #endif } void debug_mqtt_connect(const std::string &host, const uint16_t port, const std::string &username, const std::string &password) { - if (host.length() == 0) + if (host.empty()) return; -#ifdef USE_ESP8266 +#if defined(USE_ESP8266) if (mqtt_client == nullptr) { mqtt_client = new AsyncMqttClient(); mqtt_client->setServer(host.c_str(), port); - if (username.length() > 0) + if (!username.empty()) mqtt_client->setCredentials(username.c_str(), password.c_str()); } if (!mqtt_client->connected()) mqtt_client->connect(); -#elif USE_ESP32 + +#elif defined(USE_ESP32) if (mqtt_client == nullptr) { esp_mqtt_client_config_t mqtt_cfg = {}; mqtt_cfg.host = host.c_str(); mqtt_cfg.port = port; - if (username.length() > 0) + if (!username.empty()) { mqtt_cfg.username = username.c_str(); mqtt_cfg.password = password.c_str(); @@ -66,18 +61,13 @@ namespace esphome bool debug_mqtt_publish(const std::string &topic, const std::string &payload) { -#ifdef USE_ESP8266 if (mqtt_client == nullptr) return false; +#if defined(USE_ESP8266) return mqtt_client->publish(topic.c_str(), 0, false, payload.c_str()) != 0; -#elif USE_ESP32 - if (mqtt_client == nullptr) - return false; - +#elif defined(USE_ESP32) return esp_mqtt_client_publish(mqtt_client, topic.c_str(), payload.c_str(), payload.length(), 0, false) != -1; -#else - return true; #endif } } // namespace samsung_ac diff --git a/components/samsung_ac/debug_mqtt.h b/components/samsung_ac/debug_mqtt.h index 25d9b692..56fa6a0e 100644 --- a/components/samsung_ac/debug_mqtt.h +++ b/components/samsung_ac/debug_mqtt.h @@ -1,5 +1,6 @@ #pragma once -#include + +#include namespace esphome { diff --git a/components/samsung_ac/device_state_tracker.h b/components/samsung_ac/device_state_tracker.h new file mode 100644 index 00000000..394d4920 --- /dev/null +++ b/components/samsung_ac/device_state_tracker.h @@ -0,0 +1,56 @@ +#ifndef DEVICE_STATE_TRACKER_H +#define DEVICE_STATE_TRACKER_H + +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" +#include +#include + +namespace esphome { + +template +class DeviceStateTracker { + public: + DeviceStateTracker(unsigned long timeout_period) + : TIMEOUT_PERIOD(timeout_period) {} + + void update(const std::string &address, const T ¤t_value) { + unsigned long now = millis(); + + if (pending_changes_.find(address) != pending_changes_.end()) { + if (current_value == pending_changes_[address]) { + pending_changes_.erase(address); + } else { + ESP_LOGI("device_state_tracker", "Stale value received for device: %s, ignoring.", address.c_str()); + return; + } + } + + if (last_values_.find(address) == last_values_.end() || last_values_[address] != current_value) { + pending_changes_[address] = current_value; + last_values_[address] = current_value; + last_update_time_[address] = now; + + ESP_LOGI("device_state_tracker", "Value changed for device: %s", address.c_str()); + } else { + ESP_LOGD("device_state_tracker", "No change in value for device: %s", address.c_str()); + + if (now - last_update_time_[address] > TIMEOUT_PERIOD) { + if (pending_changes_.find(address) != pending_changes_.end()) { + ESP_LOGW("device_state_tracker", "Timeout for device: %s, forcing update.", address.c_str()); + pending_changes_.erase(address); + } + } + } + } + + private: + std::map last_values_; + std::map last_update_time_; + std::map pending_changes_; + const unsigned long TIMEOUT_PERIOD; +}; + +} // namespace esphome + +#endif // DEVICE_STATE_TRACKER_H diff --git a/components/samsung_ac/protocol_nasa.cpp b/components/samsung_ac/protocol_nasa.cpp index 25aa82de..6baa9198 100644 --- a/components/samsung_ac/protocol_nasa.cpp +++ b/components/samsung_ac/protocol_nasa.cpp @@ -1,9 +1,6 @@ -#include -#include #include #include "esphome/core/log.h" #include "esphome/core/util.h" -#include "esphome/core/hal.h" #include "util.h" #include "protocol_nasa.h" #include "debug_mqtt.h" @@ -21,9 +18,9 @@ namespace esphome return value - (int)65535 /*uint16 max*/ - 1.0; } -#define LOG_MESSAGE(message_name, temp, source, dest) \ - if (debug_log_messages) \ - { \ +#define LOG_MESSAGE(message_name, temp, source, dest) \ + if (debug_log_messages) \ + { \ ESP_LOGW(TAG, "s:%s d:%s " #message_name " %g", source.c_str(), dest.c_str(), static_cast(temp)); \ } @@ -82,8 +79,8 @@ namespace esphome std::string Address::to_string() { char str[9]; - sprintf(str, "%02x.%02x.%02x", (int)klass, channel, address); - return str; + sprintf(str, "%02x.%02x.%02x", klass, channel, address); + return std::string(str); } void Command::decode(std::vector &data, unsigned int index) @@ -861,11 +858,9 @@ namespace esphome void process_messageset_debug(std::string source, std::string dest, MessageSet &message, MessageTarget *target) { - if (source == "20.00.00" || source == "20.00.01" || source == "20.00.03") + if (source == "20.00.00" || source == "20.00.01" || source == "20.00.02" || source == "20.00.03") return; - // return; // :) - switch ((uint16_t)message.messageNumber) { case 0x4003: @@ -900,18 +895,6 @@ namespace esphome LOG_MESSAGE(ENUM_in_fan_vent_mode, message.value, source, dest); // fan_vent_mode_to_fanmode(); break; - case 0x4205: // VAR_in_temp_eva_in_f unit = 'Celsius' - { - double temp = (double)message.value / (double)10; - LOG_MESSAGE(VAR_in_temp_eva_in_f, temp, source, dest); - break; - } - case 0x4206: // VAR_in_temp_eva_out_f unit = 'Celsius' - { - double temp = (double)message.value / (double)10; - LOG_MESSAGE(VAR_in_temp_eva_out_f, temp, source, dest); - break; - } case 0x4211: // VAR_in_capacity_request unit = 'kW' { double temp = (double)message.value / (double)8.6; diff --git a/components/samsung_ac/protocol_nasa.h b/components/samsung_ac/protocol_nasa.h index b987e24b..499d4075 100644 --- a/components/samsung_ac/protocol_nasa.h +++ b/components/samsung_ac/protocol_nasa.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include "protocol.h" namespace esphome diff --git a/components/samsung_ac/protocol_non_nasa.cpp b/components/samsung_ac/protocol_non_nasa.cpp index 2e9bdc13..1d503b78 100644 --- a/components/samsung_ac/protocol_non_nasa.cpp +++ b/components/samsung_ac/protocol_non_nasa.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "esphome/core/log.h" #include "esphome/core/hal.h" #include "util.h" diff --git a/components/samsung_ac/protocol_non_nasa.h b/components/samsung_ac/protocol_non_nasa.h index 21c6f825..3542c47c 100644 --- a/components/samsung_ac/protocol_non_nasa.h +++ b/components/samsung_ac/protocol_non_nasa.h @@ -2,7 +2,6 @@ #include #include -#include #include #include "protocol.h" #include "util.h" diff --git a/components/samsung_ac/samsung_ac.cpp b/components/samsung_ac/samsung_ac.cpp index d0215fd8..c7890db9 100644 --- a/components/samsung_ac/samsung_ac.cpp +++ b/components/samsung_ac/samsung_ac.cpp @@ -23,6 +23,17 @@ namespace esphome ESP_LOGW(TAG, "update"); } + for (const auto &pair : devices_) + { + optional current_value = pair.second->_cur_mode; + std::string address = pair.second->address; + + if (current_value.has_value()) + { + state_tracker_.update(address, current_value.value()); + } + } + debug_mqtt_connect(debug_mqtt_host, debug_mqtt_port, debug_mqtt_username, debug_mqtt_password); // Waiting for first update before beginning processing data @@ -32,31 +43,25 @@ namespace esphome data_processing_init = false; } - std::string devices = ""; + std::string devices; for (const auto &pair : devices_) { - devices += devices.length() > 0 ? ", " + pair.second->address : pair.second->address; + if (!devices.empty()) + devices += ", "; + devices += pair.second->address; } ESP_LOGCONFIG(TAG, "Configured devices: %s", devices.c_str()); - std::string knownIndoor = ""; - std::string knownOutdoor = ""; - std::string knownOther = ""; - for (auto const &address : addresses_) + std::string knownIndoor, knownOutdoor, knownOther; + for (const auto &address : addresses_) { - switch (get_address_type(address)) - { - case AddressType::Outdoor: - knownOutdoor += knownOutdoor.length() > 0 ? ", " + address : address; - break; - case AddressType::Indoor: - knownIndoor += knownIndoor.length() > 0 ? ", " + address : address; - break; - default: - knownOther += knownOther.length() > 0 ? ", " + address : address; - break; - } + auto &target = (get_address_type(address) == AddressType::Outdoor) ? knownOutdoor : (get_address_type(address) == AddressType::Indoor) ? knownIndoor + : knownOther; + if (!target.empty()) + target += ", "; + target += address; } + ESP_LOGCONFIG(TAG, "Discovered devices:"); ESP_LOGCONFIG(TAG, " Outdoor: %s", (knownOutdoor.length() == 0 ? "-" : knownOutdoor.c_str())); ESP_LOGCONFIG(TAG, " Indoor: %s", (knownIndoor.length() == 0 ? "-" : knownIndoor.c_str())); @@ -94,31 +99,27 @@ namespace esphome return; const uint32_t now = millis(); - if (data_.size() > 0 && (now - last_transmission_ >= 500)) + if (!data_.empty() && (now - last_transmission_ >= 500)) { ESP_LOGW(TAG, "Last transmission too long ago. Reset RX index."); data_.clear(); } - // If there is no data we use the time to send - if (available()) + while (available()) { last_transmission_ = now; - while (available()) + uint8_t c; + if (!read_byte(&c)) + continue; + if (data_.empty() && c != 0x32) + continue; // skip until start-byte found + + data_.push_back(c); + + if (process_data(data_, this) == DataResult::Clear) { - uint8_t c; - if (!read_byte(&c)) - continue; - if (data_.size() == 0 && c != 0x32) - continue; // skip until start-byte found - - data_.push_back(c); - - if (process_data(data_, this) == DataResult::Clear) - { - data_.clear(); - break; // wait for next loop - } + data_.clear(); + break; // wait for next loop } } diff --git a/components/samsung_ac/samsung_ac.h b/components/samsung_ac/samsung_ac.h index 968e6908..2919487e 100644 --- a/components/samsung_ac/samsung_ac.h +++ b/components/samsung_ac/samsung_ac.h @@ -8,6 +8,7 @@ #include "esphome/components/uart/uart.h" #include "samsung_ac_device.h" #include "protocol.h" +#include "device_state_tracker.h" namespace esphome { @@ -193,6 +194,7 @@ namespace esphome if (dev != nullptr) dev->update_custom_sensor(message_number, value); } + void /*MessageTarget::*/ set_error_code(const std::string address, int value) override { Samsung_AC_Device *dev = find_device(address); @@ -212,11 +214,12 @@ namespace esphome } std::map devices_; + DeviceStateTracker state_tracker_{1000}; std::set addresses_; std::vector data_; - uint32_t last_transmission_{0}; - uint32_t last_protocol_update_{0}; + uint32_t last_transmission_ = 0; + uint32_t last_protocol_update_ = 0; bool data_processing_init = true; diff --git a/components/samsung_ac/samsung_ac_device.cpp b/components/samsung_ac/samsung_ac_device.cpp index 56c14f31..99b713f4 100644 --- a/components/samsung_ac/samsung_ac_device.cpp +++ b/components/samsung_ac/samsung_ac_device.cpp @@ -20,19 +20,19 @@ namespace esphome traits.set_visual_min_temperature(16); traits.set_visual_max_temperature(30); - std::set modes; - modes.insert(climate::CLIMATE_MODE_OFF); - modes.insert(climate::CLIMATE_MODE_AUTO); - modes.insert(climate::CLIMATE_MODE_COOL); - modes.insert(climate::CLIMATE_MODE_DRY); - modes.insert(climate::CLIMATE_MODE_FAN_ONLY); - modes.insert(climate::CLIMATE_MODE_HEAT); + const std::set modes = { + climate::CLIMATE_MODE_OFF, + climate::CLIMATE_MODE_AUTO, + climate::CLIMATE_MODE_COOL, + climate::CLIMATE_MODE_DRY, + climate::CLIMATE_MODE_FAN_ONLY, + climate::CLIMATE_MODE_HEAT}; traits.set_supported_modes(modes); - std::set fan; - fan.insert(climate::ClimateFanMode::CLIMATE_FAN_HIGH); - fan.insert(climate::ClimateFanMode::CLIMATE_FAN_MIDDLE); - fan.insert(climate::ClimateFanMode::CLIMATE_FAN_LOW); + std::set fan = { + climate::ClimateFanMode::CLIMATE_FAN_HIGH, + climate::ClimateFanMode::CLIMATE_FAN_MIDDLE, + climate::ClimateFanMode::CLIMATE_FAN_LOW}; if (this->mode != climate::CLIMATE_MODE_FAN_ONLY) { diff --git a/components/samsung_ac/util.cpp b/components/samsung_ac/util.cpp index acaa7ad5..fa72f8f7 100644 --- a/components/samsung_ac/util.cpp +++ b/components/samsung_ac/util.cpp @@ -7,8 +7,8 @@ namespace esphome std::string long_to_hex(long number) { char str[10]; - sprintf(str, "%02lx", number); - return str; + snprintf(str, sizeof(str), "%02lx", number); // Use of snprintf for security reasons. + return std::string(str); } int hex_to_int(const std::string &hex) @@ -19,9 +19,12 @@ namespace esphome std::string bytes_to_hex(const std::vector &data) { std::string str; - for (int i = 0; i < data.size(); i++) + str.reserve(data.size() * 2); // Memory reservations are made to increase efficiency. + for (uint8_t byte : data) { - str += long_to_hex(data[i]); + char buf[3]; + snprintf(buf, sizeof(buf), "%02x", byte); + str += buf; } return str; } @@ -29,9 +32,11 @@ namespace esphome std::vector hex_to_bytes(const std::string &hex) { std::vector bytes; - for (unsigned int i = 0; i < hex.length(); i += 2) + bytes.reserve(hex.length() / 2); + for (size_t i = 0; i < hex.length(); i += 2) { - bytes.push_back((uint8_t)strtol(hex.substr(i, 2).c_str(), NULL, 16)); + uint8_t byte = (uint8_t)strtol(hex.substr(i, 2).c_str(), nullptr, 16); + bytes.push_back(byte); } return bytes; } diff --git a/readme.md b/readme.md index 56efa15a..ed6a8c30 100644 --- a/readme.md +++ b/readme.md @@ -20,6 +20,21 @@ The current implementation offers the following features: - **AC Mode Control:** The controller enables you to change the AC mode, giving you control over cooling, heating, or other operational modes. +## New Feature: ESPHome Samsung AC Blueprint + +We are excited to introduce a new Blueprint that integrates with the esphome_samsung_ac component. This Blueprint enhances your Home Assistant setup by enabling you to monitor error codes from your Samsung AC units and receive real-time notifications directly to your selected devices. + +### Key Features: +- **Error Code Monitoring:** Continuously monitors error codes from your Samsung AC unit, ensuring that you are always informed about any issues. +- **Automated Notifications:** Sends detailed notifications with corresponding error messages to selected devices whenever an error code is detected. +- **User-Friendly Setup:** Easily import and configure this Blueprint through Home Assistant’s Blueprint feature. + +For more detailed instructions on setup and usage, please refer to the [Blueprint documentation](https://github.com/omerfaruk-aran/esphome_samsung_ac_blueprint). + +This Blueprint adds a new layer of functionality to your Home Assistant setup, allowing for more proactive and informed management of your Samsung AC units. + +[![Add Blueprint to Home Assistant](https://community-assets.home-assistant.io/original/4X/d/7/6/d7625545838a4970873f3a996172212440b7e0ae.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https://raw.githubusercontent.com/omerfaruk-aran/esphome_samsung_ac_blueprint/main/blueprints/automation/esphome_samsung_ac/notification_blueprint.yaml) + ## Compatibility In general, all devices with dedicated communication wires (not only power) should work. If you want to be safe when buying a new AC, then just ask for NASA support. diff --git a/test/esphome/core/log.h b/test/esphome/core/log.h index a4a04cee..644e55bf 100644 --- a/test/esphome/core/log.h +++ b/test/esphome/core/log.h @@ -4,40 +4,21 @@ namespace esphome { -#define ESP_LOGD(tag, format, ...) \ +#define ESP_LOG(level, TAG, format, ...) \ do \ { \ - std::string str = ""; \ + std::string str = "["; \ + str += level; \ + str += "] "; \ str += format; \ str += "\n"; \ printf((str.c_str()), ##__VA_ARGS__); \ } while (0); -#define ESP_LOGE(tag, format, ...) \ - do \ - { \ - std::string str = ""; \ - str += format; \ - str += "\n"; \ - printf((str.c_str()), ##__VA_ARGS__); \ - } while (0); - -#define ESP_LOGW(tag, format, ...) \ - do \ - { \ - std::string str = ""; \ - str += format; \ - str += "\n"; \ - printf((str.c_str()), ##__VA_ARGS__); \ - } while (0); - -#define ESP_LOGV(tag, format, ...) \ - do \ - { \ - std::string str = ""; \ - str += format; \ - str += "\n"; \ - printf((str.c_str()), ##__VA_ARGS__); \ - } while (0); +#define ESP_LOGD(TAG, format, ...) ESP_LOG("DEBUG", TAG, format, ##__VA_ARGS__) +#define ESP_LOGE(TAG, format, ...) ESP_LOG("ERROR", TAG, format, ##__VA_ARGS__) +#define ESP_LOGW(TAG, format, ...) ESP_LOG("WARN", TAG, format, ##__VA_ARGS__) +#define ESP_LOGV(TAG, format, ...) ESP_LOG("VERBOSE", TAG, format, ##__VA_ARGS__) +#define ESP_LOGI(TAG, format, ...) ESP_LOG("INFO", TAG, format, ##__VA_ARGS__) } // namespace esphome