mirror of
https://github.com/esphome/esphome.git
synced 2026-01-13 13:37:39 -07:00
Compare commits
54 Commits
integratio
...
ha_state_n
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36b5f0aaf0 | ||
|
|
96c47f3b4d | ||
|
|
5b5cede5f9 | ||
|
|
c737033cc4 | ||
|
|
0194bfd9ea | ||
|
|
339399eb70 | ||
|
|
a615b28ecf | ||
|
|
468bd7b04f | ||
|
|
4c16afeacb | ||
|
|
d86c05bfe6 | ||
|
|
63464a13c3 | ||
|
|
20e43398fa | ||
|
|
2e7cdad532 | ||
|
|
636cccc6a3 | ||
|
|
93e2a1bd1a | ||
|
|
dd3beb5841 | ||
|
|
97af01c5ed | ||
|
|
7e362cdafc | ||
|
|
890d531cea | ||
|
|
6a6c6b648f | ||
|
|
d0673122a8 | ||
|
|
5cbef3ef95 | ||
|
|
a1e0121330 | ||
|
|
eb050ff13e | ||
|
|
45e61f100c | ||
|
|
5e99dd14ae | ||
|
|
a6097f4a0f | ||
|
|
f243e609a5 | ||
|
|
be0bf1e5b9 | ||
|
|
a275f37135 | ||
|
|
e9f2d75aab | ||
|
|
34067f8b15 | ||
|
|
bdc087148a | ||
|
|
5a2e0612a8 | ||
|
|
f1fecd22e3 | ||
|
|
0919017d49 | ||
|
|
963f594c9e | ||
|
|
4f70663658 | ||
|
|
958a35e262 | ||
|
|
0c566c6f00 | ||
|
|
ba73289b28 | ||
|
|
99f7e9aeb7 | ||
|
|
ebb6babb3d | ||
|
|
0922f240e0 | ||
|
|
c8fb694dcb | ||
|
|
6054685dae | ||
|
|
61ec3508ed | ||
|
|
086ec770ea | ||
|
|
b055f5b4bf | ||
|
|
726db746c8 | ||
|
|
1922455fa7 | ||
|
|
dc943d7e7a | ||
|
|
ffefa8929e | ||
|
|
7d5342bca5 |
@@ -1 +1 @@
|
||||
4268ab0b5150f79ab1c317e8f3834c8bb0b4c8122da4f6b1fd67c49d0f2098c9
|
||||
94557f94be073390342833aff12ef8676a8b597db5fa770a5a1232e9425cb48f
|
||||
|
||||
@@ -789,7 +789,13 @@ def command_compile(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
exit_code = compile_program(args, config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
_LOGGER.info("Successfully compiled program.")
|
||||
if CORE.is_host:
|
||||
from esphome.platformio_api import get_idedata
|
||||
|
||||
program_path = str(get_idedata(config).firmware_elf_path)
|
||||
_LOGGER.info("Successfully compiled program to path '%s'", program_path)
|
||||
else:
|
||||
_LOGGER.info("Successfully compiled program.")
|
||||
return 0
|
||||
|
||||
|
||||
@@ -839,10 +845,8 @@ def command_run(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
if CORE.is_host:
|
||||
from esphome.platformio_api import get_idedata
|
||||
|
||||
idedata = get_idedata(config)
|
||||
if idedata is None:
|
||||
return 1
|
||||
program_path = idedata.raw["prog_path"]
|
||||
program_path = str(get_idedata(config).firmware_elf_path)
|
||||
_LOGGER.info("Running program from path '%s'", program_path)
|
||||
return run_external_process(program_path)
|
||||
|
||||
# Get devices, resolving special identifiers like OTA
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace alarm_control_panel {
|
||||
namespace esphome::alarm_control_panel {
|
||||
|
||||
static const char *const TAG = "alarm_control_panel";
|
||||
|
||||
@@ -115,5 +114,4 @@ void AlarmControlPanel::disarm(optional<std::string> code) {
|
||||
call.perform();
|
||||
}
|
||||
|
||||
} // namespace alarm_control_panel
|
||||
} // namespace esphome
|
||||
} // namespace esphome::alarm_control_panel
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "alarm_control_panel_call.h"
|
||||
#include "alarm_control_panel_state.h"
|
||||
|
||||
@@ -9,8 +7,7 @@
|
||||
#include "esphome/core/entity_base.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace alarm_control_panel {
|
||||
namespace esphome::alarm_control_panel {
|
||||
|
||||
enum AlarmControlPanelFeature : uint8_t {
|
||||
// Matches Home Assistant values
|
||||
@@ -141,5 +138,4 @@ class AlarmControlPanel : public EntityBase {
|
||||
LazyCallbackManager<void()> ready_callback_{};
|
||||
};
|
||||
|
||||
} // namespace alarm_control_panel
|
||||
} // namespace esphome
|
||||
} // namespace esphome::alarm_control_panel
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace alarm_control_panel {
|
||||
namespace esphome::alarm_control_panel {
|
||||
|
||||
static const char *const TAG = "alarm_control_panel";
|
||||
|
||||
@@ -99,5 +98,4 @@ void AlarmControlPanelCall::perform() {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace alarm_control_panel
|
||||
} // namespace esphome
|
||||
} // namespace esphome::alarm_control_panel
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace alarm_control_panel {
|
||||
namespace esphome::alarm_control_panel {
|
||||
|
||||
class AlarmControlPanel;
|
||||
|
||||
@@ -36,5 +35,4 @@ class AlarmControlPanelCall {
|
||||
void validate_();
|
||||
};
|
||||
|
||||
} // namespace alarm_control_panel
|
||||
} // namespace esphome
|
||||
} // namespace esphome::alarm_control_panel
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "alarm_control_panel_state.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace alarm_control_panel {
|
||||
namespace esphome::alarm_control_panel {
|
||||
|
||||
const LogString *alarm_control_panel_state_to_string(AlarmControlPanelState state) {
|
||||
switch (state) {
|
||||
@@ -30,5 +29,4 @@ const LogString *alarm_control_panel_state_to_string(AlarmControlPanelState stat
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace alarm_control_panel
|
||||
} // namespace esphome
|
||||
} // namespace esphome::alarm_control_panel
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include <cstdint>
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace alarm_control_panel {
|
||||
namespace esphome::alarm_control_panel {
|
||||
|
||||
enum AlarmControlPanelState : uint8_t {
|
||||
ACP_STATE_DISARMED = 0,
|
||||
@@ -25,5 +24,4 @@ enum AlarmControlPanelState : uint8_t {
|
||||
*/
|
||||
const LogString *alarm_control_panel_state_to_string(AlarmControlPanelState state);
|
||||
|
||||
} // namespace alarm_control_panel
|
||||
} // namespace esphome
|
||||
} // namespace esphome::alarm_control_panel
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "esphome/core/automation.h"
|
||||
#include "alarm_control_panel.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace alarm_control_panel {
|
||||
namespace esphome::alarm_control_panel {
|
||||
|
||||
/// Trigger on any state change
|
||||
class StateTrigger : public Trigger<> {
|
||||
@@ -165,5 +164,4 @@ template<typename... Ts> class AlarmControlPanelCondition : public Condition<Ts.
|
||||
AlarmControlPanel *parent_;
|
||||
};
|
||||
|
||||
} // namespace alarm_control_panel
|
||||
} // namespace esphome
|
||||
} // namespace esphome::alarm_control_panel
|
||||
|
||||
@@ -1711,9 +1711,8 @@ void APIConnection::on_home_assistant_state_response(const HomeAssistantStateRes
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create temporary string for callback (callback takes const std::string &)
|
||||
// Handle empty state (nullptr with len=0)
|
||||
std::string state(msg.state_len > 0 ? reinterpret_cast<const char *>(msg.state) : "", msg.state_len);
|
||||
// Create StringRef directly from message data (zero allocation)
|
||||
StringRef state(reinterpret_cast<const char *>(msg.state), msg.state_len);
|
||||
it.callback(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,18 +423,18 @@ void APIServer::handle_action_response(uint32_t call_id, bool success, const std
|
||||
#endif // USE_API_HOMEASSISTANT_SERVICES
|
||||
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
// Helper to add subscription (reduces duplication)
|
||||
void APIServer::add_state_subscription_(const char *entity_id, const char *attribute,
|
||||
std::function<void(std::string)> f, bool once) {
|
||||
// Helper to add subscription (reduces duplication) - const char* version (zero allocation)
|
||||
void APIServer::add_state_subscription_(const char *entity_id, const char *attribute, std::function<void(StringRef)> f,
|
||||
bool once) {
|
||||
this->state_subs_.push_back(HomeAssistantStateSubscription{
|
||||
.entity_id = entity_id, .attribute = attribute, .callback = std::move(f), .once = once,
|
||||
// entity_id_dynamic_storage and attribute_dynamic_storage remain nullptr (no heap allocation)
|
||||
});
|
||||
}
|
||||
|
||||
// Helper to add subscription with heap-allocated strings (reduces duplication)
|
||||
// Helper to add subscription with heap-allocated strings and StringRef callback
|
||||
void APIServer::add_state_subscription_(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(std::string)> f, bool once) {
|
||||
std::function<void(StringRef)> f, bool once) {
|
||||
HomeAssistantStateSubscription sub;
|
||||
// Allocate heap storage for the strings
|
||||
sub.entity_id_dynamic_storage = std::make_unique<std::string>(std::move(entity_id));
|
||||
@@ -452,25 +452,45 @@ void APIServer::add_state_subscription_(std::string entity_id, optional<std::str
|
||||
this->state_subs_.push_back(std::move(sub));
|
||||
}
|
||||
|
||||
// Legacy helper: wraps std::string callback and delegates to StringRef version
|
||||
void APIServer::add_state_subscription_(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(const std::string &)> f, bool once) {
|
||||
// Wrap callback to convert StringRef -> std::string, then delegate
|
||||
this->add_state_subscription_(std::move(entity_id), std::move(attribute),
|
||||
std::function<void(StringRef)>([f = std::move(f)](StringRef state) { f(state.str()); }),
|
||||
once);
|
||||
}
|
||||
|
||||
// New const char* overload (for internal components - zero allocation)
|
||||
void APIServer::subscribe_home_assistant_state(const char *entity_id, const char *attribute,
|
||||
std::function<void(std::string)> f) {
|
||||
std::function<void(StringRef)> f) {
|
||||
this->add_state_subscription_(entity_id, attribute, std::move(f), false);
|
||||
}
|
||||
|
||||
void APIServer::get_home_assistant_state(const char *entity_id, const char *attribute,
|
||||
std::function<void(std::string)> f) {
|
||||
std::function<void(StringRef)> f) {
|
||||
this->add_state_subscription_(entity_id, attribute, std::move(f), true);
|
||||
}
|
||||
|
||||
// Existing std::string overload (for custom_api_device.h - heap allocation)
|
||||
// std::string overload with StringRef callback (zero-allocation callback)
|
||||
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(std::string)> f) {
|
||||
std::function<void(StringRef)> f) {
|
||||
this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), false);
|
||||
}
|
||||
|
||||
void APIServer::get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(std::string)> f) {
|
||||
std::function<void(StringRef)> f) {
|
||||
this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), true);
|
||||
}
|
||||
|
||||
// Legacy std::string overload (for custom_api_device.h - converts StringRef to std::string)
|
||||
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(const std::string &)> f) {
|
||||
this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), false);
|
||||
}
|
||||
|
||||
void APIServer::get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(const std::string &)> f) {
|
||||
this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), true);
|
||||
}
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ class APIServer : public Component,
|
||||
struct HomeAssistantStateSubscription {
|
||||
const char *entity_id; // Pointer to flash (internal) or heap (external)
|
||||
const char *attribute; // Pointer to flash or nullptr (nullptr means no attribute)
|
||||
std::function<void(std::string)> callback;
|
||||
std::function<void(StringRef)> callback;
|
||||
bool once;
|
||||
|
||||
// Dynamic storage for external components using std::string API (custom_api_device.h)
|
||||
@@ -205,14 +205,20 @@ class APIServer : public Component,
|
||||
};
|
||||
|
||||
// New const char* overload (for internal components - zero allocation)
|
||||
void subscribe_home_assistant_state(const char *entity_id, const char *attribute, std::function<void(std::string)> f);
|
||||
void get_home_assistant_state(const char *entity_id, const char *attribute, std::function<void(std::string)> f);
|
||||
void subscribe_home_assistant_state(const char *entity_id, const char *attribute, std::function<void(StringRef)> f);
|
||||
void get_home_assistant_state(const char *entity_id, const char *attribute, std::function<void(StringRef)> f);
|
||||
|
||||
// Existing std::string overload (for custom_api_device.h - heap allocation)
|
||||
// std::string overload with StringRef callback (for custom_api_device.h with zero-allocation callback)
|
||||
void subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(std::string)> f);
|
||||
std::function<void(StringRef)> f);
|
||||
void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(std::string)> f);
|
||||
std::function<void(StringRef)> f);
|
||||
|
||||
// Legacy std::string overload (for custom_api_device.h - converts StringRef to std::string for callback)
|
||||
void subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(const std::string &)> f);
|
||||
void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(const std::string &)> f);
|
||||
|
||||
const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
|
||||
#endif
|
||||
@@ -236,10 +242,12 @@ class APIServer : public Component,
|
||||
#endif // USE_API_NOISE
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
// Helper methods to reduce code duplication
|
||||
void add_state_subscription_(const char *entity_id, const char *attribute, std::function<void(std::string)> f,
|
||||
void add_state_subscription_(const char *entity_id, const char *attribute, std::function<void(StringRef)> f,
|
||||
bool once);
|
||||
void add_state_subscription_(std::string entity_id, optional<std::string> attribute, std::function<void(StringRef)> f,
|
||||
bool once);
|
||||
void add_state_subscription_(std::string entity_id, optional<std::string> attribute,
|
||||
std::function<void(std::string)> f, bool once);
|
||||
std::function<void(const std::string &)> f, bool once);
|
||||
#endif // USE_API_HOMEASSISTANT_STATES
|
||||
// Pointers and pointer-like types first (4 bytes each)
|
||||
std::unique_ptr<socket::Socket> socket_ = nullptr;
|
||||
|
||||
@@ -122,17 +122,29 @@ class CustomAPIDevice {
|
||||
* subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "climate.kitchen", "current_temperature");
|
||||
* }
|
||||
*
|
||||
* void on_state_changed(std::string state) {
|
||||
* // State of sensor.weather_forecast is `state`
|
||||
* void on_state_changed(StringRef state) {
|
||||
* // State of climate.kitchen current_temperature is `state`
|
||||
* // Use state.c_str() for C string, state.str() for std::string
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @tparam T The class type creating the service, automatically deduced from the function pointer.
|
||||
* @param callback The member function to call when the entity state changes.
|
||||
* @param callback The member function to call when the entity state changes (zero-allocation).
|
||||
* @param entity_id The entity_id to track.
|
||||
* @param attribute The entity state attribute to track.
|
||||
*/
|
||||
template<typename T>
|
||||
void subscribe_homeassistant_state(void (T::*callback)(StringRef), const std::string &entity_id,
|
||||
const std::string &attribute = "") {
|
||||
auto f = std::bind(callback, (T *) this, std::placeholders::_1);
|
||||
global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute), std::move(f));
|
||||
}
|
||||
|
||||
/** Subscribe to the state (or attribute state) of an entity from Home Assistant (legacy std::string version).
|
||||
*
|
||||
* @deprecated Use the StringRef overload for zero-allocation callbacks.
|
||||
*/
|
||||
template<typename T>
|
||||
void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id,
|
||||
const std::string &attribute = "") {
|
||||
auto f = std::bind(callback, (T *) this, std::placeholders::_1);
|
||||
@@ -148,23 +160,42 @@ class CustomAPIDevice {
|
||||
* subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast");
|
||||
* }
|
||||
*
|
||||
* void on_state_changed(std::string entity_id, std::string state) {
|
||||
* void on_state_changed(const std::string &entity_id, StringRef state) {
|
||||
* // State of `entity_id` is `state`
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @tparam T The class type creating the service, automatically deduced from the function pointer.
|
||||
* @param callback The member function to call when the entity state changes.
|
||||
* @param callback The member function to call when the entity state changes (zero-allocation for state).
|
||||
* @param entity_id The entity_id to track.
|
||||
* @param attribute The entity state attribute to track.
|
||||
*/
|
||||
template<typename T>
|
||||
void subscribe_homeassistant_state(void (T::*callback)(const std::string &, StringRef), const std::string &entity_id,
|
||||
const std::string &attribute = "") {
|
||||
auto f = std::bind(callback, (T *) this, entity_id, std::placeholders::_1);
|
||||
global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute), std::move(f));
|
||||
}
|
||||
|
||||
/** Subscribe to the state (or attribute state) of an entity from Home Assistant (legacy std::string version).
|
||||
*
|
||||
* @deprecated Use the StringRef overload for zero-allocation callbacks.
|
||||
*/
|
||||
template<typename T>
|
||||
void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id,
|
||||
const std::string &attribute = "") {
|
||||
auto f = std::bind(callback, (T *) this, entity_id, std::placeholders::_1);
|
||||
global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute), f);
|
||||
}
|
||||
#else
|
||||
template<typename T>
|
||||
void subscribe_homeassistant_state(void (T::*callback)(StringRef), const std::string &entity_id,
|
||||
const std::string &attribute = "") {
|
||||
static_assert(sizeof(T) == 0,
|
||||
"subscribe_homeassistant_state() requires 'homeassistant_states: true' in the 'api:' section "
|
||||
"of your YAML configuration");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id,
|
||||
const std::string &attribute = "") {
|
||||
@@ -173,6 +204,14 @@ class CustomAPIDevice {
|
||||
"of your YAML configuration");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void subscribe_homeassistant_state(void (T::*callback)(const std::string &, StringRef), const std::string &entity_id,
|
||||
const std::string &attribute = "") {
|
||||
static_assert(sizeof(T) == 0,
|
||||
"subscribe_homeassistant_state() requires 'homeassistant_states: true' in the 'api:' section "
|
||||
"of your YAML configuration");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id,
|
||||
const std::string &attribute = "") {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "audio_reader.h"
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "audio.h"
|
||||
#include "audio_transfer_buffer.h"
|
||||
|
||||
@@ -50,6 +50,7 @@ TYPES = [
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(cg.Component),
|
||||
cv.GenerateID(CONF_BME68X_BSEC2_ID): cv.use_id(BME68xBSEC2Component),
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_CELSIUS,
|
||||
|
||||
@@ -97,10 +97,6 @@ async def to_code(config):
|
||||
cg.add_define("USE_CAPTIVE_PORTAL")
|
||||
|
||||
if CORE.using_arduino:
|
||||
if CORE.is_esp32:
|
||||
cg.add_library("ESP32 Async UDP", None)
|
||||
cg.add_library("DNSServer", None)
|
||||
cg.add_library("WiFi", None)
|
||||
if CORE.is_esp8266:
|
||||
cg.add_library("DNSServer", None)
|
||||
if CORE.is_libretiny:
|
||||
@@ -110,6 +106,9 @@ async def to_code(config):
|
||||
# Only compile the ESP-IDF DNS server when using ESP-IDF framework
|
||||
FILTER_SOURCE_FILES = filter_source_files_from_platform(
|
||||
{
|
||||
"dns_server_esp32_idf.cpp": {PlatformFramework.ESP32_IDF},
|
||||
"dns_server_esp32_idf.cpp": {
|
||||
PlatformFramework.ESP32_ARDUINO,
|
||||
PlatformFramework.ESP32_IDF,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -69,12 +69,11 @@ void CaptivePortal::start() {
|
||||
|
||||
network::IPAddress ip = wifi::global_wifi_component->wifi_soft_ap_ip();
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#if defined(USE_ESP32)
|
||||
// Create DNS server instance for ESP-IDF
|
||||
this->dns_server_ = make_unique<DNSServer>();
|
||||
this->dns_server_->start(ip);
|
||||
#endif
|
||||
#ifdef USE_ARDUINO
|
||||
#elif defined(USE_ARDUINO)
|
||||
this->dns_server_ = make_unique<DNSServer>();
|
||||
this->dns_server_->setErrorReplyCode(DNSReplyCode::NoError);
|
||||
this->dns_server_->start(53, ESPHOME_F("*"), ip);
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
#include "esphome/core/defines.h"
|
||||
#ifdef USE_CAPTIVE_PORTAL
|
||||
#include <memory>
|
||||
#ifdef USE_ARDUINO
|
||||
#include <DNSServer.h>
|
||||
#endif
|
||||
#ifdef USE_ESP_IDF
|
||||
#if defined(USE_ESP32)
|
||||
#include "dns_server_esp32_idf.h"
|
||||
#elif defined(USE_ARDUINO)
|
||||
#include <DNSServer.h>
|
||||
#endif
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
@@ -23,15 +22,14 @@ class CaptivePortal : public AsyncWebHandler, public Component {
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
void loop() override {
|
||||
#ifdef USE_ARDUINO
|
||||
if (this->dns_server_ != nullptr) {
|
||||
this->dns_server_->processNextRequest();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_ESP_IDF
|
||||
#if defined(USE_ESP32)
|
||||
if (this->dns_server_ != nullptr) {
|
||||
this->dns_server_->process_next_request();
|
||||
}
|
||||
#elif defined(USE_ARDUINO)
|
||||
if (this->dns_server_ != nullptr) {
|
||||
this->dns_server_->processNextRequest();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
float get_setup_priority() const override;
|
||||
@@ -64,7 +62,7 @@ class CaptivePortal : public AsyncWebHandler, public Component {
|
||||
web_server_base::WebServerBase *base_;
|
||||
bool initialized_{false};
|
||||
bool active_{false};
|
||||
#if defined(USE_ARDUINO) || defined(USE_ESP_IDF)
|
||||
#if defined(USE_ARDUINO) || defined(USE_ESP32)
|
||||
std::unique_ptr<DNSServer> dns_server_{nullptr};
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "dns_server_esp32_idf.h"
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/hal.h"
|
||||
@@ -202,4 +202,4 @@ void DNSServer::process_next_request() {
|
||||
|
||||
} // namespace esphome::captive_portal
|
||||
|
||||
#endif // USE_ESP_IDF
|
||||
#endif // USE_ESP32
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include <memory>
|
||||
#include "esphome/core/helpers.h"
|
||||
@@ -24,4 +24,4 @@ class DNSServer {
|
||||
|
||||
} // namespace esphome::captive_portal
|
||||
|
||||
#endif // USE_ESP_IDF
|
||||
#endif // USE_ESP32
|
||||
|
||||
@@ -169,14 +169,16 @@ void CC1101Component::loop() {
|
||||
}
|
||||
|
||||
// Read packet
|
||||
uint8_t payload_length;
|
||||
uint8_t payload_length, expected_rx;
|
||||
if (this->state_.LENGTH_CONFIG == static_cast<uint8_t>(LengthConfig::LENGTH_CONFIG_VARIABLE)) {
|
||||
this->read_(Register::FIFO, &payload_length, 1);
|
||||
expected_rx = payload_length + 1;
|
||||
} else {
|
||||
payload_length = this->state_.PKTLEN;
|
||||
expected_rx = payload_length;
|
||||
}
|
||||
if (payload_length == 0 || payload_length > 64) {
|
||||
ESP_LOGW(TAG, "Invalid payload length: %u", payload_length);
|
||||
if (payload_length == 0 || payload_length > 64 || rx_bytes != expected_rx) {
|
||||
ESP_LOGW(TAG, "Invalid packet: rx_bytes %u, payload_length %u", rx_bytes, payload_length);
|
||||
this->enter_idle_();
|
||||
this->strobe_(Command::FRX);
|
||||
this->strobe_(Command::RX);
|
||||
@@ -186,13 +188,12 @@ void CC1101Component::loop() {
|
||||
this->packet_.resize(payload_length);
|
||||
this->read_(Register::FIFO, this->packet_.data(), payload_length);
|
||||
|
||||
// Read status and trigger
|
||||
uint8_t status[2];
|
||||
this->read_(Register::FIFO, status, 2);
|
||||
int8_t rssi_raw = static_cast<int8_t>(status[0]);
|
||||
float rssi = (rssi_raw * RSSI_STEP) - RSSI_OFFSET;
|
||||
bool crc_ok = (status[1] & STATUS_CRC_OK_MASK) != 0;
|
||||
uint8_t lqi = status[1] & STATUS_LQI_MASK;
|
||||
// Read status from registers (more reliable than FIFO status bytes due to timing issues)
|
||||
this->read_(Register::RSSI);
|
||||
this->read_(Register::LQI);
|
||||
float rssi = (this->state_.RSSI * RSSI_STEP) - RSSI_OFFSET;
|
||||
bool crc_ok = (this->state_.LQI & STATUS_CRC_OK_MASK) != 0;
|
||||
uint8_t lqi = this->state_.LQI & STATUS_LQI_MASK;
|
||||
if (this->state_.CRC_EN == 0 || crc_ok) {
|
||||
this->packet_trigger_->trigger(this->packet_, rssi, lqi);
|
||||
}
|
||||
@@ -616,12 +617,15 @@ void CC1101Component::set_packet_mode(bool value) {
|
||||
this->state_.GDO0_CFG = 0x01;
|
||||
// Set max RX FIFO threshold to ensure we only trigger on end-of-packet
|
||||
this->state_.FIFO_THR = 15;
|
||||
// Don't append status bytes to FIFO - we read from registers instead
|
||||
this->state_.APPEND_STATUS = 0;
|
||||
} else {
|
||||
// Configure GDO0 for serial data (async serial mode)
|
||||
this->state_.GDO0_CFG = 0x0D;
|
||||
}
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::PKTCTRL0);
|
||||
this->write_(Register::PKTCTRL1);
|
||||
this->write_(Register::IOCFG0);
|
||||
this->write_(Register::FIFOTHR);
|
||||
}
|
||||
|
||||
@@ -369,7 +369,7 @@ optional<ClimateDeviceRestoreState> Climate::restore_state_() {
|
||||
}
|
||||
|
||||
void Climate::save_state_() {
|
||||
#if (defined(USE_ESP_IDF) || (defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 0, 0))) && \
|
||||
#if (defined(USE_ESP32) || (defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 0, 0))) && \
|
||||
!defined(CLANG_TIDY)
|
||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
||||
#define TEMP_IGNORE_MEMACCESS
|
||||
|
||||
@@ -51,7 +51,7 @@ void DallasTemperatureSensor::update() {
|
||||
}
|
||||
|
||||
float tempc = this->get_temp_c_();
|
||||
ESP_LOGD(TAG, "'%s': Got Temperature=%.1f°C", this->get_name().c_str(), tempc);
|
||||
ESP_LOGD(TAG, "'%s': Got Temperature=%f°C", this->get_name().c_str(), tempc);
|
||||
this->publish_state(tempc);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ void DebugComponent::get_device_info_(std::string &device_info) {
|
||||
#ifdef USE_ARDUINO
|
||||
ESP_LOGD(TAG, "Framework: Arduino");
|
||||
device_info += "Arduino";
|
||||
#elif defined(USE_ESP_IDF)
|
||||
#elif defined(USE_ESP32)
|
||||
ESP_LOGD(TAG, "Framework: ESP-IDF");
|
||||
device_info += "ESP-IDF";
|
||||
#else
|
||||
|
||||
@@ -357,11 +357,12 @@ def _is_framework_url(source: str) -> bool:
|
||||
# The default/recommended arduino framework version
|
||||
# - https://github.com/espressif/arduino-esp32/releases
|
||||
ARDUINO_FRAMEWORK_VERSION_LOOKUP = {
|
||||
"recommended": cv.Version(3, 3, 2),
|
||||
"latest": cv.Version(3, 3, 4),
|
||||
"dev": cv.Version(3, 3, 4),
|
||||
"recommended": cv.Version(3, 3, 5),
|
||||
"latest": cv.Version(3, 3, 5),
|
||||
"dev": cv.Version(3, 3, 5),
|
||||
}
|
||||
ARDUINO_PLATFORM_VERSION_LOOKUP = {
|
||||
cv.Version(3, 3, 5): cv.Version(55, 3, 35),
|
||||
cv.Version(3, 3, 4): cv.Version(55, 3, 31, "2"),
|
||||
cv.Version(3, 3, 3): cv.Version(55, 3, 31, "2"),
|
||||
cv.Version(3, 3, 2): cv.Version(55, 3, 31, "2"),
|
||||
@@ -374,15 +375,33 @@ ARDUINO_PLATFORM_VERSION_LOOKUP = {
|
||||
cv.Version(3, 1, 1): cv.Version(53, 3, 11),
|
||||
cv.Version(3, 1, 0): cv.Version(53, 3, 10),
|
||||
}
|
||||
# Maps Arduino framework versions to a compatible ESP-IDF version
|
||||
# These versions correspond to pioarduino/esp-idf releases
|
||||
# See: https://github.com/pioarduino/esp-idf/releases
|
||||
ARDUINO_IDF_VERSION_LOOKUP = {
|
||||
cv.Version(3, 3, 5): cv.Version(5, 5, 2),
|
||||
cv.Version(3, 3, 4): cv.Version(5, 5, 1),
|
||||
cv.Version(3, 3, 3): cv.Version(5, 5, 1),
|
||||
cv.Version(3, 3, 2): cv.Version(5, 5, 1),
|
||||
cv.Version(3, 3, 1): cv.Version(5, 5, 1),
|
||||
cv.Version(3, 3, 0): cv.Version(5, 5, 0),
|
||||
cv.Version(3, 2, 1): cv.Version(5, 4, 2),
|
||||
cv.Version(3, 2, 0): cv.Version(5, 4, 2),
|
||||
cv.Version(3, 1, 3): cv.Version(5, 3, 2),
|
||||
cv.Version(3, 1, 2): cv.Version(5, 3, 2),
|
||||
cv.Version(3, 1, 1): cv.Version(5, 3, 1),
|
||||
cv.Version(3, 1, 0): cv.Version(5, 3, 0),
|
||||
}
|
||||
|
||||
# The default/recommended esp-idf framework version
|
||||
# - https://github.com/espressif/esp-idf/releases
|
||||
ESP_IDF_FRAMEWORK_VERSION_LOOKUP = {
|
||||
"recommended": cv.Version(5, 5, 1),
|
||||
"latest": cv.Version(5, 5, 1),
|
||||
"dev": cv.Version(5, 5, 1),
|
||||
"recommended": cv.Version(5, 5, 2),
|
||||
"latest": cv.Version(5, 5, 2),
|
||||
"dev": cv.Version(5, 5, 2),
|
||||
}
|
||||
ESP_IDF_PLATFORM_VERSION_LOOKUP = {
|
||||
cv.Version(5, 5, 2): cv.Version(55, 3, 35),
|
||||
cv.Version(5, 5, 1): cv.Version(55, 3, 31, "2"),
|
||||
cv.Version(5, 5, 0): cv.Version(55, 3, 31, "2"),
|
||||
cv.Version(5, 4, 3): cv.Version(55, 3, 32),
|
||||
@@ -399,9 +418,9 @@ ESP_IDF_PLATFORM_VERSION_LOOKUP = {
|
||||
# The platform-espressif32 version
|
||||
# - https://github.com/pioarduino/platform-espressif32/releases
|
||||
PLATFORM_VERSION_LOOKUP = {
|
||||
"recommended": cv.Version(55, 3, 31, "2"),
|
||||
"latest": cv.Version(55, 3, 31, "2"),
|
||||
"dev": cv.Version(55, 3, 31, "2"),
|
||||
"recommended": cv.Version(55, 3, 35),
|
||||
"latest": cv.Version(55, 3, 35),
|
||||
"dev": cv.Version(55, 3, 35),
|
||||
}
|
||||
|
||||
|
||||
@@ -727,12 +746,14 @@ FRAMEWORK_SCHEMA = cv.Schema(
|
||||
)
|
||||
|
||||
|
||||
# Remove this class in 2026.7.0
|
||||
class _FrameworkMigrationWarning:
|
||||
shown = False
|
||||
|
||||
|
||||
def _show_framework_migration_message(name: str, variant: str) -> None:
|
||||
"""Show a friendly message about framework migration when defaulting to Arduino."""
|
||||
"""Show a message about the framework default change and how to switch back to Arduino."""
|
||||
# Remove this function in 2026.7.0
|
||||
if _FrameworkMigrationWarning.shown:
|
||||
return
|
||||
_FrameworkMigrationWarning.shown = True
|
||||
@@ -742,41 +763,27 @@ def _show_framework_migration_message(name: str, variant: str) -> None:
|
||||
message = (
|
||||
color(
|
||||
AnsiFore.BOLD_CYAN,
|
||||
f"💡 IMPORTANT: {name} doesn't have a framework specified!",
|
||||
f"💡 NOTICE: {name} does not have a framework specified.",
|
||||
)
|
||||
+ "\n\n"
|
||||
+ f"Currently, {variant} defaults to the Arduino framework.\n"
|
||||
+ color(AnsiFore.YELLOW, "This will change to ESP-IDF in ESPHome 2026.1.0.\n")
|
||||
+ f"Starting with ESPHome 2026.1.0, the default framework for {variant} is ESP-IDF.\n"
|
||||
+ "(We've been warning about this change since ESPHome 2025.8.0)\n"
|
||||
+ "\n"
|
||||
+ "Note: Newer ESP32 variants (C6, H2, P4, etc.) already use ESP-IDF by default.\n"
|
||||
+ "\n"
|
||||
+ "Why change? ESP-IDF offers:\n"
|
||||
+ color(AnsiFore.GREEN, " ✨ Up to 40% smaller binaries\n")
|
||||
+ color(AnsiFore.GREEN, " 🚀 Better performance and optimization\n")
|
||||
+ "Why we made this change:\n"
|
||||
+ color(AnsiFore.GREEN, " ✨ Up to 40% smaller firmware binaries\n")
|
||||
+ color(AnsiFore.GREEN, " ⚡ 2-3x faster compile times\n")
|
||||
+ color(AnsiFore.GREEN, " 📦 Custom-built firmware for your exact needs\n")
|
||||
+ color(
|
||||
AnsiFore.GREEN,
|
||||
" 🔧 Active development and testing by ESPHome developers\n",
|
||||
)
|
||||
+ color(AnsiFore.GREEN, " 🚀 Better performance and newer features\n")
|
||||
+ color(AnsiFore.GREEN, " 🔧 More actively maintained by ESPHome\n")
|
||||
+ "\n"
|
||||
+ "Trade-offs:\n"
|
||||
+ color(AnsiFore.YELLOW, " 🔄 Some components need migration\n")
|
||||
+ "To continue using Arduino, add this to your YAML under 'esp32:':\n"
|
||||
+ color(AnsiFore.WHITE, " framework:\n")
|
||||
+ color(AnsiFore.WHITE, " type: arduino\n")
|
||||
+ "\n"
|
||||
+ "What should I do?\n"
|
||||
+ color(AnsiFore.CYAN, " Option 1")
|
||||
+ ": Migrate to ESP-IDF (recommended)\n"
|
||||
+ " Add this to your YAML under 'esp32:':\n"
|
||||
+ color(AnsiFore.WHITE, " framework:\n")
|
||||
+ color(AnsiFore.WHITE, " type: esp-idf\n")
|
||||
+ "To silence this message with ESP-IDF, explicitly set:\n"
|
||||
+ color(AnsiFore.WHITE, " framework:\n")
|
||||
+ color(AnsiFore.WHITE, " type: esp-idf\n")
|
||||
+ "\n"
|
||||
+ color(AnsiFore.CYAN, " Option 2")
|
||||
+ ": Keep using Arduino (still supported)\n"
|
||||
+ " Add this to your YAML under 'esp32:':\n"
|
||||
+ color(AnsiFore.WHITE, " framework:\n")
|
||||
+ color(AnsiFore.WHITE, " type: arduino\n")
|
||||
+ "\n"
|
||||
+ "Need help? Check out the migration guide:\n"
|
||||
+ "Migration guide: "
|
||||
+ color(
|
||||
AnsiFore.BLUE,
|
||||
"https://esphome.io/guides/esp32_arduino_to_idf/",
|
||||
@@ -791,13 +798,13 @@ def _set_default_framework(config):
|
||||
config[CONF_FRAMEWORK] = FRAMEWORK_SCHEMA({})
|
||||
if CONF_TYPE not in config[CONF_FRAMEWORK]:
|
||||
variant = config[CONF_VARIANT]
|
||||
config[CONF_FRAMEWORK][CONF_TYPE] = FRAMEWORK_ESP_IDF
|
||||
# Show migration message for variants that previously defaulted to Arduino
|
||||
# Remove this message in 2026.7.0
|
||||
if variant in ARDUINO_ALLOWED_VARIANTS:
|
||||
config[CONF_FRAMEWORK][CONF_TYPE] = FRAMEWORK_ARDUINO
|
||||
_show_framework_migration_message(
|
||||
config.get(CONF_NAME, "This device"), variant
|
||||
)
|
||||
else:
|
||||
config[CONF_FRAMEWORK][CONF_TYPE] = FRAMEWORK_ESP_IDF
|
||||
|
||||
return config
|
||||
|
||||
@@ -991,6 +998,13 @@ async def to_code(config):
|
||||
add_idf_sdkconfig_option("CONFIG_MBEDTLS_PSK_MODES", True)
|
||||
add_idf_sdkconfig_option("CONFIG_MBEDTLS_CERTIFICATE_BUNDLE", True)
|
||||
|
||||
# Add IDF framework source for Arduino builds to ensure it uses the same version as
|
||||
# the ESP-IDF framework
|
||||
if (idf_ver := ARDUINO_IDF_VERSION_LOOKUP.get(framework_ver)) is not None:
|
||||
cg.add_platformio_option(
|
||||
"platform_packages", [_format_framework_espidf_version(idf_ver, None)]
|
||||
)
|
||||
|
||||
# ESP32-S2 Arduino: Disable USB Serial on boot to avoid TinyUSB dependency
|
||||
if get_esp32_variant() == VARIANT_ESP32S2:
|
||||
cg.add_build_unflag("-DARDUINO_USB_CDC_ON_BOOT=1")
|
||||
|
||||
@@ -1488,6 +1488,10 @@ BOARDS = {
|
||||
"name": "Arduino Nano ESP32",
|
||||
"variant": VARIANT_ESP32S3,
|
||||
},
|
||||
"arduino_nesso_n1": {
|
||||
"name": "Arduino Nesso-N1",
|
||||
"variant": VARIANT_ESP32C6,
|
||||
},
|
||||
"atd147_s3": {
|
||||
"name": "ArtronShop ATD1.47-S3",
|
||||
"variant": VARIANT_ESP32S3,
|
||||
@@ -1656,6 +1660,10 @@ BOARDS = {
|
||||
"name": "Espressif ESP32-C6-DevKitM-1",
|
||||
"variant": VARIANT_ESP32C6,
|
||||
},
|
||||
"esp32-c61-devkitc1-n8r2": {
|
||||
"name": "Espressif ESP32-C61-DevKitC-1 N8R2 (8 MB Flash Quad, 2 MB PSRAM Quad)",
|
||||
"variant": VARIANT_ESP32C61,
|
||||
},
|
||||
"esp32-devkitlipo": {
|
||||
"name": "OLIMEX ESP32-DevKit-LiPo",
|
||||
"variant": VARIANT_ESP32,
|
||||
@@ -1673,11 +1681,15 @@ BOARDS = {
|
||||
"variant": VARIANT_ESP32H2,
|
||||
},
|
||||
"esp32-p4": {
|
||||
"name": "Espressif ESP32-P4 generic",
|
||||
"name": "Espressif ESP32-P4 ES (pre rev.300) generic",
|
||||
"variant": VARIANT_ESP32P4,
|
||||
},
|
||||
"esp32-p4-evboard": {
|
||||
"name": "Espressif ESP32-P4 Function EV Board",
|
||||
"name": "Espressif ESP32-P4 Function EV Board (ES pre rev.300)",
|
||||
"variant": VARIANT_ESP32P4,
|
||||
},
|
||||
"esp32-p4_r3": {
|
||||
"name": "Espressif ESP32-P4 rev.300 generic",
|
||||
"variant": VARIANT_ESP32P4,
|
||||
},
|
||||
"esp32-pico-devkitm-2": {
|
||||
@@ -2093,7 +2105,7 @@ BOARDS = {
|
||||
"variant": VARIANT_ESP32,
|
||||
},
|
||||
"m5stack-tab5-p4": {
|
||||
"name": "M5STACK Tab5 esp32-p4 Board",
|
||||
"name": "M5STACK Tab5 esp32-p4 Board (ES pre rev.300)",
|
||||
"variant": VARIANT_ESP32P4,
|
||||
},
|
||||
"m5stack-timer-cam": {
|
||||
|
||||
@@ -24,7 +24,9 @@ extern "C" {
|
||||
#include <nvs_flash.h>
|
||||
|
||||
#ifdef USE_ARDUINO
|
||||
#include <esp32-hal-bt.h>
|
||||
// Prevent Arduino from releasing BT memory at startup (esp32-hal-misc.c).
|
||||
// Without this, esp_bt_controller_init() fails with ESP_ERR_INVALID_STATE.
|
||||
extern "C" bool btInUse() { return true; } // NOLINT(readability-identifier-naming)
|
||||
#endif
|
||||
|
||||
namespace esphome::esp32_ble {
|
||||
@@ -165,12 +167,6 @@ void ESP32BLE::advertising_init_() {
|
||||
bool ESP32BLE::ble_setup_() {
|
||||
esp_err_t err;
|
||||
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
|
||||
#ifdef USE_ARDUINO
|
||||
if (!btStart()) {
|
||||
ESP_LOGE(TAG, "btStart failed: %d", esp_bt_controller_get_status());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
|
||||
// start bt controller
|
||||
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {
|
||||
@@ -195,7 +191,6 @@ bool ESP32BLE::ble_setup_() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
#else
|
||||
@@ -334,12 +329,6 @@ bool ESP32BLE::ble_dismantle_() {
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ESP_HOSTED_ENABLE_BT_BLUEDROID
|
||||
#ifdef USE_ARDUINO
|
||||
if (!btStop()) {
|
||||
ESP_LOGE(TAG, "btStop failed: %d", esp_bt_controller_get_status());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {
|
||||
// stop bt controller
|
||||
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED) {
|
||||
@@ -363,7 +352,6 @@ bool ESP32BLE::ble_dismantle_() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
if (esp_hosted_bt_controller_disable() != ESP_OK) {
|
||||
ESP_LOGW(TAG, "esp_hosted_bt_controller_disable failed");
|
||||
|
||||
@@ -191,7 +191,8 @@ async def to_code(config):
|
||||
cg.add_define(ThreadModel.SINGLE)
|
||||
|
||||
cg.add_platformio_option(
|
||||
"extra_scripts", ["pre:testing_mode.py", "post:post_build.py"]
|
||||
"extra_scripts",
|
||||
["pre:testing_mode.py", "pre:exclude_updater.py", "post:post_build.py"],
|
||||
)
|
||||
|
||||
conf = config[CONF_FRAMEWORK]
|
||||
@@ -278,3 +279,8 @@ def copy_files():
|
||||
testing_mode_file,
|
||||
CORE.relative_build_path("testing_mode.py"),
|
||||
)
|
||||
exclude_updater_file = dir / "exclude_updater.py.script"
|
||||
copy_file_if_changed(
|
||||
exclude_updater_file,
|
||||
CORE.relative_build_path("exclude_updater.py"),
|
||||
)
|
||||
|
||||
21
esphome/components/esp8266/exclude_updater.py.script
Normal file
21
esphome/components/esp8266/exclude_updater.py.script
Normal file
@@ -0,0 +1,21 @@
|
||||
# pylint: disable=E0602
|
||||
Import("env") # noqa
|
||||
|
||||
import os
|
||||
|
||||
# Filter out Updater.cpp from the Arduino core build
|
||||
# This saves 228 bytes of .bss by not instantiating the global Update object
|
||||
# ESPHome uses its own native OTA backend instead
|
||||
|
||||
|
||||
def filter_updater_from_core(env, node):
|
||||
"""Filter callback to exclude Updater.cpp from framework build."""
|
||||
path = node.get_path()
|
||||
if path.endswith("Updater.cpp"):
|
||||
print(f"ESPHome: Excluding {os.path.basename(path)} from build (using native OTA backend)")
|
||||
return None
|
||||
return node
|
||||
|
||||
|
||||
# Apply the filter to framework sources
|
||||
env.AddBuildMiddleware(filter_updater_from_core, "**/cores/esp8266/Updater.cpp")
|
||||
@@ -31,7 +31,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
}
|
||||
)
|
||||
),
|
||||
cv.only_with_esp_idf,
|
||||
cv.only_on_esp32,
|
||||
only_on_variant(supported=[VARIANT_ESP32P4]),
|
||||
)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#endif
|
||||
#include "esphome/components/network/util.h"
|
||||
#include "esphome/components/ota/ota_backend.h"
|
||||
#include "esphome/components/ota/ota_backend_arduino_esp8266.h"
|
||||
#include "esphome/components/ota/ota_backend_esp8266.h"
|
||||
#include "esphome/components/ota/ota_backend_arduino_libretiny.h"
|
||||
#include "esphome/components/ota/ota_backend_arduino_rp2040.h"
|
||||
#include "esphome/components/ota/ota_backend_esp_idf.h"
|
||||
@@ -654,12 +654,7 @@ bool ESPHomeOTAComponent::handle_auth_send_() {
|
||||
this->auth_buf_[0] = this->auth_type_;
|
||||
hasher->get_hex(buf);
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char log_buf[65]; // Fixed size for SHA256 hex (64) + null, works for MD5 (32) too
|
||||
memcpy(log_buf, buf, hex_size);
|
||||
log_buf[hex_size] = '\0';
|
||||
ESP_LOGV(TAG, "Auth: Nonce is %s", log_buf);
|
||||
#endif
|
||||
ESP_LOGV(TAG, "Auth: Nonce is %.*s", hex_size, buf);
|
||||
}
|
||||
|
||||
// Try to write auth_type + nonce
|
||||
@@ -739,23 +734,13 @@ bool ESPHomeOTAComponent::handle_auth_read_() {
|
||||
hasher->add(nonce, hex_size * 2); // Add both nonce and cnonce (contiguous in buffer)
|
||||
hasher->calculate();
|
||||
|
||||
ESP_LOGV(TAG, "Auth: CNonce is %.*s", hex_size, cnonce);
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char log_buf[65]; // Fixed size for SHA256 hex (64) + null, works for MD5 (32) too
|
||||
// Log CNonce
|
||||
memcpy(log_buf, cnonce, hex_size);
|
||||
log_buf[hex_size] = '\0';
|
||||
ESP_LOGV(TAG, "Auth: CNonce is %s", log_buf);
|
||||
|
||||
// Log computed hash
|
||||
hasher->get_hex(log_buf);
|
||||
log_buf[hex_size] = '\0';
|
||||
ESP_LOGV(TAG, "Auth: Result is %s", log_buf);
|
||||
|
||||
// Log received response
|
||||
memcpy(log_buf, response, hex_size);
|
||||
log_buf[hex_size] = '\0';
|
||||
ESP_LOGV(TAG, "Auth: Response is %s", log_buf);
|
||||
char computed_hash[65]; // Buffer for hex-encoded hash (max expected length + null terminator)
|
||||
hasher->get_hex(computed_hash);
|
||||
ESP_LOGV(TAG, "Auth: Result is %.*s", hex_size, computed_hash);
|
||||
#endif
|
||||
ESP_LOGV(TAG, "Auth: Response is %.*s", hex_size, response);
|
||||
|
||||
// Compare response
|
||||
bool matches = hasher->equals_hex(response);
|
||||
|
||||
@@ -644,6 +644,12 @@ void EthernetComponent::dump_connect_params_() {
|
||||
dns_ip2 = dns_getserver(1);
|
||||
}
|
||||
|
||||
// Use stack buffers for IP address formatting to avoid heap allocations
|
||||
char ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
char subnet_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
char gateway_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
char dns1_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
char dns2_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" IP Address: %s\n"
|
||||
" Hostname: '%s'\n"
|
||||
@@ -651,9 +657,9 @@ void EthernetComponent::dump_connect_params_() {
|
||||
" Gateway: %s\n"
|
||||
" DNS1: %s\n"
|
||||
" DNS2: %s",
|
||||
network::IPAddress(&ip.ip).str().c_str(), App.get_name().c_str(),
|
||||
network::IPAddress(&ip.netmask).str().c_str(), network::IPAddress(&ip.gw).str().c_str(),
|
||||
network::IPAddress(dns_ip1).str().c_str(), network::IPAddress(dns_ip2).str().c_str());
|
||||
network::IPAddress(&ip.ip).str_to(ip_buf), App.get_name().c_str(),
|
||||
network::IPAddress(&ip.netmask).str_to(subnet_buf), network::IPAddress(&ip.gw).str_to(gateway_buf),
|
||||
network::IPAddress(dns_ip1).str_to(dns1_buf), network::IPAddress(dns_ip2).str_to(dns2_buf));
|
||||
|
||||
#if USE_NETWORK_IPV6
|
||||
struct esp_ip6_addr if_ip6s[CONFIG_LWIP_IPV6_NUM_ADDRESSES];
|
||||
@@ -665,12 +671,13 @@ void EthernetComponent::dump_connect_params_() {
|
||||
}
|
||||
#endif /* USE_NETWORK_IPV6 */
|
||||
|
||||
char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" MAC Address: %s\n"
|
||||
" Is Full Duplex: %s\n"
|
||||
" Link Speed: %u",
|
||||
this->get_eth_mac_address_pretty().c_str(), YESNO(this->get_duplex_mode() == ETH_DUPLEX_FULL),
|
||||
this->get_link_speed() == ETH_SPEED_100M ? 100 : 10);
|
||||
this->get_eth_mac_address_pretty_into_buffer(mac_buf),
|
||||
YESNO(this->get_duplex_mode() == ETH_DUPLEX_FULL), this->get_link_speed() == ETH_SPEED_100M ? 100 : 10);
|
||||
}
|
||||
|
||||
#ifdef USE_ETHERNET_SPI
|
||||
@@ -711,11 +718,16 @@ void EthernetComponent::get_eth_mac_address_raw(uint8_t *mac) {
|
||||
}
|
||||
|
||||
std::string EthernetComponent::get_eth_mac_address_pretty() {
|
||||
char buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
return std::string(this->get_eth_mac_address_pretty_into_buffer(buf));
|
||||
}
|
||||
|
||||
const char *EthernetComponent::get_eth_mac_address_pretty_into_buffer(
|
||||
std::span<char, MAC_ADDRESS_PRETTY_BUFFER_SIZE> buf) {
|
||||
uint8_t mac[6];
|
||||
get_eth_mac_address_raw(mac);
|
||||
char buf[18];
|
||||
format_mac_addr_upper(mac, buf);
|
||||
return std::string(buf);
|
||||
format_mac_addr_upper(mac, buf.data());
|
||||
return buf.data();
|
||||
}
|
||||
|
||||
eth_duplex_t EthernetComponent::get_duplex_mode() {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/components/network/ip_address.h"
|
||||
|
||||
#ifdef USE_ESP32
|
||||
@@ -93,6 +94,7 @@ class EthernetComponent : public Component {
|
||||
void set_use_address(const char *use_address);
|
||||
void get_eth_mac_address_raw(uint8_t *mac);
|
||||
std::string get_eth_mac_address_pretty();
|
||||
const char *get_eth_mac_address_pretty_into_buffer(std::span<char, MAC_ADDRESS_PRETTY_BUFFER_SIZE> buf);
|
||||
eth_duplex_t get_duplex_mode();
|
||||
eth_speed_t get_link_speed();
|
||||
bool powerdown();
|
||||
|
||||
@@ -2,37 +2,35 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/components/api/api_server.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace homeassistant {
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
static const char *const TAG = "homeassistant.binary_sensor";
|
||||
|
||||
void HomeassistantBinarySensor::setup() {
|
||||
api::global_api_server->subscribe_home_assistant_state(
|
||||
this->entity_id_, this->attribute_, [this](const std::string &state) {
|
||||
auto val = parse_on_off(state.c_str());
|
||||
switch (val) {
|
||||
case PARSE_NONE:
|
||||
case PARSE_TOGGLE:
|
||||
ESP_LOGW(TAG, "Can't convert '%s' to binary state!", state.c_str());
|
||||
break;
|
||||
case PARSE_ON:
|
||||
case PARSE_OFF:
|
||||
bool new_state = val == PARSE_ON;
|
||||
if (this->attribute_ != nullptr) {
|
||||
ESP_LOGD(TAG, "'%s::%s': Got attribute state %s", this->entity_id_, this->attribute_, ONOFF(new_state));
|
||||
} else {
|
||||
ESP_LOGD(TAG, "'%s': Got state %s", this->entity_id_, ONOFF(new_state));
|
||||
}
|
||||
if (this->initial_) {
|
||||
this->publish_initial_state(new_state);
|
||||
} else {
|
||||
this->publish_state(new_state);
|
||||
}
|
||||
break;
|
||||
api::global_api_server->subscribe_home_assistant_state(this->entity_id_, this->attribute_, [this](StringRef state) {
|
||||
auto val = parse_on_off(state.c_str());
|
||||
switch (val) {
|
||||
case PARSE_NONE:
|
||||
case PARSE_TOGGLE:
|
||||
ESP_LOGW(TAG, "Can't convert '%s' to binary state!", state.c_str());
|
||||
break;
|
||||
case PARSE_ON:
|
||||
case PARSE_OFF:
|
||||
bool new_state = val == PARSE_ON;
|
||||
if (this->attribute_ != nullptr) {
|
||||
ESP_LOGD(TAG, "'%s::%s': Got attribute state %s", this->entity_id_, this->attribute_, ONOFF(new_state));
|
||||
} else {
|
||||
ESP_LOGD(TAG, "'%s': Got state %s", this->entity_id_, ONOFF(new_state));
|
||||
}
|
||||
this->initial_ = false;
|
||||
});
|
||||
if (this->initial_) {
|
||||
this->publish_initial_state(new_state);
|
||||
} else {
|
||||
this->publish_state(new_state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
this->initial_ = false;
|
||||
});
|
||||
}
|
||||
void HomeassistantBinarySensor::dump_config() {
|
||||
LOG_BINARY_SENSOR("", "Homeassistant Binary Sensor", this);
|
||||
@@ -43,5 +41,4 @@ void HomeassistantBinarySensor::dump_config() {
|
||||
}
|
||||
float HomeassistantBinarySensor::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
|
||||
|
||||
} // namespace homeassistant
|
||||
} // namespace esphome
|
||||
} // namespace esphome::homeassistant
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace homeassistant {
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
class HomeassistantBinarySensor : public binary_sensor::BinarySensor, public Component {
|
||||
public:
|
||||
@@ -20,5 +19,4 @@ class HomeassistantBinarySensor : public binary_sensor::BinarySensor, public Com
|
||||
bool initial_{true};
|
||||
};
|
||||
|
||||
} // namespace homeassistant
|
||||
} // namespace esphome
|
||||
} // namespace esphome::homeassistant
|
||||
|
||||
@@ -4,13 +4,12 @@
|
||||
#include "esphome/components/api/api_server.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace homeassistant {
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
static const char *const TAG = "homeassistant.number";
|
||||
|
||||
void HomeassistantNumber::state_changed_(const std::string &state) {
|
||||
auto number_value = parse_number<float>(state);
|
||||
void HomeassistantNumber::state_changed_(StringRef state) {
|
||||
auto number_value = parse_number<float>(state.c_str());
|
||||
if (!number_value.has_value()) {
|
||||
ESP_LOGW(TAG, "'%s': Can't convert '%s' to number!", this->entity_id_, state.c_str());
|
||||
this->publish_state(NAN);
|
||||
@@ -23,8 +22,8 @@ void HomeassistantNumber::state_changed_(const std::string &state) {
|
||||
this->publish_state(number_value.value());
|
||||
}
|
||||
|
||||
void HomeassistantNumber::min_retrieved_(const std::string &min) {
|
||||
auto min_value = parse_number<float>(min);
|
||||
void HomeassistantNumber::min_retrieved_(StringRef min) {
|
||||
auto min_value = parse_number<float>(min.c_str());
|
||||
if (!min_value.has_value()) {
|
||||
ESP_LOGE(TAG, "'%s': Can't convert 'min' value '%s' to number!", this->entity_id_, min.c_str());
|
||||
return;
|
||||
@@ -33,8 +32,8 @@ void HomeassistantNumber::min_retrieved_(const std::string &min) {
|
||||
this->traits.set_min_value(min_value.value());
|
||||
}
|
||||
|
||||
void HomeassistantNumber::max_retrieved_(const std::string &max) {
|
||||
auto max_value = parse_number<float>(max);
|
||||
void HomeassistantNumber::max_retrieved_(StringRef max) {
|
||||
auto max_value = parse_number<float>(max.c_str());
|
||||
if (!max_value.has_value()) {
|
||||
ESP_LOGE(TAG, "'%s': Can't convert 'max' value '%s' to number!", this->entity_id_, max.c_str());
|
||||
return;
|
||||
@@ -43,8 +42,8 @@ void HomeassistantNumber::max_retrieved_(const std::string &max) {
|
||||
this->traits.set_max_value(max_value.value());
|
||||
}
|
||||
|
||||
void HomeassistantNumber::step_retrieved_(const std::string &step) {
|
||||
auto step_value = parse_number<float>(step);
|
||||
void HomeassistantNumber::step_retrieved_(StringRef step) {
|
||||
auto step_value = parse_number<float>(step.c_str());
|
||||
if (!step_value.has_value()) {
|
||||
ESP_LOGE(TAG, "'%s': Can't convert 'step' value '%s' to number!", this->entity_id_, step.c_str());
|
||||
return;
|
||||
@@ -99,5 +98,4 @@ void HomeassistantNumber::control(float value) {
|
||||
api::global_api_server->send_homeassistant_action(resp);
|
||||
}
|
||||
|
||||
} // namespace homeassistant
|
||||
} // namespace esphome
|
||||
} // namespace esphome::homeassistant
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "esphome/components/number/number.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/string_ref.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace homeassistant {
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
class HomeassistantNumber : public number::Number, public Component {
|
||||
public:
|
||||
@@ -18,14 +15,14 @@ class HomeassistantNumber : public number::Number, public Component {
|
||||
float get_setup_priority() const override;
|
||||
|
||||
protected:
|
||||
void state_changed_(const std::string &state);
|
||||
void min_retrieved_(const std::string &min);
|
||||
void max_retrieved_(const std::string &max);
|
||||
void step_retrieved_(const std::string &step);
|
||||
void state_changed_(StringRef state);
|
||||
void min_retrieved_(StringRef min);
|
||||
void max_retrieved_(StringRef max);
|
||||
void step_retrieved_(StringRef step);
|
||||
|
||||
void control(float value) override;
|
||||
|
||||
const char *entity_id_{nullptr};
|
||||
};
|
||||
} // namespace homeassistant
|
||||
} // namespace esphome
|
||||
|
||||
} // namespace esphome::homeassistant
|
||||
|
||||
@@ -2,28 +2,26 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/components/api/api_server.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace homeassistant {
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
static const char *const TAG = "homeassistant.sensor";
|
||||
|
||||
void HomeassistantSensor::setup() {
|
||||
api::global_api_server->subscribe_home_assistant_state(
|
||||
this->entity_id_, this->attribute_, [this](const std::string &state) {
|
||||
auto val = parse_number<float>(state);
|
||||
if (!val.has_value()) {
|
||||
ESP_LOGW(TAG, "'%s': Can't convert '%s' to number!", this->entity_id_, state.c_str());
|
||||
this->publish_state(NAN);
|
||||
return;
|
||||
}
|
||||
api::global_api_server->subscribe_home_assistant_state(this->entity_id_, this->attribute_, [this](StringRef state) {
|
||||
auto val = parse_number<float>(state.c_str());
|
||||
if (!val.has_value()) {
|
||||
ESP_LOGW(TAG, "'%s': Can't convert '%s' to number!", this->entity_id_, state.c_str());
|
||||
this->publish_state(NAN);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->attribute_ != nullptr) {
|
||||
ESP_LOGD(TAG, "'%s::%s': Got attribute state %.2f", this->entity_id_, this->attribute_, *val);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "'%s': Got state %.2f", this->entity_id_, *val);
|
||||
}
|
||||
this->publish_state(*val);
|
||||
});
|
||||
if (this->attribute_ != nullptr) {
|
||||
ESP_LOGD(TAG, "'%s::%s': Got attribute state %.2f", this->entity_id_, this->attribute_, *val);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "'%s': Got state %.2f", this->entity_id_, *val);
|
||||
}
|
||||
this->publish_state(*val);
|
||||
});
|
||||
}
|
||||
void HomeassistantSensor::dump_config() {
|
||||
LOG_SENSOR("", "Homeassistant Sensor", this);
|
||||
@@ -34,5 +32,4 @@ void HomeassistantSensor::dump_config() {
|
||||
}
|
||||
float HomeassistantSensor::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; }
|
||||
|
||||
} // namespace homeassistant
|
||||
} // namespace esphome
|
||||
} // namespace esphome::homeassistant
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace homeassistant {
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
class HomeassistantSensor : public sensor::Sensor, public Component {
|
||||
public:
|
||||
@@ -19,5 +18,4 @@ class HomeassistantSensor : public sensor::Sensor, public Component {
|
||||
const char *attribute_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace homeassistant
|
||||
} // namespace esphome
|
||||
} // namespace esphome::homeassistant
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
#include "esphome/components/api/api_server.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace homeassistant {
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
static const char *const TAG = "homeassistant.switch";
|
||||
|
||||
using namespace esphome::switch_;
|
||||
|
||||
void HomeassistantSwitch::setup() {
|
||||
api::global_api_server->subscribe_home_assistant_state(this->entity_id_, nullptr, [this](const std::string &state) {
|
||||
api::global_api_server->subscribe_home_assistant_state(this->entity_id_, nullptr, [this](StringRef state) {
|
||||
auto val = parse_on_off(state.c_str());
|
||||
switch (val) {
|
||||
case PARSE_NONE:
|
||||
@@ -59,5 +58,4 @@ void HomeassistantSwitch::write_state(bool state) {
|
||||
api::global_api_server->send_homeassistant_action(resp);
|
||||
}
|
||||
|
||||
} // namespace homeassistant
|
||||
} // namespace esphome
|
||||
} // namespace esphome::homeassistant
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "esphome/components/switch/switch.h"
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace homeassistant {
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
class HomeassistantSwitch : public switch_::Switch, public Component {
|
||||
public:
|
||||
@@ -18,5 +17,4 @@ class HomeassistantSwitch : public switch_::Switch, public Component {
|
||||
const char *entity_id_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace homeassistant
|
||||
} // namespace esphome
|
||||
} // namespace esphome::homeassistant
|
||||
|
||||
@@ -2,21 +2,19 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/components/api/api_server.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace homeassistant {
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
static const char *const TAG = "homeassistant.text_sensor";
|
||||
|
||||
void HomeassistantTextSensor::setup() {
|
||||
api::global_api_server->subscribe_home_assistant_state(
|
||||
this->entity_id_, this->attribute_, [this](const std::string &state) {
|
||||
if (this->attribute_ != nullptr) {
|
||||
ESP_LOGD(TAG, "'%s::%s': Got attribute state '%s'", this->entity_id_, this->attribute_, state.c_str());
|
||||
} else {
|
||||
ESP_LOGD(TAG, "'%s': Got state '%s'", this->entity_id_, state.c_str());
|
||||
}
|
||||
this->publish_state(state);
|
||||
});
|
||||
api::global_api_server->subscribe_home_assistant_state(this->entity_id_, this->attribute_, [this](StringRef state) {
|
||||
if (this->attribute_ != nullptr) {
|
||||
ESP_LOGD(TAG, "'%s::%s': Got attribute state '%s'", this->entity_id_, this->attribute_, state.c_str());
|
||||
} else {
|
||||
ESP_LOGD(TAG, "'%s': Got state '%s'", this->entity_id_, state.c_str());
|
||||
}
|
||||
this->publish_state(state.str());
|
||||
});
|
||||
}
|
||||
void HomeassistantTextSensor::dump_config() {
|
||||
LOG_TEXT_SENSOR("", "Homeassistant Text Sensor", this);
|
||||
@@ -26,5 +24,5 @@ void HomeassistantTextSensor::dump_config() {
|
||||
}
|
||||
}
|
||||
float HomeassistantTextSensor::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; }
|
||||
} // namespace homeassistant
|
||||
} // namespace esphome
|
||||
|
||||
} // namespace esphome::homeassistant
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/text_sensor/text_sensor.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace homeassistant {
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
class HomeassistantTextSensor : public text_sensor::TextSensor, public Component {
|
||||
public:
|
||||
@@ -19,5 +18,4 @@ class HomeassistantTextSensor : public text_sensor::TextSensor, public Component
|
||||
const char *attribute_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace homeassistant
|
||||
} // namespace esphome
|
||||
} // namespace esphome::homeassistant
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "esphome/components/md5/md5.h"
|
||||
#include "esphome/components/watchdog/watchdog.h"
|
||||
#include "esphome/components/ota/ota_backend.h"
|
||||
#include "esphome/components/ota/ota_backend_arduino_esp8266.h"
|
||||
#include "esphome/components/ota/ota_backend_esp8266.h"
|
||||
#include "esphome/components/ota/ota_backend_arduino_rp2040.h"
|
||||
#include "esphome/components/ota/ota_backend_esp_idf.h"
|
||||
|
||||
|
||||
@@ -8,8 +8,9 @@ extern "C" {
|
||||
uint8_t temprature_sens_read();
|
||||
}
|
||||
#elif defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C3) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32C61) || defined(USE_ESP32_VARIANT_ESP32H2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
defined(USE_ESP32_VARIANT_ESP32C5) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32C61) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#include "driver/temperature_sensor.h"
|
||||
#endif // USE_ESP32_VARIANT
|
||||
#endif // USE_ESP32
|
||||
@@ -27,9 +28,9 @@ namespace internal_temperature {
|
||||
|
||||
static const char *const TAG = "internal_temperature";
|
||||
#ifdef USE_ESP32
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C61) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32P4) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C5) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32C61) || defined(USE_ESP32_VARIANT_ESP32H2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
static temperature_sensor_handle_t tsensNew = NULL;
|
||||
#endif // USE_ESP32_VARIANT
|
||||
#endif // USE_ESP32
|
||||
@@ -44,8 +45,9 @@ void InternalTemperatureSensor::update() {
|
||||
temperature = (raw - 32) / 1.8f;
|
||||
success = (raw != 128);
|
||||
#elif defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C3) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32C61) || defined(USE_ESP32_VARIANT_ESP32H2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
defined(USE_ESP32_VARIANT_ESP32C5) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32C61) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
esp_err_t result = temperature_sensor_get_celsius(tsensNew, &temperature);
|
||||
success = (result == ESP_OK);
|
||||
if (!success) {
|
||||
@@ -81,9 +83,9 @@ void InternalTemperatureSensor::update() {
|
||||
|
||||
void InternalTemperatureSensor::setup() {
|
||||
#ifdef USE_ESP32
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C61) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32P4) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C5) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32C61) || defined(USE_ESP32_VARIANT_ESP32H2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
temperature_sensor_config_t tsens_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80);
|
||||
|
||||
esp_err_t result = temperature_sensor_install(&tsens_config, &tsensNew);
|
||||
|
||||
@@ -65,8 +65,8 @@ void HOT Logger::log_vprintf_(uint8_t level, const char *tag, int line, const ch
|
||||
uint16_t buffer_at = 0; // Initialize buffer position
|
||||
this->format_log_to_buffer_with_terminator_(level, tag, line, format, args, console_buffer, &buffer_at,
|
||||
MAX_CONSOLE_LOG_MSG_SIZE);
|
||||
// Add newline if platform needs it (ESP32 doesn't add via write_msg_)
|
||||
this->add_newline_to_buffer_if_needed_(console_buffer, &buffer_at, MAX_CONSOLE_LOG_MSG_SIZE);
|
||||
// Add newline before writing to console
|
||||
this->add_newline_to_buffer_(console_buffer, &buffer_at, MAX_CONSOLE_LOG_MSG_SIZE);
|
||||
this->write_msg_(console_buffer, buffer_at);
|
||||
}
|
||||
|
||||
|
||||
@@ -117,17 +117,6 @@ static constexpr uint16_t MAX_HEADER_SIZE = 128;
|
||||
// "0x" + 2 hex digits per byte + '\0'
|
||||
static constexpr size_t MAX_POINTER_REPRESENTATION = 2 + sizeof(void *) * 2 + 1;
|
||||
|
||||
// Platform-specific: does write_msg_ add its own newline?
|
||||
// false: Caller must add newline to buffer before calling write_msg_ (ESP32, ESP8266, RP2040, LibreTiny, Zephyr)
|
||||
// Allows single write call with newline included for efficiency
|
||||
// true: write_msg_ adds newline itself via puts()/println() (other platforms)
|
||||
// Newline should NOT be added to buffer
|
||||
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
|
||||
static constexpr bool WRITE_MSG_ADDS_NEWLINE = false;
|
||||
#else
|
||||
static constexpr bool WRITE_MSG_ADDS_NEWLINE = true;
|
||||
#endif
|
||||
|
||||
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_ZEPHYR)
|
||||
/** Enum for logging UART selection
|
||||
*
|
||||
@@ -259,22 +248,20 @@ class Logger : public Component {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to add newline to buffer for platforms that need it
|
||||
// Helper to add newline to buffer before writing to console
|
||||
// Modifies buffer_at to include the newline
|
||||
inline void HOT add_newline_to_buffer_if_needed_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size) {
|
||||
if constexpr (!WRITE_MSG_ADDS_NEWLINE) {
|
||||
// Add newline - don't need to maintain null termination
|
||||
// write_msg_ now always receives explicit length, so we can safely overwrite the null terminator
|
||||
// This is safe because:
|
||||
// 1. Callbacks already received the message (before we add newline)
|
||||
// 2. write_msg_ receives the length explicitly (doesn't need null terminator)
|
||||
if (*buffer_at < buffer_size) {
|
||||
buffer[(*buffer_at)++] = '\n';
|
||||
} else if (buffer_size > 0) {
|
||||
// Buffer was full - replace last char with newline to ensure it's visible
|
||||
buffer[buffer_size - 1] = '\n';
|
||||
*buffer_at = buffer_size;
|
||||
}
|
||||
inline void HOT add_newline_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size) {
|
||||
// Add newline - don't need to maintain null termination
|
||||
// write_msg_ receives explicit length, so we can safely overwrite the null terminator
|
||||
// This is safe because:
|
||||
// 1. Callbacks already received the message (before we add newline)
|
||||
// 2. write_msg_ receives the length explicitly (doesn't need null terminator)
|
||||
if (*buffer_at < buffer_size) {
|
||||
buffer[(*buffer_at)++] = '\n';
|
||||
} else if (buffer_size > 0) {
|
||||
// Buffer was full - replace last char with newline to ensure it's visible
|
||||
buffer[buffer_size - 1] = '\n';
|
||||
*buffer_at = buffer_size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +270,7 @@ class Logger : public Component {
|
||||
inline void HOT write_tx_buffer_to_console_(uint16_t offset = 0, uint16_t *length = nullptr) {
|
||||
if (this->baud_rate_ > 0) {
|
||||
uint16_t *len_ptr = length ? length : &this->tx_buffer_at_;
|
||||
this->add_newline_to_buffer_if_needed_(this->tx_buffer_ + offset, len_ptr, this->tx_buffer_size_ - offset);
|
||||
this->add_newline_to_buffer_(this->tx_buffer_ + offset, len_ptr, this->tx_buffer_size_ - offset);
|
||||
this->write_msg_(this->tx_buffer_ + offset, *len_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,23 @@
|
||||
|
||||
namespace esphome::logger {
|
||||
|
||||
void HOT Logger::write_msg_(const char *msg, size_t) {
|
||||
time_t rawtime;
|
||||
struct tm *timeinfo;
|
||||
char buffer[80];
|
||||
void HOT Logger::write_msg_(const char *msg, size_t len) {
|
||||
static constexpr size_t TIMESTAMP_LEN = 10; // "[HH:MM:SS]"
|
||||
// tx_buffer_size_ defaults to 512, so 768 covers default + headroom
|
||||
char buffer[TIMESTAMP_LEN + 768];
|
||||
|
||||
time_t rawtime;
|
||||
time(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
strftime(buffer, sizeof buffer, "[%H:%M:%S]", timeinfo);
|
||||
fputs(buffer, stdout);
|
||||
puts(msg);
|
||||
struct tm *timeinfo = localtime(&rawtime);
|
||||
size_t pos = strftime(buffer, TIMESTAMP_LEN + 1, "[%H:%M:%S]", timeinfo);
|
||||
|
||||
// Copy message (with newline already included by caller)
|
||||
size_t copy_len = std::min(len, sizeof(buffer) - pos);
|
||||
memcpy(buffer + pos, msg, copy_len);
|
||||
pos += copy_len;
|
||||
|
||||
// Single write for everything
|
||||
fwrite(buffer, 1, pos, stdout);
|
||||
}
|
||||
|
||||
void Logger::pre_setup() { global_logger = this; }
|
||||
|
||||
@@ -5,7 +5,7 @@ Constants already defined in esphome.const are not duplicated here and must be i
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from typing import Any
|
||||
|
||||
from esphome import codegen as cg, config_validation as cv
|
||||
from esphome.const import CONF_ITEMS
|
||||
@@ -96,13 +96,9 @@ class LValidator:
|
||||
return None
|
||||
if isinstance(value, Lambda):
|
||||
# Local import to avoid circular import
|
||||
from .lvcode import CodeContext, LambdaContext
|
||||
from .lvcode import get_lambda_context_args
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# CodeContext does not have get_automation_parameters
|
||||
# so we need to assert the type here
|
||||
assert isinstance(CodeContext.code_context, LambdaContext)
|
||||
args = args or CodeContext.code_context.get_automation_parameters()
|
||||
args = args or get_lambda_context_args()
|
||||
return cg.RawExpression(
|
||||
call_lambda(
|
||||
await cg.process_lambda(value, args, return_type=self.rtype)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import re
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from typing import Any
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import image
|
||||
@@ -404,14 +404,9 @@ class TextValidator(LValidator):
|
||||
self, value: Any, args: list[tuple[SafeExpType, str]] | None = None
|
||||
) -> Expression:
|
||||
# Local import to avoid circular import at module level
|
||||
from .lvcode import get_lambda_context_args
|
||||
|
||||
from .lvcode import CodeContext, LambdaContext
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# CodeContext does not have get_automation_parameters
|
||||
# so we need to assert the type here
|
||||
assert isinstance(CodeContext.code_context, LambdaContext)
|
||||
args = args or CodeContext.code_context.get_automation_parameters()
|
||||
args = args or get_lambda_context_args()
|
||||
|
||||
if isinstance(value, dict):
|
||||
if format_str := value.get(CONF_FORMAT):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import abc
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from esphome import codegen as cg
|
||||
from esphome.config import Config
|
||||
@@ -200,6 +201,21 @@ class LvContext(LambdaContext):
|
||||
return self.add(*args)
|
||||
|
||||
|
||||
def get_lambda_context_args() -> list[tuple[SafeExpType, str]]:
|
||||
"""Get automation parameters from the current lambda context if available.
|
||||
|
||||
When called from outside LVGL's context (e.g., from interval),
|
||||
CodeContext.code_context will be None, so return empty args.
|
||||
"""
|
||||
if CodeContext.code_context is None:
|
||||
return []
|
||||
if TYPE_CHECKING:
|
||||
# CodeContext base class doesn't define get_automation_parameters(),
|
||||
# but LambdaContext and LvContext (the concrete implementations) do.
|
||||
assert isinstance(CodeContext.code_context, LambdaContext)
|
||||
return CodeContext.code_context.get_automation_parameters()
|
||||
|
||||
|
||||
class LocalVariable(MockObj):
|
||||
"""
|
||||
Create a local variable and enclose the code using it within a block.
|
||||
|
||||
@@ -368,7 +368,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
cv.only_with_esp_idf,
|
||||
cv.only_on_esp32,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "micro_wake_word.h"
|
||||
#include "streaming_model.h"
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
namespace esphome {
|
||||
namespace micro_wake_word {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "micro_wake_word.h"
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/hal.h"
|
||||
@@ -473,4 +473,4 @@ bool MicroWakeWord::update_model_probabilities_(const int8_t audio_features[PREP
|
||||
} // namespace micro_wake_word
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ESP_IDF
|
||||
#endif // USE_ESP32
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "preprocessor_settings.h"
|
||||
#include "streaming_model.h"
|
||||
@@ -140,4 +140,4 @@ class MicroWakeWord : public Component
|
||||
} // namespace micro_wake_word
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ESP_IDF
|
||||
#endif // USE_ESP32
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "streaming_model.h"
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "preprocessor_settings.h"
|
||||
|
||||
|
||||
@@ -165,8 +165,8 @@ def model_schema(config):
|
||||
)
|
||||
return cv.All(
|
||||
schema,
|
||||
cv.only_on_esp32,
|
||||
only_on_variant(supported=[VARIANT_ESP32P4]),
|
||||
cv.only_with_esp_idf,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -224,8 +224,8 @@ def _config_schema(config):
|
||||
schema = model_schema(config)
|
||||
return cv.All(
|
||||
schema,
|
||||
cv.only_on_esp32,
|
||||
only_on_variant(supported=[VARIANT_ESP32S3]),
|
||||
cv.only_with_esp_idf,
|
||||
)(config)
|
||||
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ def model_schema(config):
|
||||
}
|
||||
)
|
||||
if bus_mode != TYPE_SINGLE:
|
||||
return cv.All(schema, cv.only_with_esp_idf)
|
||||
return cv.All(schema, cv.only_on_esp32)
|
||||
return schema
|
||||
|
||||
|
||||
|
||||
@@ -93,9 +93,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
),
|
||||
cv.Optional(CONF_NUM_CHANNELS): cv.int_range(min=1, max=2),
|
||||
cv.Optional(CONF_QUEUE_MODE, default=False): cv.boolean,
|
||||
cv.SplitDefault(CONF_TASK_STACK_IN_PSRAM, esp32_idf=False): cv.All(
|
||||
cv.boolean, cv.only_with_esp_idf
|
||||
),
|
||||
cv.Optional(CONF_TASK_STACK_IN_PSRAM, default=False): cv.boolean,
|
||||
}
|
||||
),
|
||||
cv.only_on([PLATFORM_ESP32]),
|
||||
|
||||
@@ -232,16 +232,6 @@ void MQTTBackendESP32::esphome_mqtt_task(void *params) {
|
||||
this_mqtt->mqtt_event_pool_.release(elem);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up any remaining items in the queue
|
||||
struct QueueElement *elem;
|
||||
while ((elem = this_mqtt->mqtt_queue_.pop()) != nullptr) {
|
||||
this_mqtt->mqtt_event_pool_.release(elem);
|
||||
}
|
||||
|
||||
// Note: EventPool destructor will clean up the pool itself
|
||||
// Task will delete itself
|
||||
vTaskDelete(nullptr);
|
||||
}
|
||||
|
||||
bool MQTTBackendESP32::enqueue_(MqttQueueTypeT type, const char *topic, int qos, bool retain, const char *payload,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/macros.h"
|
||||
|
||||
#if defined(USE_ESP_IDF) || defined(USE_LIBRETINY) || USE_ARDUINO_VERSION_CODE > VERSION_CODE(3, 0, 0)
|
||||
#if defined(USE_ESP32) || defined(USE_LIBRETINY) || USE_ARDUINO_VERSION_CODE > VERSION_CODE(3, 0, 0)
|
||||
#include <lwip/ip_addr.h>
|
||||
#endif
|
||||
|
||||
@@ -40,6 +40,9 @@ using ip4_addr_t = in_addr;
|
||||
namespace esphome {
|
||||
namespace network {
|
||||
|
||||
/// Buffer size for IP address string (IPv6 max: 39 chars + null)
|
||||
static constexpr size_t IP_ADDRESS_BUFFER_SIZE = 40;
|
||||
|
||||
struct IPAddress {
|
||||
public:
|
||||
#ifdef USE_HOST
|
||||
@@ -50,6 +53,10 @@ struct IPAddress {
|
||||
IPAddress(const std::string &in_address) { inet_aton(in_address.c_str(), &ip_addr_); }
|
||||
IPAddress(const ip_addr_t *other_ip) { ip_addr_ = *other_ip; }
|
||||
std::string str() const { return str_lower_case(inet_ntoa(ip_addr_)); }
|
||||
/// Write IP address to buffer. Buffer must be at least IP_ADDRESS_BUFFER_SIZE bytes.
|
||||
char *str_to(char *buf) const {
|
||||
return const_cast<char *>(inet_ntop(AF_INET, &ip_addr_, buf, IP_ADDRESS_BUFFER_SIZE));
|
||||
}
|
||||
#else
|
||||
IPAddress() { ip_addr_set_zero(&ip_addr_); }
|
||||
IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) {
|
||||
@@ -128,6 +135,8 @@ struct IPAddress {
|
||||
bool is_ip6() const { return IP_IS_V6(&ip_addr_); }
|
||||
bool is_multicast() const { return ip_addr_ismulticast(&ip_addr_); }
|
||||
std::string str() const { return str_lower_case(ipaddr_ntoa(&ip_addr_)); }
|
||||
/// Write IP address to buffer. Buffer must be at least IP_ADDRESS_BUFFER_SIZE bytes.
|
||||
char *str_to(char *buf) const { return ipaddr_ntoa_r(&ip_addr_, buf, IP_ADDRESS_BUFFER_SIZE); }
|
||||
bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
|
||||
bool operator!=(const IPAddress &other) const { return !ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
|
||||
IPAddress &operator+=(uint8_t increase) {
|
||||
|
||||
@@ -49,7 +49,8 @@ void OneWireBus::search() {
|
||||
break;
|
||||
auto *address8 = reinterpret_cast<uint8_t *>(&address);
|
||||
if (crc8(address8, 7) != address8[7]) {
|
||||
ESP_LOGW(TAG, "Dallas device 0x%s has invalid CRC.", format_hex(address).c_str());
|
||||
char hex_buf[17];
|
||||
ESP_LOGW(TAG, "Dallas device 0x%s has invalid CRC.", format_hex_to(hex_buf, address));
|
||||
} else {
|
||||
this->devices_.push_back(address);
|
||||
}
|
||||
@@ -82,8 +83,9 @@ void OneWireBus::dump_devices_(const char *tag) {
|
||||
ESP_LOGW(tag, " Found no devices!");
|
||||
} else {
|
||||
ESP_LOGCONFIG(tag, " Found devices:");
|
||||
char hex_buf[17]; // uint64_t = 16 hex chars + null
|
||||
for (auto &address : this->devices_) {
|
||||
ESP_LOGCONFIG(tag, " 0x%s (%s)", format_hex(address).c_str(), LOG_STR_ARG(get_model_str(address & 0xff)));
|
||||
ESP_LOGCONFIG(tag, " 0x%s (%s)", format_hex_to(hex_buf, address), LOG_STR_ARG(get_model_str(address & 0xff)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +152,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
}
|
||||
).extend(_CONNECTION_SCHEMA),
|
||||
cv.has_exactly_one_key(CONF_NETWORK_KEY, CONF_TLV),
|
||||
cv.only_with_esp_idf,
|
||||
only_on_variant(supported=[VARIANT_ESP32C5, VARIANT_ESP32C6, VARIANT_ESP32H2]),
|
||||
_validate,
|
||||
_require_vfs_select,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "esphome/core/defines.h"
|
||||
#if defined(USE_OPENTHREAD) && defined(USE_ESP_IDF)
|
||||
#if defined(USE_OPENTHREAD) && defined(USE_ESP32)
|
||||
#include <openthread/logging.h>
|
||||
#include "openthread.h"
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ FILTER_SOURCE_FILES = filter_source_files_from_platform(
|
||||
PlatformFramework.ESP32_ARDUINO,
|
||||
PlatformFramework.ESP32_IDF,
|
||||
},
|
||||
"ota_backend_arduino_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
|
||||
"ota_backend_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
|
||||
"ota_backend_arduino_rp2040.cpp": {PlatformFramework.RP2040_ARDUINO},
|
||||
"ota_backend_arduino_libretiny.cpp": {
|
||||
PlatformFramework.BK72XX_ARDUINO,
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
#ifdef USE_ARDUINO
|
||||
#ifdef USE_ESP8266
|
||||
#include "ota_backend_arduino_esp8266.h"
|
||||
#include "ota_backend.h"
|
||||
|
||||
#include "esphome/components/esp8266/preferences.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include <Updater.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace ota {
|
||||
|
||||
static const char *const TAG = "ota.arduino_esp8266";
|
||||
|
||||
std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ArduinoESP8266OTABackend>(); }
|
||||
|
||||
OTAResponseTypes ArduinoESP8266OTABackend::begin(size_t image_size) {
|
||||
// Handle UPDATE_SIZE_UNKNOWN (0) by calculating available space
|
||||
if (image_size == 0) {
|
||||
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
|
||||
image_size = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
|
||||
}
|
||||
bool ret = Update.begin(image_size, U_FLASH);
|
||||
if (ret) {
|
||||
esp8266::preferences_prevent_write(true);
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
uint8_t error = Update.getError();
|
||||
if (error == UPDATE_ERROR_BOOTSTRAP)
|
||||
return OTA_RESPONSE_ERROR_INVALID_BOOTSTRAPPING;
|
||||
if (error == UPDATE_ERROR_NEW_FLASH_CONFIG)
|
||||
return OTA_RESPONSE_ERROR_WRONG_NEW_FLASH_CONFIG;
|
||||
if (error == UPDATE_ERROR_FLASH_CONFIG)
|
||||
return OTA_RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG;
|
||||
if (error == UPDATE_ERROR_SPACE)
|
||||
return OTA_RESPONSE_ERROR_ESP8266_NOT_ENOUGH_SPACE;
|
||||
|
||||
ESP_LOGE(TAG, "Begin error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
void ArduinoESP8266OTABackend::set_update_md5(const char *md5) {
|
||||
Update.setMD5(md5);
|
||||
this->md5_set_ = true;
|
||||
}
|
||||
|
||||
OTAResponseTypes ArduinoESP8266OTABackend::write(uint8_t *data, size_t len) {
|
||||
size_t written = Update.write(data, len);
|
||||
if (written == len) {
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
uint8_t error = Update.getError();
|
||||
ESP_LOGE(TAG, "Write error: %d", error);
|
||||
|
||||
return OTA_RESPONSE_ERROR_WRITING_FLASH;
|
||||
}
|
||||
|
||||
OTAResponseTypes ArduinoESP8266OTABackend::end() {
|
||||
// Use strict validation (false) when MD5 is set, lenient validation (true) when no MD5
|
||||
// This matches the behavior of the old web_server OTA implementation
|
||||
bool success = Update.end(!this->md5_set_);
|
||||
|
||||
// On ESP8266, Update.end() might return false even with error code 0
|
||||
// Check the actual error code to determine success
|
||||
uint8_t error = Update.getError();
|
||||
|
||||
if (success || error == UPDATE_ERROR_OK) {
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "End error: %d", error);
|
||||
return OTA_RESPONSE_ERROR_UPDATE_END;
|
||||
}
|
||||
|
||||
void ArduinoESP8266OTABackend::abort() {
|
||||
Update.end();
|
||||
esp8266::preferences_prevent_write(false);
|
||||
}
|
||||
|
||||
} // namespace ota
|
||||
} // namespace esphome
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
#ifdef USE_ARDUINO
|
||||
#ifdef USE_ESP8266
|
||||
#include "ota_backend.h"
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/macros.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ota {
|
||||
|
||||
class ArduinoESP8266OTABackend : public OTABackend {
|
||||
public:
|
||||
OTAResponseTypes begin(size_t image_size) override;
|
||||
void set_update_md5(const char *md5) override;
|
||||
OTAResponseTypes write(uint8_t *data, size_t len) override;
|
||||
OTAResponseTypes end() override;
|
||||
void abort() override;
|
||||
#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 7, 0)
|
||||
bool supports_compression() override { return true; }
|
||||
#else
|
||||
bool supports_compression() override { return false; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool md5_set_{false};
|
||||
};
|
||||
|
||||
} // namespace ota
|
||||
} // namespace esphome
|
||||
|
||||
#endif
|
||||
#endif
|
||||
356
esphome/components/ota/ota_backend_esp8266.cpp
Normal file
356
esphome/components/ota/ota_backend_esp8266.cpp
Normal file
@@ -0,0 +1,356 @@
|
||||
#ifdef USE_ESP8266
|
||||
#include "ota_backend_esp8266.h"
|
||||
#include "ota_backend.h"
|
||||
|
||||
#include "esphome/components/esp8266/preferences.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include <Esp.h>
|
||||
#include <esp8266_peri.h>
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
extern "C" {
|
||||
#include <c_types.h>
|
||||
#include <eboot_command.h>
|
||||
#include <flash_hal.h>
|
||||
#include <spi_flash.h>
|
||||
#include <user_interface.h>
|
||||
}
|
||||
|
||||
// Note: FLASH_SECTOR_SIZE (0x1000) is already defined in spi_flash_geometry.h
|
||||
|
||||
// Flash header offsets
|
||||
static constexpr uint8_t FLASH_MODE_OFFSET = 2;
|
||||
|
||||
// Firmware magic bytes
|
||||
static constexpr uint8_t FIRMWARE_MAGIC = 0xE9;
|
||||
static constexpr uint8_t GZIP_MAGIC_1 = 0x1F;
|
||||
static constexpr uint8_t GZIP_MAGIC_2 = 0x8B;
|
||||
|
||||
// ESP8266 flash memory base address (memory-mapped flash starts here)
|
||||
static constexpr uint32_t FLASH_BASE_ADDRESS = 0x40200000;
|
||||
|
||||
// Boot mode extraction from GPI register (bits 16-19 contain boot mode)
|
||||
static constexpr int BOOT_MODE_SHIFT = 16;
|
||||
static constexpr int BOOT_MODE_MASK = 0xf;
|
||||
|
||||
// Boot mode indicating UART download mode (OTA not possible)
|
||||
static constexpr int BOOT_MODE_UART_DOWNLOAD = 1;
|
||||
|
||||
// Minimum buffer size when memory is constrained
|
||||
static constexpr size_t MIN_BUFFER_SIZE = 256;
|
||||
|
||||
namespace esphome::ota {
|
||||
|
||||
static const char *const TAG = "ota.esp8266";
|
||||
|
||||
std::unique_ptr<ota::OTABackend> make_ota_backend() { return make_unique<ota::ESP8266OTABackend>(); }
|
||||
|
||||
OTAResponseTypes ESP8266OTABackend::begin(size_t image_size) {
|
||||
// Handle UPDATE_SIZE_UNKNOWN (0) by calculating available space
|
||||
if (image_size == 0) {
|
||||
// Round down to sector boundary: subtract one sector, then mask to sector alignment
|
||||
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
|
||||
image_size = (ESP.getFreeSketchSpace() - FLASH_SECTOR_SIZE) & ~(FLASH_SECTOR_SIZE - 1);
|
||||
}
|
||||
|
||||
// Check boot mode - if boot mode is UART download mode,
|
||||
// we will not be able to reset into normal mode once update is done
|
||||
int boot_mode = (GPI >> BOOT_MODE_SHIFT) & BOOT_MODE_MASK;
|
||||
if (boot_mode == BOOT_MODE_UART_DOWNLOAD) {
|
||||
return OTA_RESPONSE_ERROR_INVALID_BOOTSTRAPPING;
|
||||
}
|
||||
|
||||
// Check flash configuration - real size must be >= configured size
|
||||
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
|
||||
if (!ESP.checkFlashConfig(false)) {
|
||||
return OTA_RESPONSE_ERROR_WRONG_CURRENT_FLASH_CONFIG;
|
||||
}
|
||||
|
||||
// Get current sketch size
|
||||
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
|
||||
uint32_t sketch_size = ESP.getSketchSize();
|
||||
|
||||
// Size of current sketch rounded to sector boundary
|
||||
uint32_t current_sketch_size = (sketch_size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
|
||||
|
||||
// Size of update rounded to sector boundary
|
||||
uint32_t rounded_size = (image_size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
|
||||
|
||||
// End of available space for sketch and update (start of filesystem)
|
||||
uint32_t update_end_address = FS_start - FLASH_BASE_ADDRESS;
|
||||
|
||||
// Calculate start address for the update (write from end backwards)
|
||||
this->start_address_ = (update_end_address > rounded_size) ? (update_end_address - rounded_size) : 0;
|
||||
|
||||
// Check if there's enough space for both current sketch and update
|
||||
if (this->start_address_ < current_sketch_size) {
|
||||
return OTA_RESPONSE_ERROR_ESP8266_NOT_ENOUGH_SPACE;
|
||||
}
|
||||
|
||||
// Allocate buffer for sector writes (use smaller buffer if memory constrained)
|
||||
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
|
||||
this->buffer_size_ = (ESP.getFreeHeap() > 2 * FLASH_SECTOR_SIZE) ? FLASH_SECTOR_SIZE : MIN_BUFFER_SIZE;
|
||||
|
||||
// ESP8266's umm_malloc guarantees 4-byte aligned allocations, which is required
|
||||
// for spi_flash_write(). This is the same pattern used by Arduino's Updater class.
|
||||
this->buffer_ = make_unique<uint8_t[]>(this->buffer_size_);
|
||||
if (!this->buffer_) {
|
||||
return OTA_RESPONSE_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
this->current_address_ = this->start_address_;
|
||||
this->image_size_ = image_size;
|
||||
this->buffer_len_ = 0;
|
||||
this->md5_set_ = false;
|
||||
|
||||
// Disable WiFi sleep during update
|
||||
wifi_set_sleep_type(NONE_SLEEP_T);
|
||||
|
||||
// Prevent preference writes during update
|
||||
esp8266::preferences_prevent_write(true);
|
||||
|
||||
// Initialize MD5 computation
|
||||
this->md5_.init();
|
||||
|
||||
ESP_LOGD(TAG, "OTA begin: start=0x%08" PRIX32 ", size=%zu", this->start_address_, image_size);
|
||||
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
void ESP8266OTABackend::set_update_md5(const char *md5) {
|
||||
// Parse hex string to bytes
|
||||
if (parse_hex(md5, this->expected_md5_, 16)) {
|
||||
this->md5_set_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
OTAResponseTypes ESP8266OTABackend::write(uint8_t *data, size_t len) {
|
||||
if (!this->buffer_) {
|
||||
return OTA_RESPONSE_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
size_t written = 0;
|
||||
while (written < len) {
|
||||
// Calculate how much we can buffer
|
||||
size_t to_buffer = std::min(len - written, this->buffer_size_ - this->buffer_len_);
|
||||
memcpy(this->buffer_.get() + this->buffer_len_, data + written, to_buffer);
|
||||
this->buffer_len_ += to_buffer;
|
||||
written += to_buffer;
|
||||
|
||||
// If buffer is full, write to flash
|
||||
if (this->buffer_len_ == this->buffer_size_ && !this->write_buffer_()) {
|
||||
return OTA_RESPONSE_ERROR_WRITING_FLASH;
|
||||
}
|
||||
}
|
||||
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
bool ESP8266OTABackend::erase_sector_if_needed_() {
|
||||
if ((this->current_address_ % FLASH_SECTOR_SIZE) != 0) {
|
||||
return true; // Not at sector boundary
|
||||
}
|
||||
|
||||
App.feed_wdt();
|
||||
if (spi_flash_erase_sector(this->current_address_ / FLASH_SECTOR_SIZE) != SPI_FLASH_RESULT_OK) {
|
||||
ESP_LOGE(TAG, "Flash erase failed at 0x%08" PRIX32, this->current_address_);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ESP8266OTABackend::flash_write_() {
|
||||
App.feed_wdt();
|
||||
if (spi_flash_write(this->current_address_, reinterpret_cast<uint32_t *>(this->buffer_.get()), this->buffer_len_) !=
|
||||
SPI_FLASH_RESULT_OK) {
|
||||
ESP_LOGE(TAG, "Flash write failed at 0x%08" PRIX32, this->current_address_);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ESP8266OTABackend::write_buffer_() {
|
||||
if (this->buffer_len_ == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this->erase_sector_if_needed_()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Patch flash mode in first sector if needed
|
||||
// This is analogous to what esptool.py does when it receives a --flash_mode argument
|
||||
bool is_first_sector = (this->current_address_ == this->start_address_);
|
||||
uint8_t original_flash_mode = 0;
|
||||
bool patched_flash_mode = false;
|
||||
|
||||
// Only patch if we have enough bytes to access flash mode offset and it's not GZIP
|
||||
if (is_first_sector && this->buffer_len_ > FLASH_MODE_OFFSET && this->buffer_[0] != GZIP_MAGIC_1) {
|
||||
// Not GZIP compressed - check and patch flash mode
|
||||
uint8_t current_flash_mode = this->get_flash_chip_mode_();
|
||||
uint8_t buffer_flash_mode = this->buffer_[FLASH_MODE_OFFSET];
|
||||
|
||||
if (buffer_flash_mode != current_flash_mode) {
|
||||
original_flash_mode = buffer_flash_mode;
|
||||
this->buffer_[FLASH_MODE_OFFSET] = current_flash_mode;
|
||||
patched_flash_mode = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->flash_write_()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Restore original flash mode for MD5 calculation
|
||||
if (patched_flash_mode) {
|
||||
this->buffer_[FLASH_MODE_OFFSET] = original_flash_mode;
|
||||
}
|
||||
|
||||
// Update MD5 with original (unpatched) data
|
||||
this->md5_.add(this->buffer_.get(), this->buffer_len_);
|
||||
|
||||
this->current_address_ += this->buffer_len_;
|
||||
this->buffer_len_ = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ESP8266OTABackend::write_buffer_final_() {
|
||||
// Similar to write_buffer_(), but without flash mode patching or MD5 update (for final padded write)
|
||||
if (this->buffer_len_ == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this->erase_sector_if_needed_() || !this->flash_write_()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->current_address_ += this->buffer_len_;
|
||||
this->buffer_len_ = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
OTAResponseTypes ESP8266OTABackend::end() {
|
||||
// Write any remaining buffered data
|
||||
if (this->buffer_len_ > 0) {
|
||||
// Add actual data to MD5 before padding
|
||||
this->md5_.add(this->buffer_.get(), this->buffer_len_);
|
||||
|
||||
// Pad to 4-byte alignment for flash write
|
||||
while (this->buffer_len_ % 4 != 0) {
|
||||
this->buffer_[this->buffer_len_++] = 0xFF;
|
||||
}
|
||||
if (!this->write_buffer_final_()) {
|
||||
this->abort();
|
||||
return OTA_RESPONSE_ERROR_WRITING_FLASH;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate actual bytes written
|
||||
size_t actual_size = this->current_address_ - this->start_address_;
|
||||
|
||||
// Check if any data was written
|
||||
if (actual_size == 0) {
|
||||
ESP_LOGE(TAG, "No data written");
|
||||
this->abort();
|
||||
return OTA_RESPONSE_ERROR_UPDATE_END;
|
||||
}
|
||||
|
||||
// Verify MD5 if set (strict mode), otherwise use lenient mode
|
||||
// In lenient mode (no MD5), we accept whatever was written
|
||||
if (this->md5_set_) {
|
||||
this->md5_.calculate();
|
||||
if (!this->md5_.equals_bytes(this->expected_md5_)) {
|
||||
ESP_LOGE(TAG, "MD5 mismatch");
|
||||
this->abort();
|
||||
return OTA_RESPONSE_ERROR_MD5_MISMATCH;
|
||||
}
|
||||
} else {
|
||||
// Lenient mode: adjust size to what was actually written
|
||||
// This matches Arduino's Update.end(true) behavior
|
||||
this->image_size_ = actual_size;
|
||||
}
|
||||
|
||||
// Verify firmware header
|
||||
if (!this->verify_end_()) {
|
||||
this->abort();
|
||||
return OTA_RESPONSE_ERROR_UPDATE_END;
|
||||
}
|
||||
|
||||
// Write eboot command to copy firmware on next boot
|
||||
eboot_command ebcmd;
|
||||
ebcmd.action = ACTION_COPY_RAW;
|
||||
ebcmd.args[0] = this->start_address_;
|
||||
ebcmd.args[1] = 0x00000; // Destination: start of flash
|
||||
ebcmd.args[2] = this->image_size_;
|
||||
eboot_command_write(&ebcmd);
|
||||
|
||||
ESP_LOGI(TAG, "OTA update staged: 0x%08" PRIX32 " -> 0x00000, size=%zu", this->start_address_, this->image_size_);
|
||||
|
||||
// Clean up
|
||||
this->buffer_.reset();
|
||||
esp8266::preferences_prevent_write(false);
|
||||
|
||||
return OTA_RESPONSE_OK;
|
||||
}
|
||||
|
||||
void ESP8266OTABackend::abort() {
|
||||
this->buffer_.reset();
|
||||
this->buffer_len_ = 0;
|
||||
this->image_size_ = 0;
|
||||
esp8266::preferences_prevent_write(false);
|
||||
}
|
||||
|
||||
bool ESP8266OTABackend::verify_end_() {
|
||||
uint32_t buf;
|
||||
if (spi_flash_read(this->start_address_, &buf, 4) != SPI_FLASH_RESULT_OK) {
|
||||
ESP_LOGE(TAG, "Failed to read firmware header");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *bytes = reinterpret_cast<uint8_t *>(&buf);
|
||||
|
||||
// Check for GZIP (compressed firmware)
|
||||
if (bytes[0] == GZIP_MAGIC_1 && bytes[1] == GZIP_MAGIC_2) {
|
||||
// GZIP compressed - can't verify further
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check firmware magic byte
|
||||
if (bytes[0] != FIRMWARE_MAGIC) {
|
||||
ESP_LOGE(TAG, "Invalid firmware magic: 0x%02X (expected 0x%02X)", bytes[0], FIRMWARE_MAGIC);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !FLASH_MAP_SUPPORT
|
||||
// Check if new firmware's flash size fits (only when auto-detection is disabled)
|
||||
// With FLASH_MAP_SUPPORT (modern cores), flash size is auto-detected from chip
|
||||
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
|
||||
uint32_t bin_flash_size = ESP.magicFlashChipSize((bytes[3] & 0xf0) >> 4);
|
||||
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
|
||||
if (bin_flash_size > ESP.getFlashChipRealSize()) {
|
||||
ESP_LOGE(TAG, "Firmware flash size (%" PRIu32 ") exceeds chip size (%" PRIu32 ")", bin_flash_size,
|
||||
ESP.getFlashChipRealSize());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t ESP8266OTABackend::get_flash_chip_mode_() {
|
||||
uint32_t data;
|
||||
if (spi_flash_read(0x0000, &data, 4) != SPI_FLASH_RESULT_OK) {
|
||||
return 0; // Default to QIO
|
||||
}
|
||||
return (reinterpret_cast<uint8_t *>(&data))[FLASH_MODE_OFFSET];
|
||||
}
|
||||
|
||||
} // namespace esphome::ota
|
||||
#endif // USE_ESP8266
|
||||
58
esphome/components/ota/ota_backend_esp8266.h
Normal file
58
esphome/components/ota/ota_backend_esp8266.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
#ifdef USE_ESP8266
|
||||
#include "ota_backend.h"
|
||||
|
||||
#include "esphome/components/md5/md5.h"
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace esphome::ota {
|
||||
|
||||
/// OTA backend for ESP8266 using native SDK functions.
|
||||
/// This implementation bypasses the Arduino Updater library to save ~228 bytes of RAM
|
||||
/// by not having a global Update object in .bss.
|
||||
class ESP8266OTABackend : public OTABackend {
|
||||
public:
|
||||
OTAResponseTypes begin(size_t image_size) override;
|
||||
void set_update_md5(const char *md5) override;
|
||||
OTAResponseTypes write(uint8_t *data, size_t len) override;
|
||||
OTAResponseTypes end() override;
|
||||
void abort() override;
|
||||
// Compression supported in all ESP8266 Arduino versions ESPHome supports (>= 2.7.0)
|
||||
bool supports_compression() override { return true; }
|
||||
|
||||
protected:
|
||||
/// Erase flash sector if current address is at sector boundary
|
||||
bool erase_sector_if_needed_();
|
||||
|
||||
/// Write buffer to flash (does not update address or clear buffer)
|
||||
bool flash_write_();
|
||||
|
||||
/// Write buffered data to flash and update MD5
|
||||
bool write_buffer_();
|
||||
|
||||
/// Write buffered data to flash without MD5 update (for final padded write)
|
||||
bool write_buffer_final_();
|
||||
|
||||
/// Verify the firmware header is valid
|
||||
bool verify_end_();
|
||||
|
||||
/// Get current flash chip mode from flash header
|
||||
uint8_t get_flash_chip_mode_();
|
||||
|
||||
std::unique_ptr<uint8_t[]> buffer_;
|
||||
size_t buffer_size_{0};
|
||||
size_t buffer_len_{0};
|
||||
|
||||
uint32_t start_address_{0};
|
||||
uint32_t current_address_{0};
|
||||
size_t image_size_{0};
|
||||
|
||||
md5::MD5Digest md5_{};
|
||||
uint8_t expected_md5_[16]; // Fixed-size buffer for 128-bit (16-byte) MD5 digest
|
||||
bool md5_set_{false};
|
||||
};
|
||||
|
||||
} // namespace esphome::ota
|
||||
#endif // USE_ESP8266
|
||||
@@ -162,14 +162,14 @@ void PIDClimate::start_autotune(std::unique_ptr<PIDAutotuner> &&autotune) {
|
||||
float min_value = this->supports_cool_() ? -1.0f : 0.0f;
|
||||
float max_value = this->supports_heat_() ? 1.0f : 0.0f;
|
||||
this->autotuner_->config(min_value, max_value);
|
||||
this->autotuner_->set_autotuner_id(this->get_object_id());
|
||||
this->autotuner_->set_autotuner_id(this->get_name());
|
||||
|
||||
ESP_LOGI(TAG,
|
||||
"%s: Autotune has started. This can take a long time depending on the "
|
||||
"responsiveness of your system. Your system "
|
||||
"output will be altered to deliberately oscillate above and below the setpoint multiple times. "
|
||||
"Until your sensor provides a reading, the autotuner may display \'nan\'",
|
||||
this->get_object_id().c_str());
|
||||
this->get_name().c_str());
|
||||
|
||||
this->set_interval("autotune-progress", 10000, [this]() {
|
||||
if (this->autotuner_ != nullptr && !this->autotuner_->is_finished())
|
||||
@@ -178,7 +178,7 @@ void PIDClimate::start_autotune(std::unique_ptr<PIDAutotuner> &&autotune) {
|
||||
|
||||
if (mode != climate::CLIMATE_MODE_HEAT_COOL) {
|
||||
ESP_LOGW(TAG, "%s: !!! For PID autotuner you need to set AUTO (also called heat/cool) mode!",
|
||||
this->get_object_id().c_str());
|
||||
this->get_name().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,11 @@ void PrometheusHandler::handleRequest(AsyncWebServerRequest *req) {
|
||||
|
||||
std::string PrometheusHandler::relabel_id_(EntityBase *obj) {
|
||||
auto item = relabel_map_id_.find(obj);
|
||||
return item == relabel_map_id_.end() ? obj->get_object_id() : item->second;
|
||||
if (item != relabel_map_id_.end()) {
|
||||
return item->second;
|
||||
}
|
||||
char object_id_buf[OBJECT_ID_MAX_LEN];
|
||||
return obj->get_object_id_to(object_id_buf).str();
|
||||
}
|
||||
|
||||
std::string PrometheusHandler::relabel_name_(EntityBase *obj) {
|
||||
|
||||
@@ -60,13 +60,13 @@ class PVVXDisplay : public ble_client::BLEClientNode, public PollingComponent {
|
||||
* Valid values are from -99.5 to 1999.5. Smaller values are displayed as Lo, higher as Hi.
|
||||
* It will printed as it fits in the screen.
|
||||
*/
|
||||
void print_bignum(float bignum) { this->bignum_ = bignum * 10; }
|
||||
void print_bignum(float bignum) { this->bignum_ = static_cast<int16_t>(bignum * 10); }
|
||||
/**
|
||||
* Print the small number
|
||||
*
|
||||
* Valid values are from -9 to 99. Smaller values are displayed as Lo, higher as Hi.
|
||||
*/
|
||||
void print_smallnum(float smallnum) { this->smallnum_ = smallnum; }
|
||||
void print_smallnum(float smallnum) { this->smallnum_ = static_cast<int16_t>(smallnum); }
|
||||
/**
|
||||
* Print a happy face
|
||||
*
|
||||
@@ -107,8 +107,8 @@ class PVVXDisplay : public ble_client::BLEClientNode, public PollingComponent {
|
||||
bool auto_clear_enabled_{true};
|
||||
uint32_t disconnect_delay_ms_ = 5000;
|
||||
uint16_t validity_period_ = 300;
|
||||
uint16_t bignum_ = 0;
|
||||
uint16_t smallnum_ = 0;
|
||||
int16_t bignum_ = 0;
|
||||
int16_t smallnum_ = 0;
|
||||
uint8_t cfg_ = 0;
|
||||
|
||||
void setcfgbit_(uint8_t bit, bool value);
|
||||
|
||||
@@ -154,7 +154,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
upper=True,
|
||||
key=CONF_MODEL,
|
||||
),
|
||||
cv.only_with_esp_idf,
|
||||
cv.only_on_esp32,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if defined(USE_ESP_IDF) && defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#if defined(USE_ESP32) && defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#include "qspi_dbi.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#if defined(USE_ESP_IDF) && defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#if defined(USE_ESP32) && defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#include "esphome/components/spi/spi.h"
|
||||
#include "esphome/components/display/display.h"
|
||||
#include "esphome/components/display/display_buffer.h"
|
||||
|
||||
@@ -122,7 +122,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
)
|
||||
),
|
||||
only_on_variant(supported=[VARIANT_ESP32S3]),
|
||||
cv.only_with_esp_idf,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -315,7 +315,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(CONF_ON_VOLUME): automation.validate_automation(single=True),
|
||||
}
|
||||
),
|
||||
cv.only_with_esp_idf,
|
||||
cv.only_on_esp32,
|
||||
_validate_repeated_speaker,
|
||||
_request_high_performance_networking,
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "audio_pipeline.h"
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "esphome/components/audio/audio.h"
|
||||
#include "esphome/components/audio/audio_reader.h"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "speaker_media_player.h"
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "esphome/components/audio/audio.h"
|
||||
#include "esphome/core/automation.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "speaker_media_player.h"
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_ESP_IDF
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "audio_pipeline.h"
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ def spi_mode_schema(mode):
|
||||
if mode == TYPE_SINGLE:
|
||||
return SPI_SINGLE_SCHEMA
|
||||
pin_count = 4 if mode == TYPE_QUAD else 8
|
||||
onlys = [cv.only_on([PLATFORM_ESP32]), cv.only_with_esp_idf]
|
||||
onlys = [cv.only_on([PLATFORM_ESP32])]
|
||||
if pin_count == 8:
|
||||
onlys.append(
|
||||
only_on_variant(
|
||||
@@ -399,7 +399,7 @@ def spi_device_schema(
|
||||
cv.Optional(CONF_SPI_MODE, default=default_mode): cv.enum(
|
||||
SPI_MODE_OPTIONS, upper=True
|
||||
),
|
||||
cv.Optional(CONF_RELEASE_DEVICE): cv.All(cv.boolean, cv.only_with_esp_idf),
|
||||
cv.Optional(CONF_RELEASE_DEVICE): cv.All(cv.boolean, cv.only_on_esp32),
|
||||
}
|
||||
if cs_pin_required:
|
||||
schema[cv.Required(CONF_CS_PIN)] = pins.gpio_output_pin_schema
|
||||
|
||||
@@ -161,8 +161,8 @@ CONFIG_SCHEMA = cv.All(
|
||||
}
|
||||
).extend(spi.spi_device_schema(cs_pin_required=False, default_data_rate=1e6))
|
||||
),
|
||||
cv.only_on_esp32,
|
||||
only_on_variant(supported=[VARIANT_ESP32S3]),
|
||||
cv.only_with_esp_idf,
|
||||
)
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema(
|
||||
|
||||
@@ -527,7 +527,9 @@ void SX126x::dump_config() {
|
||||
this->spreading_factor_, cr, this->preamble_size_);
|
||||
}
|
||||
if (!this->sync_value_.empty()) {
|
||||
ESP_LOGCONFIG(TAG, " Sync Value: 0x%s", format_hex(this->sync_value_).c_str());
|
||||
char hex_buf[17]; // 8 bytes max = 16 hex chars + null
|
||||
ESP_LOGCONFIG(TAG, " Sync Value: 0x%s",
|
||||
format_hex_to(hex_buf, this->sync_value_.data(), this->sync_value_.size()));
|
||||
}
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, "Configuring SX126x failed");
|
||||
|
||||
@@ -476,7 +476,9 @@ void SX127x::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " Payload Length: %" PRIu32, this->payload_length_);
|
||||
}
|
||||
if (!this->sync_value_.empty()) {
|
||||
ESP_LOGCONFIG(TAG, " Sync Value: 0x%s", format_hex(this->sync_value_).c_str());
|
||||
char hex_buf[17]; // 8 bytes max = 16 hex chars + null
|
||||
ESP_LOGCONFIG(TAG, " Sync Value: 0x%s",
|
||||
format_hex_to(hex_buf, this->sync_value_.data(), this->sync_value_.size()));
|
||||
}
|
||||
if (this->preamble_size_ > 0 || this->preamble_detect_ > 0) {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
|
||||
@@ -78,8 +78,8 @@ void TextSensor::add_on_raw_state_callback(std::function<void(const std::string
|
||||
this->raw_callback_.add(std::move(callback));
|
||||
}
|
||||
|
||||
std::string TextSensor::get_state() const { return this->state; }
|
||||
std::string TextSensor::get_raw_state() const {
|
||||
const std::string &TextSensor::get_state() const { return this->state; }
|
||||
const std::string &TextSensor::get_raw_state() const {
|
||||
// Suppress deprecation warning - get_raw_state() is the replacement API
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
@@ -37,9 +37,9 @@ class TextSensor : public EntityBase, public EntityBase_DeviceClass {
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
/// Getter-syntax for .state.
|
||||
std::string get_state() const;
|
||||
const std::string &get_state() const;
|
||||
/// Getter-syntax for .raw_state
|
||||
std::string get_raw_state() const;
|
||||
const std::string &get_raw_state() const;
|
||||
|
||||
void publish_state(const std::string &state);
|
||||
|
||||
|
||||
@@ -130,7 +130,8 @@ void UDPComponent::dump_config() {
|
||||
for (const auto &address : this->addresses_)
|
||||
ESP_LOGCONFIG(TAG, " Address: %s", address.c_str());
|
||||
if (this->listen_address_.has_value()) {
|
||||
ESP_LOGCONFIG(TAG, " Listen address: %s", this->listen_address_.value().str().c_str());
|
||||
char addr_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
ESP_LOGCONFIG(TAG, " Listen address: %s", this->listen_address_.value().str_to(addr_buf));
|
||||
}
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Broadcasting: %s\n"
|
||||
|
||||
@@ -53,8 +53,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(CONF_DEVICES): cv.ensure_list(usb_device_schema()),
|
||||
}
|
||||
),
|
||||
cv.only_with_esp_idf,
|
||||
only_on_variant(supported=[VARIANT_ESP32S2, VARIANT_ESP32S3, VARIANT_ESP32P4]),
|
||||
only_on_variant(supported=[VARIANT_ESP32P4, VARIANT_ESP32S2, VARIANT_ESP32S3]),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -947,7 +947,7 @@ void VoiceAssistant::on_set_configuration(const std::vector<std::string> &active
|
||||
}
|
||||
|
||||
// Enable only active wake words
|
||||
for (auto ww_id : active_wake_words) {
|
||||
for (const auto &ww_id : active_wake_words) {
|
||||
for (auto &model : this->micro_wake_word_->get_wake_words()) {
|
||||
if (model->get_id() == ww_id) {
|
||||
model->enable();
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
#include "web_server.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace web_server {
|
||||
namespace esphome::web_server {
|
||||
|
||||
#ifdef USE_ESP32
|
||||
ListEntitiesIterator::ListEntitiesIterator(const WebServer *ws, AsyncEventSource *es) : web_server_(ws), events_(es) {}
|
||||
@@ -157,6 +156,5 @@ bool ListEntitiesIterator::on_update(update::UpdateEntity *obj) {
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace web_server
|
||||
} // namespace esphome
|
||||
} // namespace esphome::web_server
|
||||
#endif
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
#ifdef USE_WEBSERVER
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/component_iterator.h"
|
||||
namespace esphome {
|
||||
namespace esphome::web_server_idf {
|
||||
#ifdef USE_ESP32
|
||||
namespace web_server_idf {
|
||||
class AsyncEventSource;
|
||||
}
|
||||
#endif
|
||||
namespace web_server {
|
||||
} // namespace esphome::web_server_idf
|
||||
|
||||
namespace esphome::web_server {
|
||||
|
||||
#if !defined(USE_ESP32) && defined(USE_ARDUINO)
|
||||
class DeferredUpdateEventSource;
|
||||
@@ -99,6 +99,5 @@ class ListEntitiesIterator : public ComponentIterator {
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace web_server
|
||||
} // namespace esphome
|
||||
} // namespace esphome::web_server
|
||||
#endif
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef USE_ARDUINO
|
||||
#ifdef USE_ESP8266
|
||||
#include <Updater.h>
|
||||
#elif defined(USE_ESP32) || defined(USE_LIBRETINY)
|
||||
#if defined(USE_LIBRETINY)
|
||||
#include <Update.h>
|
||||
#endif
|
||||
#endif // USE_ARDUINO
|
||||
@@ -23,8 +21,7 @@ using PlatformString = std::string;
|
||||
using PlatformString = String;
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace web_server {
|
||||
namespace esphome::web_server {
|
||||
|
||||
static const char *const TAG = "web_server.ota";
|
||||
|
||||
@@ -121,10 +118,7 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Platf
|
||||
|
||||
// Platform-specific pre-initialization
|
||||
#ifdef USE_ARDUINO
|
||||
#ifdef USE_ESP8266
|
||||
Update.runAsync(true);
|
||||
#endif
|
||||
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
|
||||
#if defined(USE_LIBRETINY)
|
||||
if (Update.isRunning()) {
|
||||
Update.abort();
|
||||
}
|
||||
@@ -236,7 +230,6 @@ void WebServerOTAComponent::setup() {
|
||||
|
||||
void WebServerOTAComponent::dump_config() { ESP_LOGCONFIG(TAG, "Web Server OTA"); }
|
||||
|
||||
} // namespace web_server
|
||||
} // namespace esphome
|
||||
} // namespace esphome::web_server
|
||||
|
||||
#endif // USE_WEBSERVER_OTA
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
#include "esphome/components/web_server_base/web_server_base.h"
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace web_server {
|
||||
namespace esphome::web_server {
|
||||
|
||||
class WebServerOTAComponent : public ota::OTAComponent {
|
||||
public:
|
||||
@@ -20,7 +19,6 @@ class WebServerOTAComponent : public ota::OTAComponent {
|
||||
friend class OTARequestHandler;
|
||||
};
|
||||
|
||||
} // namespace web_server
|
||||
} // namespace esphome
|
||||
} // namespace esphome::web_server
|
||||
|
||||
#endif // USE_WEBSERVER_OTA
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace web_server {
|
||||
namespace esphome::web_server {
|
||||
|
||||
const uint8_t INDEX_GZ[] PROGMEM = {
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcd, 0x7d, 0xdb, 0x72, 0xdb, 0xc6, 0xb6, 0xe0, 0xf3,
|
||||
@@ -644,8 +643,7 @@ const uint8_t INDEX_GZ[] PROGMEM = {
|
||||
0x2b, 0x4d, 0x17, 0xb8, 0x87, 0x4c, 0xe9, 0x50, 0x19, 0x14, 0xba, 0x92, 0xde, 0x0a, 0xea, 0x97, 0xce, 0xad, 0x80,
|
||||
0x4f, 0xc7, 0xf5, 0xfe, 0x1f, 0xe7, 0xe0, 0x1c, 0x12, 0xcf, 0x89, 0x00, 0x00};
|
||||
|
||||
} // namespace web_server
|
||||
} // namespace esphome
|
||||
} // namespace esphome::web_server
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user