mirror of
https://github.com/esphome/esphome.git
synced 2026-02-20 16:35:37 -07:00
Merge branch 'dev' into api_avoid_copies
This commit is contained in:
@@ -2425,7 +2425,7 @@ message ZWaveProxyFrame {
|
||||
option (ifdef) = "USE_ZWAVE_PROXY";
|
||||
option (no_delay) = true;
|
||||
|
||||
bytes data = 1 [(pointer_to_buffer) = true];
|
||||
bytes data = 1;
|
||||
}
|
||||
|
||||
enum ZWaveProxyRequestType {
|
||||
@@ -2439,5 +2439,5 @@ message ZWaveProxyRequest {
|
||||
option (ifdef) = "USE_ZWAVE_PROXY";
|
||||
|
||||
ZWaveProxyRequestType type = 1;
|
||||
bytes data = 2 [(pointer_to_buffer) = true];
|
||||
bytes data = 2;
|
||||
}
|
||||
|
||||
@@ -1046,7 +1046,7 @@ class SubscribeLogsRequest final : public ProtoDecodableMessage {
|
||||
class SubscribeLogsResponse final : public ProtoMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 29;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 11;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 21;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "subscribe_logs_response"; }
|
||||
#endif
|
||||
@@ -1069,7 +1069,7 @@ class SubscribeLogsResponse final : public ProtoMessage {
|
||||
class NoiseEncryptionSetKeyRequest final : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 124;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 9;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 19;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "noise_encryption_set_key_request"; }
|
||||
#endif
|
||||
@@ -1161,7 +1161,7 @@ class HomeassistantActionRequest final : public ProtoMessage {
|
||||
class HomeassistantActionResponse final : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 130;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 24;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 34;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "homeassistant_action_response"; }
|
||||
#endif
|
||||
@@ -1388,7 +1388,7 @@ class ListEntitiesCameraResponse final : public InfoResponseProtoMessage {
|
||||
class CameraImageResponse final : public StateResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 44;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 20;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 30;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "camera_image_response"; }
|
||||
#endif
|
||||
@@ -2123,7 +2123,7 @@ class BluetoothGATTReadRequest final : public ProtoDecodableMessage {
|
||||
class BluetoothGATTReadResponse final : public ProtoMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 74;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 17;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 27;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "bluetooth_gatt_read_response"; }
|
||||
#endif
|
||||
@@ -2146,7 +2146,7 @@ class BluetoothGATTReadResponse final : public ProtoMessage {
|
||||
class BluetoothGATTWriteRequest final : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 75;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 19;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 29;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "bluetooth_gatt_write_request"; }
|
||||
#endif
|
||||
@@ -2182,7 +2182,7 @@ class BluetoothGATTReadDescriptorRequest final : public ProtoDecodableMessage {
|
||||
class BluetoothGATTWriteDescriptorRequest final : public ProtoDecodableMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 77;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 17;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 27;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "bluetooth_gatt_write_descriptor_request"; }
|
||||
#endif
|
||||
@@ -2218,7 +2218,7 @@ class BluetoothGATTNotifyRequest final : public ProtoDecodableMessage {
|
||||
class BluetoothGATTNotifyDataResponse final : public ProtoMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 79;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 17;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 27;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "bluetooth_gatt_notify_data_response"; }
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@ import esphome.codegen as cg
|
||||
from esphome.components import binary_sensor, esp32_ble, improv_base, output
|
||||
from esphome.components.esp32_ble import BTLoggers
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_ON_STATE, CONF_TRIGGER_ID
|
||||
from esphome.const import CONF_ID, CONF_ON_START, CONF_ON_STATE, CONF_TRIGGER_ID
|
||||
|
||||
AUTO_LOAD = ["esp32_ble_server", "improv_base"]
|
||||
CODEOWNERS = ["@jesserockz"]
|
||||
@@ -15,7 +15,6 @@ CONF_BLE_SERVER_ID = "ble_server_id"
|
||||
CONF_IDENTIFY_DURATION = "identify_duration"
|
||||
CONF_ON_PROVISIONED = "on_provisioned"
|
||||
CONF_ON_PROVISIONING = "on_provisioning"
|
||||
CONF_ON_START = "on_start"
|
||||
CONF_ON_STOP = "on_stop"
|
||||
CONF_STATUS_INDICATOR = "status_indicator"
|
||||
CONF_WIFI_TIMEOUT = "wifi_timeout"
|
||||
|
||||
@@ -28,6 +28,7 @@ from .const import (
|
||||
KEY_ESP8266,
|
||||
KEY_FLASH_SIZE,
|
||||
KEY_PIN_INITIAL_STATES,
|
||||
KEY_WAVEFORM_REQUIRED,
|
||||
esp8266_ns,
|
||||
)
|
||||
from .gpio import PinInitialState, add_pin_initial_states_array
|
||||
@@ -192,7 +193,12 @@ async def to_code(config):
|
||||
|
||||
cg.add_platformio_option(
|
||||
"extra_scripts",
|
||||
["pre:testing_mode.py", "pre:exclude_updater.py", "post:post_build.py"],
|
||||
[
|
||||
"pre:testing_mode.py",
|
||||
"pre:exclude_updater.py",
|
||||
"pre:exclude_waveform.py",
|
||||
"post:post_build.py",
|
||||
],
|
||||
)
|
||||
|
||||
conf = config[CONF_FRAMEWORK]
|
||||
@@ -264,10 +270,24 @@ async def to_code(config):
|
||||
cg.add_platformio_option("board_build.ldscript", ld_script)
|
||||
|
||||
CORE.add_job(add_pin_initial_states_array)
|
||||
CORE.add_job(finalize_waveform_config)
|
||||
|
||||
|
||||
@coroutine_with_priority(CoroPriority.WORKAROUNDS)
|
||||
async def finalize_waveform_config() -> None:
|
||||
"""Add waveform stubs define if waveform is not required.
|
||||
|
||||
This runs at WORKAROUNDS priority (-999) to ensure all components
|
||||
have had a chance to call require_waveform() first.
|
||||
"""
|
||||
if not CORE.data.get(KEY_ESP8266, {}).get(KEY_WAVEFORM_REQUIRED, False):
|
||||
# No component needs waveform - enable stubs and exclude Arduino waveform code
|
||||
# Use build flag (visible to both C++ code and PlatformIO script)
|
||||
cg.add_build_flag("-DUSE_ESP8266_WAVEFORM_STUBS")
|
||||
|
||||
|
||||
# Called by writer.py
|
||||
def copy_files():
|
||||
def copy_files() -> None:
|
||||
dir = Path(__file__).parent
|
||||
post_build_file = dir / "post_build.py.script"
|
||||
copy_file_if_changed(
|
||||
@@ -284,3 +304,8 @@ def copy_files():
|
||||
exclude_updater_file,
|
||||
CORE.relative_build_path("exclude_updater.py"),
|
||||
)
|
||||
exclude_waveform_file = dir / "exclude_waveform.py.script"
|
||||
copy_file_if_changed(
|
||||
exclude_waveform_file,
|
||||
CORE.relative_build_path("exclude_waveform.py"),
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.core import CORE
|
||||
|
||||
KEY_ESP8266 = "esp8266"
|
||||
KEY_BOARD = "board"
|
||||
@@ -6,6 +7,25 @@ KEY_PIN_INITIAL_STATES = "pin_initial_states"
|
||||
CONF_RESTORE_FROM_FLASH = "restore_from_flash"
|
||||
CONF_EARLY_PIN_INIT = "early_pin_init"
|
||||
KEY_FLASH_SIZE = "flash_size"
|
||||
KEY_WAVEFORM_REQUIRED = "waveform_required"
|
||||
|
||||
# esp8266 namespace is already defined by arduino, manually prefix esphome
|
||||
esp8266_ns = cg.global_ns.namespace("esphome").namespace("esp8266")
|
||||
|
||||
|
||||
def require_waveform() -> None:
|
||||
"""Mark that Arduino waveform/PWM support is required.
|
||||
|
||||
Call this from components that need the Arduino waveform generator
|
||||
(startWaveform, stopWaveform, analogWrite, Tone, Servo).
|
||||
|
||||
If no component calls this, the waveform code is excluded from the build
|
||||
to save ~596 bytes of RAM and 464 bytes of flash.
|
||||
|
||||
Example:
|
||||
from esphome.components.esp8266.const import require_waveform
|
||||
|
||||
async def to_code(config):
|
||||
require_waveform()
|
||||
"""
|
||||
CORE.data.setdefault(KEY_ESP8266, {})[KEY_WAVEFORM_REQUIRED] = True
|
||||
|
||||
50
esphome/components/esp8266/exclude_waveform.py.script
Normal file
50
esphome/components/esp8266/exclude_waveform.py.script
Normal file
@@ -0,0 +1,50 @@
|
||||
# pylint: disable=E0602
|
||||
Import("env") # noqa
|
||||
|
||||
import os
|
||||
|
||||
# Filter out waveform/PWM code from the Arduino core build
|
||||
# This saves ~596 bytes of RAM and 464 bytes of flash by not
|
||||
# instantiating the waveform generator state structures (wvfState + pwmState).
|
||||
#
|
||||
# The waveform code is used by: analogWrite, Tone, Servo, and direct
|
||||
# startWaveform/stopWaveform calls. ESPHome's esp8266_pwm component
|
||||
# calls require_waveform() to keep this code when needed.
|
||||
#
|
||||
# When excluded, we provide stub implementations of stopWaveform() and
|
||||
# _stopPWM() since digitalWrite() calls these unconditionally.
|
||||
|
||||
|
||||
def has_define_flag(env, name):
|
||||
"""Check if a define exists in the build flags."""
|
||||
define_flag = f"-D{name}"
|
||||
# Check BUILD_FLAGS (where ESPHome puts its defines)
|
||||
for flag in env.get("BUILD_FLAGS", []):
|
||||
if flag == define_flag or flag.startswith(f"{define_flag}="):
|
||||
return True
|
||||
# Also check CPPDEFINES list (parsed defines)
|
||||
for define in env.get("CPPDEFINES", []):
|
||||
if isinstance(define, tuple):
|
||||
if define[0] == name:
|
||||
return True
|
||||
elif define == name:
|
||||
return True
|
||||
return False
|
||||
|
||||
# USE_ESP8266_WAVEFORM_STUBS is defined when no component needs waveform
|
||||
if has_define_flag(env, "USE_ESP8266_WAVEFORM_STUBS"):
|
||||
|
||||
def filter_waveform_from_core(env, node):
|
||||
"""Filter callback to exclude waveform files from framework build."""
|
||||
path = node.get_path()
|
||||
filename = os.path.basename(path)
|
||||
if filename in (
|
||||
"core_esp8266_waveform_pwm.cpp",
|
||||
"core_esp8266_waveform_phase.cpp",
|
||||
):
|
||||
print(f"ESPHome: Excluding {filename} from build (waveform not required)")
|
||||
return None
|
||||
return node
|
||||
|
||||
# Apply the filter to framework sources
|
||||
env.AddBuildMiddleware(filter_waveform_from_core, "**/cores/esp8266/*.cpp")
|
||||
34
esphome/components/esp8266/waveform_stubs.cpp
Normal file
34
esphome/components/esp8266/waveform_stubs.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifdef USE_ESP8266_WAVEFORM_STUBS
|
||||
|
||||
// Stub implementations for Arduino waveform/PWM functions.
|
||||
//
|
||||
// When the waveform generator is not needed (no esp8266_pwm component),
|
||||
// we exclude core_esp8266_waveform_pwm.cpp from the build to save ~596 bytes
|
||||
// of RAM and 464 bytes of flash.
|
||||
//
|
||||
// These stubs satisfy calls from the Arduino GPIO code when the real
|
||||
// waveform implementation is excluded. They must be in the global namespace
|
||||
// with C linkage to match the Arduino core function declarations.
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// Empty namespace to satisfy linter - actual stubs must be at global scope
|
||||
namespace esphome::esp8266 {} // namespace esphome::esp8266
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Called by Arduino GPIO code to stop any waveform on a pin
|
||||
int stopWaveform(uint8_t pin) {
|
||||
(void) pin;
|
||||
return 1; // Success (no waveform to stop)
|
||||
}
|
||||
|
||||
// Called by Arduino GPIO code to stop any PWM on a pin
|
||||
bool _stopPWM(uint8_t pin) {
|
||||
(void) pin;
|
||||
return false; // No PWM was running
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // USE_ESP8266_WAVEFORM_STUBS
|
||||
@@ -1,6 +1,7 @@
|
||||
from esphome import automation, pins
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import output
|
||||
from esphome.components.esp8266.const import require_waveform
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_FREQUENCY, CONF_ID, CONF_NUMBER, CONF_PIN
|
||||
|
||||
@@ -34,7 +35,9 @@ CONFIG_SCHEMA = cv.All(
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
async def to_code(config) -> None:
|
||||
require_waveform()
|
||||
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await output.register_output(var, config)
|
||||
|
||||
@@ -11,6 +11,7 @@ from esphome.const import (
|
||||
CONF_ON_CLIENT_DISCONNECTED,
|
||||
CONF_ON_ERROR,
|
||||
CONF_ON_IDLE,
|
||||
CONF_ON_START,
|
||||
CONF_SPEAKER,
|
||||
)
|
||||
|
||||
@@ -24,7 +25,6 @@ CONF_ON_INTENT_END = "on_intent_end"
|
||||
CONF_ON_INTENT_PROGRESS = "on_intent_progress"
|
||||
CONF_ON_INTENT_START = "on_intent_start"
|
||||
CONF_ON_LISTENING = "on_listening"
|
||||
CONF_ON_START = "on_start"
|
||||
CONF_ON_STT_END = "on_stt_end"
|
||||
CONF_ON_STT_VAD_END = "on_stt_vad_end"
|
||||
CONF_ON_STT_VAD_START = "on_stt_vad_start"
|
||||
|
||||
@@ -710,6 +710,7 @@ CONF_ON_RELEASE = "on_release"
|
||||
CONF_ON_RESPONSE = "on_response"
|
||||
CONF_ON_SHUTDOWN = "on_shutdown"
|
||||
CONF_ON_SPEED_SET = "on_speed_set"
|
||||
CONF_ON_START = "on_start"
|
||||
CONF_ON_STATE = "on_state"
|
||||
CONF_ON_SUCCESS = "on_success"
|
||||
CONF_ON_TAG = "on_tag"
|
||||
|
||||
@@ -362,12 +362,12 @@ def create_field_type_info(
|
||||
# Traditional fixed array approach with copy (takes priority)
|
||||
return FixedArrayBytesType(field, fixed_size)
|
||||
|
||||
# For SOURCE_CLIENT only messages (decode but no encode), use pointer
|
||||
# For messages that decode (SOURCE_CLIENT or SOURCE_BOTH), use pointer
|
||||
# for zero-copy access to the receive buffer
|
||||
if needs_decode and not needs_encode:
|
||||
if needs_decode:
|
||||
return PointerToBytesBufferType(field, None)
|
||||
|
||||
# For SOURCE_BOTH/SOURCE_SERVER, explicit annotation is still needed
|
||||
# For SOURCE_SERVER (encode only), explicit annotation is still needed
|
||||
if get_field_opt(field, pb.pointer_to_buffer, False):
|
||||
return PointerToBytesBufferType(field, None)
|
||||
|
||||
|
||||
@@ -552,6 +552,8 @@ def convert_path_to_relative(abspath, current):
|
||||
exclude=[
|
||||
"esphome/components/libretiny/generate_components.py",
|
||||
"esphome/components/web_server/__init__.py",
|
||||
# const.py has absolute import in docstring example for external components
|
||||
"esphome/components/esp8266/const.py",
|
||||
],
|
||||
)
|
||||
def lint_relative_py_import(fname: Path, line, col, content):
|
||||
|
||||
Reference in New Issue
Block a user