mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Merge remote-tracking branch 'upstream/dev' into zwave_proxy
This commit is contained in:
		| @@ -89,6 +89,7 @@ esphome/components/bp5758d/* @Cossid | ||||
| esphome/components/button/* @esphome/core | ||||
| esphome/components/bytebuffer/* @clydebarrow | ||||
| esphome/components/camera/* @DT-art1 @bdraco | ||||
| esphome/components/camera_encoder/* @DT-art1 | ||||
| esphome/components/canbus/* @danielschramm @mvturnho | ||||
| esphome/components/cap1188/* @mreditor97 | ||||
| esphome/components/captive_portal/* @esphome/core | ||||
|   | ||||
| @@ -13,7 +13,7 @@ from esphome.const import ( | ||||
|     CONF_TRIGGER_ID, | ||||
|     CONF_WEB_SERVER, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -345,6 +345,6 @@ async def alarm_control_panel_is_armed_to_code( | ||||
|     return cg.new_Pvariable(condition_id, template_arg, paren) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(alarm_control_panel_ns.using) | ||||
|   | ||||
| @@ -24,7 +24,7 @@ from esphome.const import ( | ||||
|     CONF_TRIGGER_ID, | ||||
|     CONF_VARIABLES, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
|  | ||||
| DOMAIN = "api" | ||||
| DEPENDENCIES = ["network"] | ||||
| @@ -134,7 +134,7 @@ CONFIG_SCHEMA = cv.All( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(40.0) | ||||
| @coroutine_with_priority(CoroPriority.WEB) | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await cg.register_component(var, config) | ||||
|   | ||||
| @@ -1719,6 +1719,7 @@ message BluetoothScannerStateResponse { | ||||
|  | ||||
|   BluetoothScannerState state = 1; | ||||
|   BluetoothScannerMode mode = 2; | ||||
|   BluetoothScannerMode configured_mode = 3; | ||||
| } | ||||
|  | ||||
| message BluetoothScannerSetModeRequest { | ||||
|   | ||||
| @@ -2159,10 +2159,12 @@ void BluetoothDeviceClearCacheResponse::calculate_size(ProtoSize &size) const { | ||||
| void BluetoothScannerStateResponse::encode(ProtoWriteBuffer buffer) const { | ||||
|   buffer.encode_uint32(1, static_cast<uint32_t>(this->state)); | ||||
|   buffer.encode_uint32(2, static_cast<uint32_t>(this->mode)); | ||||
|   buffer.encode_uint32(3, static_cast<uint32_t>(this->configured_mode)); | ||||
| } | ||||
| void BluetoothScannerStateResponse::calculate_size(ProtoSize &size) const { | ||||
|   size.add_uint32(1, static_cast<uint32_t>(this->state)); | ||||
|   size.add_uint32(1, static_cast<uint32_t>(this->mode)); | ||||
|   size.add_uint32(1, static_cast<uint32_t>(this->configured_mode)); | ||||
| } | ||||
| bool BluetoothScannerSetModeRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { | ||||
|   switch (field_id) { | ||||
|   | ||||
| @@ -2217,12 +2217,13 @@ class BluetoothDeviceClearCacheResponse final : public ProtoMessage { | ||||
| class BluetoothScannerStateResponse final : public ProtoMessage { | ||||
|  public: | ||||
|   static constexpr uint8_t MESSAGE_TYPE = 126; | ||||
|   static constexpr uint8_t ESTIMATED_SIZE = 4; | ||||
|   static constexpr uint8_t ESTIMATED_SIZE = 6; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   const char *message_name() const override { return "bluetooth_scanner_state_response"; } | ||||
| #endif | ||||
|   enums::BluetoothScannerState state{}; | ||||
|   enums::BluetoothScannerMode mode{}; | ||||
|   enums::BluetoothScannerMode configured_mode{}; | ||||
|   void encode(ProtoWriteBuffer buffer) const override; | ||||
|   void calculate_size(ProtoSize &size) const override; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   | ||||
| @@ -1707,6 +1707,7 @@ void BluetoothScannerStateResponse::dump_to(std::string &out) const { | ||||
|   MessageDumpHelper helper(out, "BluetoothScannerStateResponse"); | ||||
|   dump_field(out, "state", static_cast<enums::BluetoothScannerState>(this->state)); | ||||
|   dump_field(out, "mode", static_cast<enums::BluetoothScannerMode>(this->mode)); | ||||
|   dump_field(out, "configured_mode", static_cast<enums::BluetoothScannerMode>(this->configured_mode)); | ||||
| } | ||||
| void BluetoothScannerSetModeRequest::dump_to(std::string &out) const { | ||||
|   MessageDumpHelper helper(out, "BluetoothScannerSetModeRequest"); | ||||
|   | ||||
| @@ -8,7 +8,7 @@ from esphome.const import ( | ||||
|     PLATFORM_LN882X, | ||||
|     PLATFORM_RTL87XX, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
|  | ||||
| CODEOWNERS = ["@esphome/core"] | ||||
|  | ||||
| @@ -27,7 +27,7 @@ CONFIG_SCHEMA = cv.All( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(200.0) | ||||
| @coroutine_with_priority(CoroPriority.NETWORK_TRANSPORT) | ||||
| async def to_code(config): | ||||
|     if CORE.is_esp32 or CORE.is_libretiny: | ||||
|         # https://github.com/ESP32Async/AsyncTCP | ||||
|   | ||||
| @@ -2,7 +2,7 @@ from esphome import automation | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID, CONF_MIC_GAIN | ||||
| from esphome.core import coroutine_with_priority | ||||
| from esphome.core import CoroPriority, coroutine_with_priority | ||||
|  | ||||
| CODEOWNERS = ["@kbx81"] | ||||
| IS_PLATFORM_COMPONENT = True | ||||
| @@ -35,7 +35,7 @@ async def audio_adc_set_mic_gain_to_code(config, action_id, template_arg, args): | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_define("USE_AUDIO_ADC") | ||||
|     cg.add_global(audio_adc_ns.using) | ||||
|   | ||||
| @@ -3,7 +3,7 @@ from esphome.automation import maybe_simple_id | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID, CONF_VOLUME | ||||
| from esphome.core import coroutine_with_priority | ||||
| from esphome.core import CoroPriority, coroutine_with_priority | ||||
|  | ||||
| CODEOWNERS = ["@kbx81"] | ||||
| IS_PLATFORM_COMPONENT = True | ||||
| @@ -51,7 +51,7 @@ async def audio_dac_set_volume_to_code(config, action_id, template_arg, args): | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_define("USE_AUDIO_DAC") | ||||
|     cg.add_global(audio_dac_ns.using) | ||||
|   | ||||
| @@ -59,7 +59,7 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_VIBRATION, | ||||
|     DEVICE_CLASS_WINDOW, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
| from esphome.util import Registry | ||||
| @@ -652,7 +652,7 @@ async def binary_sensor_is_off_to_code(config, condition_id, template_arg, args) | ||||
|     return cg.new_Pvariable(condition_id, template_arg, paren, False) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(binary_sensor_ns.using) | ||||
|  | ||||
|   | ||||
| @@ -15,8 +15,8 @@ void log_binary_sensor(const char *tag, const char *prefix, const char *type, Bi | ||||
|  | ||||
|   ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str()); | ||||
|  | ||||
|   if (!obj->get_device_class().empty()) { | ||||
|     ESP_LOGCONFIG(tag, "%s  Device Class: '%s'", prefix, obj->get_device_class().c_str()); | ||||
|   if (!obj->get_device_class_ref().empty()) { | ||||
|     ESP_LOGCONFIG(tag, "%s  Device Class: '%s'", prefix, obj->get_device_class_ref().c_str()); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -24,6 +24,9 @@ void BluetoothProxy::setup() { | ||||
|   this->connections_free_response_.limit = BLUETOOTH_PROXY_MAX_CONNECTIONS; | ||||
|   this->connections_free_response_.free = BLUETOOTH_PROXY_MAX_CONNECTIONS; | ||||
|  | ||||
|   // Capture the configured scan mode from YAML before any API changes | ||||
|   this->configured_scan_active_ = this->parent_->get_scan_active(); | ||||
|  | ||||
|   this->parent_->add_scanner_state_callback([this](esp32_ble_tracker::ScannerState state) { | ||||
|     if (this->api_connection_ != nullptr) { | ||||
|       this->send_bluetooth_scanner_state_(state); | ||||
| @@ -36,6 +39,9 @@ void BluetoothProxy::send_bluetooth_scanner_state_(esp32_ble_tracker::ScannerSta | ||||
|   resp.state = static_cast<api::enums::BluetoothScannerState>(state); | ||||
|   resp.mode = this->parent_->get_scan_active() ? api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE | ||||
|                                                : api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_PASSIVE; | ||||
|   resp.configured_mode = this->configured_scan_active_ | ||||
|                              ? api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE | ||||
|                              : api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_PASSIVE; | ||||
|   this->api_connection_->send_message(resp, api::BluetoothScannerStateResponse::MESSAGE_TYPE); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -161,7 +161,8 @@ class BluetoothProxy final : public esp32_ble_tracker::ESPBTDeviceListener, publ | ||||
|   // Group 4: 1-byte types grouped together | ||||
|   bool active_; | ||||
|   uint8_t connection_count_{0}; | ||||
|   // 2 bytes used, 2 bytes padding | ||||
|   bool configured_scan_active_{false};  // Configured scan mode from YAML | ||||
|   // 3 bytes used, 1 byte padding | ||||
| }; | ||||
|  | ||||
| extern BluetoothProxy *global_bluetooth_proxy;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||
|   | ||||
| @@ -17,7 +17,7 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_RESTART, | ||||
|     DEVICE_CLASS_UPDATE, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -134,6 +134,6 @@ async def button_press_to_code(config, action_id, template_arg, args): | ||||
|     return cg.new_Pvariable(action_id, template_arg, paren) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(button_ns.using) | ||||
|   | ||||
| @@ -14,8 +14,8 @@ void log_button(const char *tag, const char *prefix, const char *type, Button *o | ||||
|  | ||||
|   ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str()); | ||||
|  | ||||
|   if (!obj->get_icon().empty()) { | ||||
|     ESP_LOGCONFIG(tag, "%s  Icon: '%s'", prefix, obj->get_icon().c_str()); | ||||
|   if (!obj->get_icon_ref().empty()) { | ||||
|     ESP_LOGCONFIG(tag, "%s  Icon: '%s'", prefix, obj->get_icon_ref().c_str()); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										18
									
								
								esphome/components/camera/buffer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								esphome/components/camera/buffer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <cinttypes> | ||||
| #include <cstddef> | ||||
|  | ||||
| namespace esphome::camera { | ||||
|  | ||||
| /// Interface for a generic buffer that stores image data. | ||||
| class Buffer { | ||||
|  public: | ||||
|   /// Returns a pointer to the buffer's data. | ||||
|   virtual uint8_t *get_data_buffer() = 0; | ||||
|   /// Returns the length of the buffer in bytes. | ||||
|   virtual size_t get_data_length() = 0; | ||||
|   virtual ~Buffer() = default; | ||||
| }; | ||||
|  | ||||
| }  // namespace esphome::camera | ||||
							
								
								
									
										20
									
								
								esphome/components/camera/buffer_impl.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								esphome/components/camera/buffer_impl.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #include "buffer_impl.h" | ||||
|  | ||||
| namespace esphome::camera { | ||||
|  | ||||
| BufferImpl::BufferImpl(size_t size) { | ||||
|   this->data_ = this->allocator_.allocate(size); | ||||
|   this->size_ = size; | ||||
| } | ||||
|  | ||||
| BufferImpl::BufferImpl(CameraImageSpec *spec) { | ||||
|   this->data_ = this->allocator_.allocate(spec->bytes_per_image()); | ||||
|   this->size_ = spec->bytes_per_image(); | ||||
| } | ||||
|  | ||||
| BufferImpl::~BufferImpl() { | ||||
|   if (this->data_ != nullptr) | ||||
|     this->allocator_.deallocate(this->data_, this->size_); | ||||
| } | ||||
|  | ||||
| }  // namespace esphome::camera | ||||
							
								
								
									
										26
									
								
								esphome/components/camera/buffer_impl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								esphome/components/camera/buffer_impl.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "buffer.h" | ||||
| #include "camera.h" | ||||
|  | ||||
| namespace esphome::camera { | ||||
|  | ||||
| /// Default implementation of Buffer Interface. | ||||
| /// Uses a RAMAllocator for memory reservation. | ||||
| class BufferImpl : public Buffer { | ||||
|  public: | ||||
|   explicit BufferImpl(size_t size); | ||||
|   explicit BufferImpl(CameraImageSpec *spec); | ||||
|   // -------- Buffer -------- | ||||
|   uint8_t *get_data_buffer() override { return data_; } | ||||
|   size_t get_data_length() override { return size_; } | ||||
|   // ------------------------ | ||||
|   ~BufferImpl() override; | ||||
|  | ||||
|  protected: | ||||
|   RAMAllocator<uint8_t> allocator_; | ||||
|   size_t size_{}; | ||||
|   uint8_t *data_{}; | ||||
| }; | ||||
|  | ||||
| }  // namespace esphome::camera | ||||
| @@ -15,6 +15,26 @@ namespace camera { | ||||
|  */ | ||||
| enum CameraRequester : uint8_t { IDLE, API_REQUESTER, WEB_REQUESTER }; | ||||
|  | ||||
| /// Enumeration of different pixel formats. | ||||
| enum PixelFormat : uint8_t { | ||||
|   PIXEL_FORMAT_GRAYSCALE = 0,  ///< 8-bit grayscale. | ||||
|   PIXEL_FORMAT_RGB565,         ///< 16-bit RGB (5-6-5). | ||||
|   PIXEL_FORMAT_BGR888,         ///< RGB pixel data in 8-bit format, stored as B, G, R (1 byte each). | ||||
| }; | ||||
|  | ||||
| /// Returns string name for a given PixelFormat. | ||||
| inline const char *to_string(PixelFormat format) { | ||||
|   switch (format) { | ||||
|     case PIXEL_FORMAT_GRAYSCALE: | ||||
|       return "PIXEL_FORMAT_GRAYSCALE"; | ||||
|     case PIXEL_FORMAT_RGB565: | ||||
|       return "PIXEL_FORMAT_RGB565"; | ||||
|     case PIXEL_FORMAT_BGR888: | ||||
|       return "PIXEL_FORMAT_BGR888"; | ||||
|   } | ||||
|   return "PIXEL_FORMAT_UNKNOWN"; | ||||
| } | ||||
|  | ||||
| /** Abstract camera image base class. | ||||
|  *  Encapsulates the JPEG encoded data and it is shared among | ||||
|  *  all connected clients. | ||||
| @@ -43,6 +63,29 @@ class CameraImageReader { | ||||
|   virtual ~CameraImageReader() {} | ||||
| }; | ||||
|  | ||||
| /// Specification of a caputured camera image. | ||||
| /// This struct defines the format and size details for images captured | ||||
| /// or processed by a camera component. | ||||
| struct CameraImageSpec { | ||||
|   uint16_t width; | ||||
|   uint16_t height; | ||||
|   PixelFormat format; | ||||
|   size_t bytes_per_pixel() { | ||||
|     switch (format) { | ||||
|       case PIXEL_FORMAT_GRAYSCALE: | ||||
|         return 1; | ||||
|       case PIXEL_FORMAT_RGB565: | ||||
|         return 2; | ||||
|       case PIXEL_FORMAT_BGR888: | ||||
|         return 3; | ||||
|     } | ||||
|  | ||||
|     return 1; | ||||
|   } | ||||
|   size_t bytes_per_row() { return bytes_per_pixel() * width; } | ||||
|   size_t bytes_per_image() { return bytes_per_pixel() * width * height; } | ||||
| }; | ||||
|  | ||||
| /** Abstract camera base class. Collaborates with API. | ||||
|  *  1) API server starts and installs callback (add_image_callback) | ||||
|  *     which is called by the camera when a new image is available. | ||||
|   | ||||
							
								
								
									
										69
									
								
								esphome/components/camera/encoder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								esphome/components/camera/encoder.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "buffer.h" | ||||
| #include "camera.h" | ||||
|  | ||||
| namespace esphome::camera { | ||||
|  | ||||
| /// Result codes from the encoder used to control camera pipeline flow. | ||||
| enum EncoderError : uint8_t { | ||||
|   ENCODER_ERROR_SUCCESS = 0,   ///< Encoding succeeded, continue pipeline normally. | ||||
|   ENCODER_ERROR_SKIP_FRAME,    ///< Skip current frame, try again on next frame. | ||||
|   ENCODER_ERROR_RETRY_FRAME,   ///< Retry current frame, after buffer growth or for incremental encoding. | ||||
|   ENCODER_ERROR_CONFIGURATION  ///< Fatal config error, shut down pipeline. | ||||
| }; | ||||
|  | ||||
| /// Converts EncoderError to string. | ||||
| inline const char *to_string(EncoderError error) { | ||||
|   switch (error) { | ||||
|     case ENCODER_ERROR_SUCCESS: | ||||
|       return "ENCODER_ERROR_SUCCESS"; | ||||
|     case ENCODER_ERROR_SKIP_FRAME: | ||||
|       return "ENCODER_ERROR_SKIP_FRAME"; | ||||
|     case ENCODER_ERROR_RETRY_FRAME: | ||||
|       return "ENCODER_ERROR_RETRY_FRAME"; | ||||
|     case ENCODER_ERROR_CONFIGURATION: | ||||
|       return "ENCODER_ERROR_CONFIGURATION"; | ||||
|   } | ||||
|   return "ENCODER_ERROR_INVALID"; | ||||
| } | ||||
|  | ||||
| /// Interface for an encoder buffer supporting resizing and variable-length data. | ||||
| class EncoderBuffer { | ||||
|  public: | ||||
|   ///  Sets logical buffer size, reallocates if needed. | ||||
|   ///  @param size Required size in bytes. | ||||
|   ///  @return true on success, false on allocation failure. | ||||
|   virtual bool set_buffer_size(size_t size) = 0; | ||||
|  | ||||
|   /// Returns a pointer to the buffer data. | ||||
|   virtual uint8_t *get_data() const = 0; | ||||
|  | ||||
|   /// Returns number of bytes currently used. | ||||
|   virtual size_t get_size() const = 0; | ||||
|  | ||||
|   ///  Returns total allocated buffer size. | ||||
|   virtual size_t get_max_size() const = 0; | ||||
|  | ||||
|   virtual ~EncoderBuffer() = default; | ||||
| }; | ||||
|  | ||||
| /// Interface for image encoders used in a camera pipeline. | ||||
| class Encoder { | ||||
|  public: | ||||
|   /// Encodes pixel data from a previous camera pipeline stage. | ||||
|   /// @param spec Specification of the input pixel data. | ||||
|   /// @param pixels Image pixels in RGB or grayscale format, as specified in @p spec. | ||||
|   /// @return EncoderError Indicating the result of the encoding operation. | ||||
|   virtual EncoderError encode_pixels(CameraImageSpec *spec, Buffer *pixels) = 0; | ||||
|  | ||||
|   /// Returns the encoder's output buffer. | ||||
|   /// @return Pointer to an EncoderBuffer containing encoded data. | ||||
|   virtual EncoderBuffer *get_output_buffer() = 0; | ||||
|  | ||||
|   ///  Prints the encoder's configuration to the log. | ||||
|   virtual void dump_config() = 0; | ||||
|   virtual ~Encoder() = default; | ||||
| }; | ||||
|  | ||||
| }  // namespace esphome::camera | ||||
							
								
								
									
										62
									
								
								esphome/components/camera_encoder/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								esphome/components/camera_encoder/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components.esp32 import add_idf_component | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_BUFFER_SIZE, CONF_ID, CONF_TYPE | ||||
| from esphome.core import CORE | ||||
| from esphome.types import ConfigType | ||||
|  | ||||
| CODEOWNERS = ["@DT-art1"] | ||||
|  | ||||
| AUTO_LOAD = ["camera"] | ||||
|  | ||||
| CONF_BUFFER_EXPAND_SIZE = "buffer_expand_size" | ||||
| CONF_ENCODER_BUFFER_ID = "encoder_buffer_id" | ||||
| CONF_QUALITY = "quality" | ||||
|  | ||||
| ESP32_CAMERA_ENCODER = "esp32_camera" | ||||
|  | ||||
| camera_ns = cg.esphome_ns.namespace("camera") | ||||
| camera_encoder_ns = cg.esphome_ns.namespace("camera_encoder") | ||||
|  | ||||
| Encoder = camera_ns.class_("Encoder") | ||||
| EncoderBufferImpl = camera_encoder_ns.class_("EncoderBufferImpl") | ||||
|  | ||||
| ESP32CameraJPEGEncoder = camera_encoder_ns.class_("ESP32CameraJPEGEncoder", Encoder) | ||||
|  | ||||
| MAX_JPEG_BUFFER_SIZE_2MB = 2 * 1024 * 1024 | ||||
|  | ||||
| ESP32_CAMERA_ENCODER_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.GenerateID(): cv.declare_id(ESP32CameraJPEGEncoder), | ||||
|         cv.Optional(CONF_QUALITY, default=80): cv.int_range(1, 100), | ||||
|         cv.Optional(CONF_BUFFER_SIZE, default=4096): cv.int_range( | ||||
|             1024, MAX_JPEG_BUFFER_SIZE_2MB | ||||
|         ), | ||||
|         cv.Optional(CONF_BUFFER_EXPAND_SIZE, default=1024): cv.int_range( | ||||
|             0, MAX_JPEG_BUFFER_SIZE_2MB | ||||
|         ), | ||||
|         cv.GenerateID(CONF_ENCODER_BUFFER_ID): cv.declare_id(EncoderBufferImpl), | ||||
|     } | ||||
| ) | ||||
|  | ||||
| CONFIG_SCHEMA = cv.typed_schema( | ||||
|     { | ||||
|         ESP32_CAMERA_ENCODER: ESP32_CAMERA_ENCODER_SCHEMA, | ||||
|     }, | ||||
|     default_type=ESP32_CAMERA_ENCODER, | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config: ConfigType) -> None: | ||||
|     buffer = cg.new_Pvariable(config[CONF_ENCODER_BUFFER_ID]) | ||||
|     cg.add(buffer.set_buffer_size(config[CONF_BUFFER_SIZE])) | ||||
|     if config[CONF_TYPE] == ESP32_CAMERA_ENCODER: | ||||
|         if CORE.using_esp_idf: | ||||
|             add_idf_component(name="espressif/esp32-camera", ref="2.1.0") | ||||
|         cg.add_build_flag("-DUSE_ESP32_CAMERA_JPEG_ENCODER") | ||||
|         var = cg.new_Pvariable( | ||||
|             config[CONF_ID], | ||||
|             config[CONF_QUALITY], | ||||
|             buffer, | ||||
|         ) | ||||
|         cg.add(var.set_buffer_expand_size(config[CONF_BUFFER_EXPAND_SIZE])) | ||||
							
								
								
									
										23
									
								
								esphome/components/camera_encoder/encoder_buffer_impl.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								esphome/components/camera_encoder/encoder_buffer_impl.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| #include "encoder_buffer_impl.h" | ||||
|  | ||||
| namespace esphome::camera_encoder { | ||||
|  | ||||
| bool EncoderBufferImpl::set_buffer_size(size_t size) { | ||||
|   if (size > this->capacity_) { | ||||
|     uint8_t *p = this->allocator_.reallocate(this->data_, size); | ||||
|     if (p == nullptr) | ||||
|       return false; | ||||
|  | ||||
|     this->data_ = p; | ||||
|     this->capacity_ = size; | ||||
|   } | ||||
|   this->size_ = size; | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| EncoderBufferImpl::~EncoderBufferImpl() { | ||||
|   if (this->data_ != nullptr) | ||||
|     this->allocator_.deallocate(this->data_, this->capacity_); | ||||
| } | ||||
|  | ||||
| }  // namespace esphome::camera_encoder | ||||
							
								
								
									
										25
									
								
								esphome/components/camera_encoder/encoder_buffer_impl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								esphome/components/camera_encoder/encoder_buffer_impl.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/camera/encoder.h" | ||||
| #include "esphome/core/helpers.h" | ||||
|  | ||||
| namespace esphome::camera_encoder { | ||||
|  | ||||
| class EncoderBufferImpl : public camera::EncoderBuffer { | ||||
|  public: | ||||
|   // --- EncoderBuffer  --- | ||||
|   bool set_buffer_size(size_t size) override; | ||||
|   uint8_t *get_data() const override { return this->data_; } | ||||
|   size_t get_size() const override { return this->size_; } | ||||
|   size_t get_max_size() const override { return this->capacity_; } | ||||
|   // ---------------------- | ||||
|   ~EncoderBufferImpl() override; | ||||
|  | ||||
|  protected: | ||||
|   RAMAllocator<uint8_t> allocator_; | ||||
|   size_t capacity_{}; | ||||
|   size_t size_{}; | ||||
|   uint8_t *data_{}; | ||||
| }; | ||||
|  | ||||
| }  // namespace esphome::camera_encoder | ||||
| @@ -0,0 +1,82 @@ | ||||
| #ifdef USE_ESP32_CAMERA_JPEG_ENCODER | ||||
|  | ||||
| #include "esp32_camera_jpeg_encoder.h" | ||||
|  | ||||
| namespace esphome::camera_encoder { | ||||
|  | ||||
| static const char *const TAG = "camera_encoder"; | ||||
|  | ||||
| ESP32CameraJPEGEncoder::ESP32CameraJPEGEncoder(uint8_t quality, camera::EncoderBuffer *output) { | ||||
|   this->quality_ = quality; | ||||
|   this->output_ = output; | ||||
| } | ||||
|  | ||||
| camera::EncoderError ESP32CameraJPEGEncoder::encode_pixels(camera::CameraImageSpec *spec, camera::Buffer *pixels) { | ||||
|   this->bytes_written_ = 0; | ||||
|   this->out_of_output_memory_ = false; | ||||
|   bool success = fmt2jpg_cb(pixels->get_data_buffer(), pixels->get_data_length(), spec->width, spec->height, | ||||
|                             to_internal_(spec->format), this->quality_, callback_, this); | ||||
|  | ||||
|   if (!success) | ||||
|     return camera::ENCODER_ERROR_CONFIGURATION; | ||||
|  | ||||
|   if (this->out_of_output_memory_) { | ||||
|     if (this->buffer_expand_size_ <= 0) | ||||
|       return camera::ENCODER_ERROR_SKIP_FRAME; | ||||
|  | ||||
|     size_t current_size = this->output_->get_max_size(); | ||||
|     size_t new_size = this->output_->get_max_size() + this->buffer_expand_size_; | ||||
|     if (!this->output_->set_buffer_size(new_size)) { | ||||
|       ESP_LOGE(TAG, "Failed to expand output buffer."); | ||||
|       this->buffer_expand_size_ = 0; | ||||
|       return camera::ENCODER_ERROR_SKIP_FRAME; | ||||
|     } | ||||
|  | ||||
|     ESP_LOGD(TAG, "Output buffer expanded (%u -> %u).", current_size, this->output_->get_max_size()); | ||||
|     return camera::ENCODER_ERROR_RETRY_FRAME; | ||||
|   } | ||||
|  | ||||
|   this->output_->set_buffer_size(this->bytes_written_); | ||||
|   return camera::ENCODER_ERROR_SUCCESS; | ||||
| } | ||||
|  | ||||
| void ESP32CameraJPEGEncoder::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, | ||||
|                 "ESP32 Camera JPEG Encoder:\n" | ||||
|                 "  Size: %zu\n" | ||||
|                 "  Quality: %d\n" | ||||
|                 "  Expand: %d\n", | ||||
|                 this->output_->get_max_size(), this->quality_, this->buffer_expand_size_); | ||||
| } | ||||
|  | ||||
| size_t ESP32CameraJPEGEncoder::callback_(void *arg, size_t index, const void *data, size_t len) { | ||||
|   ESP32CameraJPEGEncoder *that = reinterpret_cast<ESP32CameraJPEGEncoder *>(arg); | ||||
|   uint8_t *buffer = that->output_->get_data(); | ||||
|   size_t buffer_length = that->output_->get_max_size(); | ||||
|   if (index + len > buffer_length) { | ||||
|     that->out_of_output_memory_ = true; | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   std::memcpy(&buffer[index], data, len); | ||||
|   that->bytes_written_ += len; | ||||
|   return len; | ||||
| } | ||||
|  | ||||
| pixformat_t ESP32CameraJPEGEncoder::to_internal_(camera::PixelFormat format) { | ||||
|   switch (format) { | ||||
|     case camera::PIXEL_FORMAT_GRAYSCALE: | ||||
|       return PIXFORMAT_GRAYSCALE; | ||||
|     case camera::PIXEL_FORMAT_RGB565: | ||||
|       return PIXFORMAT_RGB565; | ||||
|     // Internal representation for RGB is in byte order: B, G, R | ||||
|     case camera::PIXEL_FORMAT_BGR888: | ||||
|       return PIXFORMAT_RGB888; | ||||
|   } | ||||
|  | ||||
|   return PIXFORMAT_GRAYSCALE; | ||||
| } | ||||
|  | ||||
| }  // namespace esphome::camera_encoder | ||||
|  | ||||
| #endif | ||||
| @@ -0,0 +1,39 @@ | ||||
| #pragma once | ||||
|  | ||||
| #ifdef USE_ESP32_CAMERA_JPEG_ENCODER | ||||
|  | ||||
| #include <esp_camera.h> | ||||
|  | ||||
| #include "esphome/components/camera/encoder.h" | ||||
|  | ||||
| namespace esphome::camera_encoder { | ||||
|  | ||||
| /// Encoder that uses the software-based JPEG implementation from Espressif's esp32-camera component. | ||||
| class ESP32CameraJPEGEncoder : public camera::Encoder { | ||||
|  public: | ||||
|   /// Constructs a ESP32CameraJPEGEncoder instance. | ||||
|   /// @param quality Sets the quality of the encoded image (1-100). | ||||
|   /// @param output Pointer to preallocated output buffer. | ||||
|   ESP32CameraJPEGEncoder(uint8_t quality, camera::EncoderBuffer *output); | ||||
|   /// Sets the number of bytes to expand the output buffer on underflow during encoding. | ||||
|   /// @param buffer_expand_size Number of bytes to expand the buffer. | ||||
|   void set_buffer_expand_size(size_t buffer_expand_size) { this->buffer_expand_size_ = buffer_expand_size; } | ||||
|   // -------- Encoder -------- | ||||
|   camera::EncoderError encode_pixels(camera::CameraImageSpec *spec, camera::Buffer *pixels) override; | ||||
|   camera::EncoderBuffer *get_output_buffer() override { return output_; } | ||||
|   void dump_config() override; | ||||
|   // ------------------------- | ||||
|  protected: | ||||
|   static size_t callback_(void *arg, size_t index, const void *data, size_t len); | ||||
|   pixformat_t to_internal_(camera::PixelFormat format); | ||||
|  | ||||
|   camera::EncoderBuffer *output_{}; | ||||
|   size_t buffer_expand_size_{}; | ||||
|   size_t bytes_written_{}; | ||||
|   uint8_t quality_{}; | ||||
|   bool out_of_output_memory_{}; | ||||
| }; | ||||
|  | ||||
| }  // namespace esphome::camera_encoder | ||||
|  | ||||
| #endif | ||||
| @@ -10,7 +10,7 @@ from esphome.const import ( | ||||
|     PLATFORM_LN882X, | ||||
|     PLATFORM_RTL87XX, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
|  | ||||
| AUTO_LOAD = ["web_server_base", "ota.web_server"] | ||||
| DEPENDENCIES = ["wifi"] | ||||
| @@ -40,7 +40,7 @@ CONFIG_SCHEMA = cv.All( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(64.0) | ||||
| @coroutine_with_priority(CoroPriority.COMMUNICATION) | ||||
| async def to_code(config): | ||||
|     paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) | ||||
|  | ||||
|   | ||||
| @@ -47,7 +47,7 @@ from esphome.const import ( | ||||
|     CONF_VISUAL, | ||||
|     CONF_WEB_SERVER, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -517,6 +517,6 @@ async def climate_control_to_code(config, action_id, template_arg, args): | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(climate_ns.using) | ||||
|   | ||||
| @@ -32,7 +32,7 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_SHUTTER, | ||||
|     DEVICE_CLASS_WINDOW, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -263,6 +263,6 @@ async def cover_control_to_code(config, action_id, template_arg, args): | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(cover_ns.using) | ||||
|   | ||||
| @@ -19,8 +19,8 @@ const extern float COVER_CLOSED; | ||||
|     if (traits_.get_is_assumed_state()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Assumed State: YES", prefix); \ | ||||
|     } \ | ||||
|     if (!(obj)->get_device_class().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Device Class: '%s'", prefix, (obj)->get_device_class().c_str()); \ | ||||
|     if (!(obj)->get_device_class_ref().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Device Class: '%s'", prefix, (obj)->get_device_class_ref().c_str()); \ | ||||
|     } \ | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,7 @@ from esphome.const import ( | ||||
|     CONF_WEB_SERVER, | ||||
|     CONF_YEAR, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -172,7 +172,7 @@ async def new_datetime(config, *args): | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(datetime_ns.using) | ||||
|  | ||||
|   | ||||
| @@ -16,8 +16,8 @@ namespace datetime { | ||||
| #define LOG_DATETIME_DATE(prefix, type, obj) \ | ||||
|   if ((obj) != nullptr) { \ | ||||
|     ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ | ||||
|     if (!(obj)->get_icon().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ | ||||
|     if (!(obj)->get_icon_ref().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \ | ||||
|     } \ | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -16,8 +16,8 @@ namespace datetime { | ||||
| #define LOG_DATETIME_DATETIME(prefix, type, obj) \ | ||||
|   if ((obj) != nullptr) { \ | ||||
|     ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ | ||||
|     if (!(obj)->get_icon().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ | ||||
|     if (!(obj)->get_icon_ref().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \ | ||||
|     } \ | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -16,8 +16,8 @@ namespace datetime { | ||||
| #define LOG_DATETIME_TIME(prefix, type, obj) \ | ||||
|   if ((obj) != nullptr) { \ | ||||
|     ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ | ||||
|     if (!(obj)->get_icon().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ | ||||
|     if (!(obj)->get_icon_ref().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \ | ||||
|     } \ | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -15,7 +15,7 @@ from esphome.const import ( | ||||
|     CONF_UPDATE_INTERVAL, | ||||
|     SCHEDULER_DONT_RUN, | ||||
| ) | ||||
| from esphome.core import coroutine_with_priority | ||||
| from esphome.core import CoroPriority, coroutine_with_priority | ||||
|  | ||||
| IS_PLATFORM_COMPONENT = True | ||||
|  | ||||
| @@ -176,7 +176,7 @@ async def display_page_show_to_code(config, action_id, template_arg, args): | ||||
|     DisplayPageShowNextAction, | ||||
|     maybe_simple_id( | ||||
|         { | ||||
|             cv.Required(CONF_ID): cv.templatable(cv.use_id(Display)), | ||||
|             cv.GenerateID(CONF_ID): cv.templatable(cv.use_id(Display)), | ||||
|         } | ||||
|     ), | ||||
| ) | ||||
| @@ -190,7 +190,7 @@ async def display_page_show_next_to_code(config, action_id, template_arg, args): | ||||
|     DisplayPageShowPrevAction, | ||||
|     maybe_simple_id( | ||||
|         { | ||||
|             cv.Required(CONF_ID): cv.templatable(cv.use_id(Display)), | ||||
|             cv.GenerateID(CONF_ID): cv.templatable(cv.use_id(Display)), | ||||
|         } | ||||
|     ), | ||||
| ) | ||||
| @@ -218,7 +218,7 @@ async def display_is_displaying_page_to_code(config, condition_id, template_arg, | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(display_ns.using) | ||||
|     cg.add_define("USE_DISPLAY") | ||||
|   | ||||
| @@ -855,11 +855,6 @@ async def to_code(config): | ||||
|  | ||||
|         cg.add_platformio_option("platform_packages", [conf[CONF_SOURCE]]) | ||||
|  | ||||
|         # platformio/toolchain-esp32ulp does not support linux_aarch64 yet and has not been updated for over 2 years | ||||
|         # This is espressif's own published version which is more up to date. | ||||
|         cg.add_platformio_option( | ||||
|             "platform_packages", ["espressif/toolchain-esp32ulp@2.35.0-20220830"] | ||||
|         ) | ||||
|         add_idf_sdkconfig_option(f"CONFIG_IDF_TARGET_{variant}", True) | ||||
|         add_idf_sdkconfig_option( | ||||
|             f"CONFIG_ESPTOOLPY_FLASHSIZE_{config[CONF_FLASH_SIZE]}", True | ||||
|   | ||||
| @@ -30,7 +30,7 @@ from esphome.const import ( | ||||
|     CONF_SERVICE_UUID, | ||||
|     CONF_TRIGGER_ID, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.enum import StrEnum | ||||
| from esphome.types import ConfigType | ||||
|  | ||||
| @@ -368,7 +368,7 @@ async def to_code(config): | ||||
| # This needs to be run as a job with very low priority so that all components have | ||||
| # chance to call register_ble_tracker and register_client before the list is checked | ||||
| # and added to the global defines list. | ||||
| @coroutine_with_priority(-1000) | ||||
| @coroutine_with_priority(CoroPriority.FINAL) | ||||
| async def _add_ble_features(): | ||||
|     # Add feature-specific defines based on what's needed | ||||
|     if BLEFeatures.ESP_BT_DEVICE in _required_features: | ||||
|   | ||||
| @@ -17,7 +17,7 @@ from esphome.const import ( | ||||
|     PLATFORM_ESP8266, | ||||
|     ThreadModel, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.helpers import copy_file_if_changed | ||||
|  | ||||
| from .boards import BOARDS, ESP8266_LD_SCRIPTS | ||||
| @@ -176,7 +176,7 @@ CONFIG_SCHEMA = cv.All( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(1000) | ||||
| @coroutine_with_priority(CoroPriority.PLATFORM) | ||||
| async def to_code(config): | ||||
|     cg.add(esp8266_ns.setup_preferences()) | ||||
|  | ||||
|   | ||||
| @@ -17,7 +17,7 @@ from esphome.const import ( | ||||
|     CONF_PULLUP, | ||||
|     PLATFORM_ESP8266, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
|  | ||||
| from . import boards | ||||
| from .const import KEY_BOARD, KEY_ESP8266, KEY_PIN_INITIAL_STATES, esp8266_ns | ||||
| @@ -188,7 +188,7 @@ async def esp8266_pin_to_code(config): | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(-999.0) | ||||
| @coroutine_with_priority(CoroPriority.WORKAROUNDS) | ||||
| async def add_pin_initial_states_array(): | ||||
|     # Add includes at the very end, so that they override everything | ||||
|     initial_states: list[PinInitialState] = CORE.data[KEY_ESP8266][ | ||||
|   | ||||
| @@ -16,7 +16,7 @@ from esphome.const import ( | ||||
|     CONF_SAFE_MODE, | ||||
|     CONF_VERSION, | ||||
| ) | ||||
| from esphome.core import coroutine_with_priority | ||||
| from esphome.core import CoroPriority, coroutine_with_priority | ||||
| import esphome.final_validate as fv | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
| @@ -121,7 +121,7 @@ CONFIG_SCHEMA = ( | ||||
| FINAL_VALIDATE_SCHEMA = ota_esphome_final_validate | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(52.0) | ||||
| @coroutine_with_priority(CoroPriority.COMMUNICATION) | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     cg.add(var.set_port(config[CONF_PORT])) | ||||
|   | ||||
| @@ -38,7 +38,12 @@ from esphome.const import ( | ||||
|     KEY_CORE, | ||||
|     KEY_FRAMEWORK_VERSION, | ||||
| ) | ||||
| from esphome.core import CORE, TimePeriodMilliseconds, coroutine_with_priority | ||||
| from esphome.core import ( | ||||
|     CORE, | ||||
|     CoroPriority, | ||||
|     TimePeriodMilliseconds, | ||||
|     coroutine_with_priority, | ||||
| ) | ||||
| import esphome.final_validate as fv | ||||
|  | ||||
| CONFLICTS_WITH = ["wifi"] | ||||
| @@ -289,7 +294,7 @@ def phy_register(address: int, value: int, page: int): | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(60.0) | ||||
| @coroutine_with_priority(CoroPriority.COMMUNICATION) | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await cg.register_component(var, config) | ||||
|   | ||||
| @@ -17,7 +17,7 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_EMPTY, | ||||
|     DEVICE_CLASS_MOTION, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -143,6 +143,6 @@ async def event_fire_to_code(config, action_id, template_arg, args): | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(event_ns.using) | ||||
|   | ||||
| @@ -13,11 +13,11 @@ namespace event { | ||||
| #define LOG_EVENT(prefix, type, obj) \ | ||||
|   if ((obj) != nullptr) { \ | ||||
|     ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ | ||||
|     if (!(obj)->get_icon().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ | ||||
|     if (!(obj)->get_icon_ref().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \ | ||||
|     } \ | ||||
|     if (!(obj)->get_device_class().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Device Class: '%s'", prefix, (obj)->get_device_class().c_str()); \ | ||||
|     if (!(obj)->get_device_class_ref().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Device Class: '%s'", prefix, (obj)->get_device_class_ref().c_str()); \ | ||||
|     } \ | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -31,7 +31,7 @@ from esphome.const import ( | ||||
|     CONF_TRIGGER_ID, | ||||
|     CONF_WEB_SERVER, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
|  | ||||
| IS_PLATFORM_COMPONENT = True | ||||
| @@ -398,6 +398,6 @@ async def fan_is_on_off_to_code(config, condition_id, template_arg, args): | ||||
|     return cg.new_Pvariable(condition_id, template_arg, paren) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(fan_ns.using) | ||||
|   | ||||
| @@ -8,7 +8,7 @@ from esphome.const import ( | ||||
|     CONF_TYPE, | ||||
|     CONF_VALUE, | ||||
| ) | ||||
| from esphome.core import coroutine_with_priority | ||||
| from esphome.core import CoroPriority, coroutine_with_priority | ||||
|  | ||||
| CODEOWNERS = ["@esphome/core"] | ||||
| globals_ns = cg.esphome_ns.namespace("globals") | ||||
| @@ -35,7 +35,7 @@ CONFIG_SCHEMA = cv.Schema( | ||||
|  | ||||
|  | ||||
| # Run with low priority so that namespaces are registered first | ||||
| @coroutine_with_priority(-100.0) | ||||
| @coroutine_with_priority(CoroPriority.LATE) | ||||
| async def to_code(config): | ||||
|     type_ = cg.RawExpression(config[CONF_TYPE]) | ||||
|     restore = config[CONF_RESTORE_VALUE] | ||||
|   | ||||
| @@ -42,9 +42,10 @@ class HostPreferences : public ESPPreferences { | ||||
|     if (len > 255) | ||||
|       return false; | ||||
|     this->setup_(); | ||||
|     if (this->data.count(key) == 0) | ||||
|     auto it = this->data.find(key); | ||||
|     if (it == this->data.end()) | ||||
|       return false; | ||||
|     auto vec = this->data[key]; | ||||
|     const auto &vec = it->second; | ||||
|     if (vec.size() != len) | ||||
|       return false; | ||||
|     memcpy(data, vec.data(), len); | ||||
|   | ||||
| @@ -3,7 +3,7 @@ import esphome.codegen as cg | ||||
| from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID, CONF_PASSWORD, CONF_URL, CONF_USERNAME | ||||
| from esphome.core import coroutine_with_priority | ||||
| from esphome.core import CoroPriority, coroutine_with_priority | ||||
|  | ||||
| from .. import CONF_HTTP_REQUEST_ID, HttpRequestComponent, http_request_ns | ||||
|  | ||||
| @@ -40,7 +40,7 @@ CONFIG_SCHEMA = cv.All( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(52.0) | ||||
| @coroutine_with_priority(CoroPriority.COMMUNICATION) | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await ota_to_code(var, config) | ||||
|   | ||||
| @@ -18,7 +18,7 @@ from esphome.const import ( | ||||
|     PLATFORM_RP2040, | ||||
|     PlatformFramework, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| import esphome.final_validate as fv | ||||
|  | ||||
| LOGGER = logging.getLogger(__name__) | ||||
| @@ -74,7 +74,7 @@ CONFIG_SCHEMA = cv.All( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(1.0) | ||||
| @coroutine_with_priority(CoroPriority.BUS) | ||||
| async def to_code(config): | ||||
|     cg.add_global(i2c_ns.using) | ||||
|     cg.add_define("USE_I2C") | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.core import coroutine_with_priority | ||||
| from esphome.core import CoroPriority, coroutine_with_priority | ||||
|  | ||||
| CODEOWNERS = ["@esphome/core"] | ||||
| json_ns = cg.esphome_ns.namespace("json") | ||||
| @@ -10,7 +10,7 @@ CONFIG_SCHEMA = cv.All( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(1.0) | ||||
| @coroutine_with_priority(CoroPriority.BUS) | ||||
| async def to_code(config): | ||||
|     cg.add_library("bblanchon/ArduinoJson", "7.4.2") | ||||
|     cg.add_define("USE_JSON") | ||||
|   | ||||
| @@ -37,7 +37,7 @@ from esphome.const import ( | ||||
|     CONF_WEB_SERVER, | ||||
|     CONF_WHITE, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -283,6 +283,6 @@ async def new_light(config, *args): | ||||
|     return output_var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(light_ns.using) | ||||
|   | ||||
| @@ -13,7 +13,7 @@ from esphome.const import ( | ||||
|     CONF_TRIGGER_ID, | ||||
|     CONF_WEB_SERVER, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -155,6 +155,6 @@ async def lock_is_off_to_code(config, condition_id, template_arg, args): | ||||
|     return cg.new_Pvariable(condition_id, template_arg, paren, False) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(lock_ns.using) | ||||
|   | ||||
| @@ -15,8 +15,8 @@ class Lock; | ||||
| #define LOG_LOCK(prefix, type, obj) \ | ||||
|   if ((obj) != nullptr) { \ | ||||
|     ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ | ||||
|     if (!(obj)->get_icon().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ | ||||
|     if (!(obj)->get_icon_ref().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \ | ||||
|     } \ | ||||
|     if ((obj)->traits.get_assumed_state()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Assumed State: YES", prefix); \ | ||||
|   | ||||
| @@ -51,7 +51,7 @@ from esphome.const import ( | ||||
|     PLATFORM_RTL87XX, | ||||
|     PlatformFramework, | ||||
| ) | ||||
| from esphome.core import CORE, Lambda, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, Lambda, coroutine_with_priority | ||||
|  | ||||
| CODEOWNERS = ["@esphome/core"] | ||||
| logger_ns = cg.esphome_ns.namespace("logger") | ||||
| @@ -275,7 +275,7 @@ CONFIG_SCHEMA = cv.All( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(90.0) | ||||
| @coroutine_with_priority(CoroPriority.DIAGNOSTICS) | ||||
| async def to_code(config): | ||||
|     baud_rate = config[CONF_BAUD_RATE] | ||||
|     level = config[CONF_LEVEL] | ||||
|   | ||||
| @@ -122,7 +122,7 @@ uint8_t Mcp4461Component::get_status_register_() { | ||||
|   uint8_t addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_STATUS); | ||||
|   uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::READ); | ||||
|   uint16_t buf; | ||||
|   if (!this->read_byte_16(reg, &buf)) { | ||||
|   if (!this->read_16_(reg, &buf)) { | ||||
|     this->error_code_ = MCP4461_STATUS_REGISTER_ERROR; | ||||
|     this->mark_failed(); | ||||
|     return 0; | ||||
| @@ -148,6 +148,20 @@ void Mcp4461Component::read_status_register_to_log() { | ||||
|            ((status_register_value >> 3) & 0x01), ((status_register_value >> 2) & 0x01), | ||||
|            ((status_register_value >> 1) & 0x01), ((status_register_value >> 0) & 0x01)); | ||||
| } | ||||
| bool Mcp4461Component::read_16_(uint8_t address, uint16_t *buf) { | ||||
|   // read 16 bits and convert from big endian to host, | ||||
|   // Do this as two separate operations to ensure a stop condition between the write and read | ||||
|   i2c::ErrorCode err = this->write(&address, 1); | ||||
|   if (err != i2c::ERROR_OK) { | ||||
|     return false; | ||||
|   } | ||||
|   err = this->read(reinterpret_cast<uint8_t *>(buf), 2); | ||||
|   if (err != i2c::ERROR_OK) { | ||||
|     return false; | ||||
|   } | ||||
|   *buf = convert_big_endian(*buf); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| uint8_t Mcp4461Component::get_wiper_address_(uint8_t wiper) { | ||||
|   uint8_t addr; | ||||
| @@ -205,7 +219,7 @@ uint16_t Mcp4461Component::read_wiper_level_(uint8_t wiper_idx) { | ||||
|     } | ||||
|   } | ||||
|   uint16_t buf = 0; | ||||
|   if (!(this->read_byte_16(reg, &buf))) { | ||||
|   if (!(this->read_16_(reg, &buf))) { | ||||
|     this->error_code_ = MCP4461_STATUS_I2C_ERROR; | ||||
|     this->status_set_warning(); | ||||
|     ESP_LOGW(TAG, "Error fetching %swiper %u value", (wiper_idx > 3) ? "nonvolatile " : "", wiper_idx); | ||||
| @@ -392,7 +406,7 @@ uint8_t Mcp4461Component::get_terminal_register_(Mcp4461TerminalIdx terminal_con | ||||
|                                                               : static_cast<uint8_t>(Mcp4461Addresses::MCP4461_TCON1); | ||||
|   reg |= static_cast<uint8_t>(Mcp4461Commands::READ); | ||||
|   uint16_t buf; | ||||
|   if (this->read_byte_16(reg, &buf)) { | ||||
|   if (this->read_16_(reg, &buf)) { | ||||
|     return static_cast<uint8_t>(buf & 0x00ff); | ||||
|   } else { | ||||
|     this->error_code_ = MCP4461_STATUS_I2C_ERROR; | ||||
| @@ -517,7 +531,7 @@ uint16_t Mcp4461Component::get_eeprom_value(Mcp4461EepromLocation location) { | ||||
|   if (!this->is_eeprom_ready_for_writing_(true)) { | ||||
|     return 0; | ||||
|   } | ||||
|   if (!this->read_byte_16(reg, &buf)) { | ||||
|   if (!this->read_16_(reg, &buf)) { | ||||
|     this->error_code_ = MCP4461_STATUS_I2C_ERROR; | ||||
|     this->status_set_warning(); | ||||
|     ESP_LOGW(TAG, "Error fetching EEPROM location value"); | ||||
|   | ||||
| @@ -96,6 +96,7 @@ class Mcp4461Component : public Component, public i2c::I2CDevice { | ||||
|  | ||||
|  protected: | ||||
|   friend class Mcp4461Wiper; | ||||
|   bool read_16_(uint8_t address, uint16_t *buf); | ||||
|   void update_write_protection_status_(); | ||||
|   uint8_t get_wiper_address_(uint8_t wiper); | ||||
|   uint16_t read_wiper_level_(uint8_t wiper); | ||||
|   | ||||
| @@ -11,7 +11,7 @@ from esphome.const import ( | ||||
|     CONF_SERVICES, | ||||
|     PlatformFramework, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
|  | ||||
| CODEOWNERS = ["@esphome/core"] | ||||
| DEPENDENCIES = ["network"] | ||||
| @@ -72,7 +72,7 @@ def mdns_service( | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(55.0) | ||||
| @coroutine_with_priority(CoroPriority.COMMUNICATION) | ||||
| async def to_code(config): | ||||
|     if config[CONF_DISABLED] is True: | ||||
|         return | ||||
|   | ||||
| @@ -14,7 +14,7 @@ from esphome.const import ( | ||||
| ) | ||||
| from esphome.core import CORE | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.coroutine import coroutine_with_priority | ||||
| from esphome.coroutine import CoroPriority, coroutine_with_priority | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| CODEOWNERS = ["@jesserockz"] | ||||
| @@ -303,7 +303,7 @@ async def media_player_volume_set_action(config, action_id, template_arg, args): | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(media_player_ns.using) | ||||
|     cg.add_define("USE_MEDIA_PLAYER") | ||||
|   | ||||
| @@ -12,7 +12,7 @@ from esphome.const import ( | ||||
|     CONF_TRIGGER_ID, | ||||
| ) | ||||
| from esphome.core import CORE | ||||
| from esphome.coroutine import coroutine_with_priority | ||||
| from esphome.coroutine import CoroPriority, coroutine_with_priority | ||||
|  | ||||
| AUTO_LOAD = ["audio"] | ||||
| CODEOWNERS = ["@jesserockz", "@kahrendt"] | ||||
| @@ -213,7 +213,7 @@ automation.register_condition( | ||||
| )(microphone_action) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(microphone_ns.using) | ||||
|     cg.add_define("USE_MICROPHONE") | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| # Various configuration constants for MIPI displays | ||||
| # Various utility functions for MIPI DBI configuration | ||||
|  | ||||
| from typing import Any | ||||
| from typing import Any, Self | ||||
|  | ||||
| from esphome.components.const import CONF_COLOR_DEPTH | ||||
| from esphome.components.display import CONF_SHOW_TEST_CARD, display_ns | ||||
| @@ -222,7 +222,7 @@ def delay(ms): | ||||
|  | ||||
|  | ||||
| class DriverChip: | ||||
|     models = {} | ||||
|     models: dict[str, Self] = {} | ||||
|  | ||||
|     def __init__( | ||||
|         self, | ||||
|   | ||||
| @@ -16,7 +16,6 @@ DriverChip( | ||||
|     lane_bit_rate="750Mbps", | ||||
|     swap_xy=cv.UNDEFINED, | ||||
|     color_order="RGB", | ||||
|     reset_pin=27, | ||||
|     initsequence=[ | ||||
|         (0x30, 0x00), (0xF7, 0x49, 0x61, 0x02, 0x00), (0x30, 0x01), (0x04, 0x0C), (0x05, 0x00), (0x06, 0x00), | ||||
|         (0x0B, 0x11), (0x17, 0x00), (0x20, 0x04), (0x1F, 0x05), (0x23, 0x00), (0x25, 0x19), (0x28, 0x18), (0x29, 0x04), (0x2A, 0x01), | ||||
|   | ||||
| @@ -57,7 +57,7 @@ from esphome.const import ( | ||||
|     PLATFORM_ESP8266, | ||||
|     PlatformFramework, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
|  | ||||
| DEPENDENCIES = ["network"] | ||||
|  | ||||
| @@ -321,7 +321,7 @@ def exp_mqtt_message(config): | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(40.0) | ||||
| @coroutine_with_priority(CoroPriority.WEB) | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await cg.register_component(var, config) | ||||
|   | ||||
| @@ -2,7 +2,7 @@ import esphome.codegen as cg | ||||
| from esphome.components.esp32 import add_idf_sdkconfig_option | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ENABLE_IPV6, CONF_MIN_IPV6_ADDR_COUNT | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
|  | ||||
| CODEOWNERS = ["@esphome/core"] | ||||
| AUTO_LOAD = ["mdns"] | ||||
| @@ -36,7 +36,7 @@ CONFIG_SCHEMA = cv.Schema( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(201.0) | ||||
| @coroutine_with_priority(CoroPriority.NETWORK) | ||||
| async def to_code(config): | ||||
|     cg.add_define("USE_NETWORK") | ||||
|     if CORE.using_arduino and CORE.is_esp32: | ||||
|   | ||||
| @@ -2,10 +2,13 @@ from __future__ import annotations | ||||
|  | ||||
| from pathlib import Path | ||||
|  | ||||
| from esphome import pins | ||||
| import esphome.codegen as cg | ||||
| from esphome.components.zephyr import ( | ||||
|     copy_files as zephyr_copy_files, | ||||
|     zephyr_add_pm_static, | ||||
|     zephyr_add_prj_conf, | ||||
|     zephyr_data, | ||||
|     zephyr_set_core_data, | ||||
|     zephyr_to_code, | ||||
| ) | ||||
| @@ -18,6 +21,8 @@ import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_BOARD, | ||||
|     CONF_FRAMEWORK, | ||||
|     CONF_ID, | ||||
|     CONF_RESET_PIN, | ||||
|     KEY_CORE, | ||||
|     KEY_FRAMEWORK_VERSION, | ||||
|     KEY_TARGET_FRAMEWORK, | ||||
| @@ -25,7 +30,7 @@ from esphome.const import ( | ||||
|     PLATFORM_NRF52, | ||||
|     ThreadModel, | ||||
| ) | ||||
| from esphome.core import CORE, EsphomeError, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, EsphomeError, coroutine_with_priority | ||||
| from esphome.storage_json import StorageJSON | ||||
| from esphome.types import ConfigType | ||||
|  | ||||
| @@ -90,19 +95,44 @@ def _detect_bootloader(config: ConfigType) -> ConfigType: | ||||
|     return config | ||||
|  | ||||
|  | ||||
| nrf52_ns = cg.esphome_ns.namespace("nrf52") | ||||
| DeviceFirmwareUpdate = nrf52_ns.class_("DeviceFirmwareUpdate", cg.Component) | ||||
|  | ||||
| CONF_DFU = "dfu" | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     _detect_bootloader, | ||||
|     set_core_data, | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.Required(CONF_BOARD): cv.string_strict, | ||||
|             cv.Optional(KEY_BOOTLOADER): cv.one_of(*BOOTLOADERS, lower=True), | ||||
|             cv.Optional(CONF_DFU): cv.Schema( | ||||
|                 { | ||||
|                     cv.GenerateID(): cv.declare_id(DeviceFirmwareUpdate), | ||||
|                     cv.Required(CONF_RESET_PIN): pins.gpio_output_pin_schema, | ||||
|                 } | ||||
|             ), | ||||
|         } | ||||
|     ), | ||||
|     _detect_bootloader, | ||||
|     set_core_data, | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(1000) | ||||
| def _validate_mcumgr(config): | ||||
|     bootloader = zephyr_data()[KEY_BOOTLOADER] | ||||
|     if bootloader == BOOTLOADER_MCUBOOT: | ||||
|         raise cv.Invalid(f"'{bootloader}' bootloader does not support DFU") | ||||
|  | ||||
|  | ||||
| def _final_validate(config): | ||||
|     if CONF_DFU in config: | ||||
|         _validate_mcumgr(config) | ||||
|  | ||||
|  | ||||
| FINAL_VALIDATE_SCHEMA = _final_validate | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(CoroPriority.PLATFORM) | ||||
| async def to_code(config: ConfigType) -> None: | ||||
|     """Convert the configuration to code.""" | ||||
|     cg.add_platformio_option("board", config[CONF_BOARD]) | ||||
| @@ -136,6 +166,19 @@ async def to_code(config: ConfigType) -> None: | ||||
|  | ||||
|     zephyr_to_code(config) | ||||
|  | ||||
|     if dfu_config := config.get(CONF_DFU): | ||||
|         CORE.add_job(_dfu_to_code, dfu_config) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(CoroPriority.DIAGNOSTICS) | ||||
| async def _dfu_to_code(dfu_config): | ||||
|     cg.add_define("USE_NRF52_DFU") | ||||
|     var = cg.new_Pvariable(dfu_config[CONF_ID]) | ||||
|     pin = await cg.gpio_pin_expression(dfu_config[CONF_RESET_PIN]) | ||||
|     cg.add(var.set_reset_pin(pin)) | ||||
|     zephyr_add_prj_conf("CDC_ACM_DTE_RATE_CALLBACK_SUPPORT", True) | ||||
|     await cg.register_component(var, dfu_config) | ||||
|  | ||||
|  | ||||
| def copy_files() -> None: | ||||
|     """Copy files to the build directory.""" | ||||
|   | ||||
| @@ -2,6 +2,7 @@ BOOTLOADER_ADAFRUIT = "adafruit" | ||||
| BOOTLOADER_ADAFRUIT_NRF52_SD132 = "adafruit_nrf52_sd132" | ||||
| BOOTLOADER_ADAFRUIT_NRF52_SD140_V6 = "adafruit_nrf52_sd140_v6" | ||||
| BOOTLOADER_ADAFRUIT_NRF52_SD140_V7 = "adafruit_nrf52_sd140_v7" | ||||
|  | ||||
| EXTRA_ADC = [ | ||||
|     "VDD", | ||||
|     "VDDHDIV5", | ||||
|   | ||||
							
								
								
									
										51
									
								
								esphome/components/nrf52/dfu.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								esphome/components/nrf52/dfu.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| #include "dfu.h" | ||||
|  | ||||
| #ifdef USE_NRF52_DFU | ||||
|  | ||||
| #include <zephyr/device.h> | ||||
| #include <zephyr/drivers/uart.h> | ||||
| #include <zephyr/drivers/uart/cdc_acm.h> | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace nrf52 { | ||||
|  | ||||
| static const char *const TAG = "dfu"; | ||||
|  | ||||
| volatile bool goto_dfu = false;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||
|  | ||||
| static const uint32_t DFU_DBL_RESET_MAGIC = 0x5A1AD5;  // SALADS | ||||
|  | ||||
| #define DEVICE_AND_COMMA(node_id) DEVICE_DT_GET(node_id), | ||||
|  | ||||
| static void cdc_dte_rate_callback(const struct device * /*unused*/, uint32_t rate) { | ||||
|   if (rate == 1200) { | ||||
|     goto_dfu = true; | ||||
|   } | ||||
| } | ||||
| void DeviceFirmwareUpdate::setup() { | ||||
|   this->reset_pin_->setup(); | ||||
|   const struct device *cdc_dev[] = {DT_FOREACH_STATUS_OKAY(zephyr_cdc_acm_uart, DEVICE_AND_COMMA)}; | ||||
|   for (auto &idx : cdc_dev) { | ||||
|     cdc_acm_dte_rate_callback_set(idx, cdc_dte_rate_callback); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void DeviceFirmwareUpdate::loop() { | ||||
|   if (goto_dfu) { | ||||
|     goto_dfu = false; | ||||
|     volatile uint32_t *dbl_reset_mem = (volatile uint32_t *) 0x20007F7C; | ||||
|     (*dbl_reset_mem) = DFU_DBL_RESET_MAGIC; | ||||
|     this->reset_pin_->digital_write(true); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void DeviceFirmwareUpdate::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "DFU:"); | ||||
|   LOG_PIN("  RESET Pin: ", this->reset_pin_); | ||||
| } | ||||
|  | ||||
| }  // namespace nrf52 | ||||
| }  // namespace esphome | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										24
									
								
								esphome/components/nrf52/dfu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								esphome/components/nrf52/dfu.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/defines.h" | ||||
| #ifdef USE_NRF52_DFU | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/gpio.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace nrf52 { | ||||
| class DeviceFirmwareUpdate : public Component { | ||||
|  public: | ||||
|   void setup() override; | ||||
|   void loop() override; | ||||
|   void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; } | ||||
|   void dump_config() override; | ||||
|  | ||||
|  protected: | ||||
|   GPIOPin *reset_pin_; | ||||
| }; | ||||
|  | ||||
| }  // namespace nrf52 | ||||
| }  // namespace esphome | ||||
|  | ||||
| #endif | ||||
| @@ -76,7 +76,7 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_WIND_DIRECTION, | ||||
|     DEVICE_CLASS_WIND_SPEED, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -321,7 +321,7 @@ async def number_in_range_to_code(config, condition_id, template_arg, args): | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(number_ns.using) | ||||
|  | ||||
|   | ||||
| @@ -14,16 +14,16 @@ void log_number(const char *tag, const char *prefix, const char *type, Number *o | ||||
|  | ||||
|   ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str()); | ||||
|  | ||||
|   if (!obj->get_icon().empty()) { | ||||
|     ESP_LOGCONFIG(tag, "%s  Icon: '%s'", prefix, obj->get_icon().c_str()); | ||||
|   if (!obj->get_icon_ref().empty()) { | ||||
|     ESP_LOGCONFIG(tag, "%s  Icon: '%s'", prefix, obj->get_icon_ref().c_str()); | ||||
|   } | ||||
|  | ||||
|   if (!obj->traits.get_unit_of_measurement().empty()) { | ||||
|     ESP_LOGCONFIG(tag, "%s  Unit of Measurement: '%s'", prefix, obj->traits.get_unit_of_measurement().c_str()); | ||||
|   } | ||||
|  | ||||
|   if (!obj->traits.get_device_class().empty()) { | ||||
|     ESP_LOGCONFIG(tag, "%s  Device Class: '%s'", prefix, obj->traits.get_device_class().c_str()); | ||||
|   if (!obj->traits.get_device_class_ref().empty()) { | ||||
|     ESP_LOGCONFIG(tag, "%s  Device Class: '%s'", prefix, obj->traits.get_device_class_ref().c_str()); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -10,7 +10,7 @@ from esphome.const import ( | ||||
|     CONF_TRIGGER_ID, | ||||
|     PlatformFramework, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
|  | ||||
| CODEOWNERS = ["@esphome/core"] | ||||
| AUTO_LOAD = ["md5", "safe_mode"] | ||||
| @@ -82,7 +82,7 @@ BASE_OTA_SCHEMA = cv.Schema( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(54.0) | ||||
| @coroutine_with_priority(CoroPriority.COMMUNICATION) | ||||
| async def to_code(config): | ||||
|     cg.add_define("USE_OTA") | ||||
|  | ||||
|   | ||||
| @@ -18,7 +18,7 @@ from esphome.const import ( | ||||
|     PLATFORM_RP2040, | ||||
|     ThreadModel, | ||||
| ) | ||||
| from esphome.core import CORE, EsphomeError, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, EsphomeError, coroutine_with_priority | ||||
| from esphome.helpers import copy_file_if_changed, mkdir_p, read_file, write_file | ||||
|  | ||||
| from .const import KEY_BOARD, KEY_PIO_FILES, KEY_RP2040, rp2040_ns | ||||
| @@ -159,7 +159,7 @@ CONFIG_SCHEMA = cv.All( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(1000) | ||||
| @coroutine_with_priority(CoroPriority.PLATFORM) | ||||
| async def to_code(config): | ||||
|     cg.add(rp2040_ns.setup_preferences()) | ||||
|  | ||||
|   | ||||
| @@ -10,7 +10,7 @@ from esphome.const import ( | ||||
|     CONF_TRIGGER_ID, | ||||
|     KEY_PAST_SAFE_MODE, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.cpp_generator import RawExpression | ||||
|  | ||||
| CODEOWNERS = ["@paulmonigatti", "@jsuanet", "@kbx81"] | ||||
| @@ -53,7 +53,7 @@ CONFIG_SCHEMA = cv.All( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(50.0) | ||||
| @coroutine_with_priority(CoroPriority.APPLICATION) | ||||
| async def to_code(config): | ||||
|     if not config[CONF_DISABLED]: | ||||
|         var = cg.new_Pvariable(config[CONF_ID]) | ||||
|   | ||||
| @@ -16,7 +16,7 @@ from esphome.const import ( | ||||
|     CONF_TRIGGER_ID, | ||||
|     CONF_WEB_SERVER, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -124,7 +124,7 @@ async def new_select(config, *args, options: list[str]): | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(select_ns.using) | ||||
|  | ||||
|   | ||||
| @@ -12,8 +12,8 @@ namespace select { | ||||
| #define LOG_SELECT(prefix, type, obj) \ | ||||
|   if ((obj) != nullptr) { \ | ||||
|     ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ | ||||
|     if (!(obj)->get_icon().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ | ||||
|     if (!(obj)->get_icon_ref().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \ | ||||
|     } \ | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -101,7 +101,7 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_WIND_SPEED, | ||||
|     ENTITY_CATEGORY_CONFIG, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
| from esphome.util import Registry | ||||
| @@ -1142,6 +1142,6 @@ def _lstsq(a, b): | ||||
|     return _mat_dot(_mat_dot(x, a_t), b) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(sensor_ns.using) | ||||
|   | ||||
| @@ -17,15 +17,15 @@ void log_sensor(const char *tag, const char *prefix, const char *type, Sensor *o | ||||
|                 "%s  State Class: '%s'\n" | ||||
|                 "%s  Unit of Measurement: '%s'\n" | ||||
|                 "%s  Accuracy Decimals: %d", | ||||
|                 prefix, type, obj->get_name().c_str(), prefix, state_class_to_string(obj->get_state_class()).c_str(), | ||||
|                 prefix, obj->get_unit_of_measurement().c_str(), prefix, obj->get_accuracy_decimals()); | ||||
|                 prefix, type, obj->get_name().c_str(), prefix, state_class_to_string(obj->get_state_class()), prefix, | ||||
|                 obj->get_unit_of_measurement().c_str(), prefix, obj->get_accuracy_decimals()); | ||||
|  | ||||
|   if (!obj->get_device_class().empty()) { | ||||
|     ESP_LOGCONFIG(tag, "%s  Device Class: '%s'", prefix, obj->get_device_class().c_str()); | ||||
|   if (!obj->get_device_class_ref().empty()) { | ||||
|     ESP_LOGCONFIG(tag, "%s  Device Class: '%s'", prefix, obj->get_device_class_ref().c_str()); | ||||
|   } | ||||
|  | ||||
|   if (!obj->get_icon().empty()) { | ||||
|     ESP_LOGCONFIG(tag, "%s  Icon: '%s'", prefix, obj->get_icon().c_str()); | ||||
|   if (!obj->get_icon_ref().empty()) { | ||||
|     ESP_LOGCONFIG(tag, "%s  Icon: '%s'", prefix, obj->get_icon_ref().c_str()); | ||||
|   } | ||||
|  | ||||
|   if (obj->get_force_update()) { | ||||
| @@ -33,7 +33,7 @@ void log_sensor(const char *tag, const char *prefix, const char *type, Sensor *o | ||||
|   } | ||||
| } | ||||
|  | ||||
| std::string state_class_to_string(StateClass state_class) { | ||||
| const char *state_class_to_string(StateClass state_class) { | ||||
|   switch (state_class) { | ||||
|     case STATE_CLASS_MEASUREMENT: | ||||
|       return "measurement"; | ||||
|   | ||||
| @@ -33,7 +33,7 @@ enum StateClass : uint8_t { | ||||
|   STATE_CLASS_TOTAL = 3, | ||||
| }; | ||||
|  | ||||
| std::string state_class_to_string(StateClass state_class); | ||||
| const char *state_class_to_string(StateClass state_class); | ||||
|  | ||||
| /** Base-class for all sensors. | ||||
|  * | ||||
|   | ||||
| @@ -14,8 +14,13 @@ namespace sntp { | ||||
|  | ||||
| static const char *const TAG = "sntp"; | ||||
|  | ||||
| #if defined(USE_ESP32) | ||||
| SNTPComponent *SNTPComponent::instance = nullptr;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||
| #endif | ||||
|  | ||||
| void SNTPComponent::setup() { | ||||
| #if defined(USE_ESP32) | ||||
|   SNTPComponent::instance = this; | ||||
|   if (esp_sntp_enabled()) { | ||||
|     esp_sntp_stop(); | ||||
|   } | ||||
| @@ -25,6 +30,11 @@ void SNTPComponent::setup() { | ||||
|     esp_sntp_setservername(i++, server.c_str()); | ||||
|   } | ||||
|   esp_sntp_set_sync_interval(this->get_update_interval()); | ||||
|   esp_sntp_set_time_sync_notification_cb([](struct timeval *tv) { | ||||
|     if (SNTPComponent::instance != nullptr) { | ||||
|       SNTPComponent::instance->defer([]() { SNTPComponent::instance->time_synced(); }); | ||||
|     } | ||||
|   }); | ||||
|   esp_sntp_init(); | ||||
| #else | ||||
|   sntp_stop(); | ||||
| @@ -34,6 +44,14 @@ void SNTPComponent::setup() { | ||||
|   for (auto &server : this->servers_) { | ||||
|     sntp_setservername(i++, server.c_str()); | ||||
|   } | ||||
|  | ||||
| #if defined(USE_ESP8266) | ||||
|   settimeofday_cb([this](bool from_sntp) { | ||||
|     if (from_sntp) | ||||
|       this->time_synced(); | ||||
|   }); | ||||
| #endif | ||||
|  | ||||
|   sntp_init(); | ||||
| #endif | ||||
| } | ||||
| @@ -46,7 +64,8 @@ void SNTPComponent::dump_config() { | ||||
| } | ||||
| void SNTPComponent::update() { | ||||
| #if !defined(USE_ESP32) | ||||
|   // force resync | ||||
|   // Some platforms currently cannot set the sync interval at runtime so we need | ||||
|   // to do the re-sync by hand for now. | ||||
|   if (sntp_enabled()) { | ||||
|     sntp_stop(); | ||||
|     this->has_time_ = false; | ||||
| @@ -55,23 +74,31 @@ void SNTPComponent::update() { | ||||
| #endif | ||||
| } | ||||
| void SNTPComponent::loop() { | ||||
| // The loop is used to infer whether we have valid time on platforms where we | ||||
| // cannot tell whether SNTP has succeeded. | ||||
| // One limitation of this approach is that we cannot tell if it was the SNTP | ||||
| // component that set the time. | ||||
| // ESP-IDF and ESP8266 use callbacks from the SNTP task to trigger the | ||||
| // `on_time_sync` trigger on successful sync events. | ||||
| #if defined(USE_ESP32) || defined(USE_ESP8266) | ||||
|   this->disable_loop(); | ||||
| #endif | ||||
|  | ||||
|   if (this->has_time_) | ||||
|     return; | ||||
|  | ||||
|   this->time_synced(); | ||||
| } | ||||
|  | ||||
| void SNTPComponent::time_synced() { | ||||
|   auto time = this->now(); | ||||
|   if (!time.is_valid()) | ||||
|   this->has_time_ = time.is_valid(); | ||||
|   if (!this->has_time_) | ||||
|     return; | ||||
|  | ||||
|   ESP_LOGD(TAG, "Synchronized time: %04d-%02d-%02d %02d:%02d:%02d", time.year, time.month, time.day_of_month, time.hour, | ||||
|            time.minute, time.second); | ||||
|   this->time_sync_callback_.call(); | ||||
|   this->has_time_ = true; | ||||
|  | ||||
| #ifdef USE_ESP_IDF | ||||
|   // On ESP-IDF, time sync is permanent and update() doesn't force resync | ||||
|   // Time is now synchronized, no need to check anymore | ||||
|   this->disable_loop(); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| }  // namespace sntp | ||||
|   | ||||
| @@ -26,9 +26,16 @@ class SNTPComponent : public time::RealTimeClock { | ||||
|   void update() override; | ||||
|   void loop() override; | ||||
|  | ||||
|   void time_synced(); | ||||
|  | ||||
|  protected: | ||||
|   std::vector<std::string> servers_; | ||||
|   bool has_time_{false}; | ||||
|  | ||||
| #if defined(USE_ESP32) | ||||
|  private: | ||||
|   static SNTPComponent *instance; | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| }  // namespace sntp | ||||
|   | ||||
| @@ -4,7 +4,7 @@ from esphome.components import audio, audio_dac | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_DATA, CONF_ID, CONF_VOLUME | ||||
| from esphome.core import CORE | ||||
| from esphome.coroutine import coroutine_with_priority | ||||
| from esphome.coroutine import CoroPriority, coroutine_with_priority | ||||
|  | ||||
| AUTO_LOAD = ["audio"] | ||||
| CODEOWNERS = ["@jesserockz", "@kahrendt"] | ||||
| @@ -138,7 +138,7 @@ async def speaker_mute_action_to_code(config, action_id, template_arg, args): | ||||
|     return cg.new_Pvariable(action_id, template_arg, paren) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(speaker_ns.using) | ||||
|     cg.add_define("USE_SPEAKER") | ||||
|   | ||||
| @@ -35,7 +35,7 @@ from esphome.const import ( | ||||
|     PLATFORM_RP2040, | ||||
|     PlatformFramework, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| import esphome.final_validate as fv | ||||
|  | ||||
| CODEOWNERS = ["@esphome/core", "@clydebarrow"] | ||||
| @@ -351,7 +351,7 @@ CONFIG_SCHEMA = cv.All( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(1.0) | ||||
| @coroutine_with_priority(CoroPriority.BUS) | ||||
| async def to_code(configs): | ||||
|     cg.add_define("USE_SPI") | ||||
|     cg.add_global(spi_ns.using) | ||||
|   | ||||
| @@ -2,7 +2,7 @@ from esphome import pins | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID, CONF_PIN | ||||
| from esphome.core import coroutine_with_priority | ||||
| from esphome.core import CoroPriority, coroutine_with_priority | ||||
|  | ||||
| status_led_ns = cg.esphome_ns.namespace("status_led") | ||||
| StatusLED = status_led_ns.class_("StatusLED", cg.Component) | ||||
| @@ -15,7 +15,7 @@ CONFIG_SCHEMA = cv.Schema( | ||||
| ).extend(cv.COMPONENT_SCHEMA) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(80.0) | ||||
| @coroutine_with_priority(CoroPriority.STATUS) | ||||
| async def to_code(config): | ||||
|     pin = await cg.gpio_pin_expression(config[CONF_PIN]) | ||||
|     rhs = StatusLED.new(pin) | ||||
|   | ||||
| @@ -10,7 +10,7 @@ from esphome.const import ( | ||||
|     CONF_SPEED, | ||||
|     CONF_TARGET, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
|  | ||||
| IS_PLATFORM_COMPONENT = True | ||||
|  | ||||
| @@ -178,6 +178,6 @@ async def stepper_set_deceleration_to_code(config, action_id, template_arg, args | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(stepper_ns.using) | ||||
|   | ||||
| @@ -21,7 +21,7 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_OUTLET, | ||||
|     DEVICE_CLASS_SWITCH, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -230,6 +230,6 @@ async def switch_is_off_to_code(config, condition_id, template_arg, args): | ||||
|     return cg.new_Pvariable(condition_id, template_arg, paren, False) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(switch_ns.using) | ||||
|   | ||||
| @@ -91,8 +91,8 @@ void log_switch(const char *tag, const char *prefix, const char *type, Switch *o | ||||
|                   LOG_STR_ARG(onoff)); | ||||
|  | ||||
|     // Add optional fields separately | ||||
|     if (!obj->get_icon().empty()) { | ||||
|       ESP_LOGCONFIG(tag, "%s  Icon: '%s'", prefix, obj->get_icon().c_str()); | ||||
|     if (!obj->get_icon_ref().empty()) { | ||||
|       ESP_LOGCONFIG(tag, "%s  Icon: '%s'", prefix, obj->get_icon_ref().c_str()); | ||||
|     } | ||||
|     if (obj->assumed_state()) { | ||||
|       ESP_LOGCONFIG(tag, "%s  Assumed State: YES", prefix); | ||||
| @@ -100,8 +100,8 @@ void log_switch(const char *tag, const char *prefix, const char *type, Switch *o | ||||
|     if (obj->is_inverted()) { | ||||
|       ESP_LOGCONFIG(tag, "%s  Inverted: YES", prefix); | ||||
|     } | ||||
|     if (!obj->get_device_class().empty()) { | ||||
|       ESP_LOGCONFIG(tag, "%s  Device Class: '%s'", prefix, obj->get_device_class().c_str()); | ||||
|     if (!obj->get_device_class_ref().empty()) { | ||||
|       ESP_LOGCONFIG(tag, "%s  Device Class: '%s'", prefix, obj->get_device_class_ref().c_str()); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -13,7 +13,7 @@ from esphome.const import ( | ||||
|     CONF_VALUE, | ||||
|     CONF_WEB_SERVER, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -149,7 +149,7 @@ async def new_text( | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(text_ns.using) | ||||
|  | ||||
|   | ||||
| @@ -12,8 +12,8 @@ namespace text { | ||||
| #define LOG_TEXT(prefix, type, obj) \ | ||||
|   if ((obj) != nullptr) { \ | ||||
|     ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ | ||||
|     if (!(obj)->get_icon().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ | ||||
|     if (!(obj)->get_icon_ref().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \ | ||||
|     } \ | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -20,7 +20,7 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_EMPTY, | ||||
|     DEVICE_CLASS_TIMESTAMP, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
| from esphome.util import Registry | ||||
| @@ -230,7 +230,7 @@ async def new_text_sensor(config, *args): | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(text_sensor_ns.using) | ||||
|  | ||||
|   | ||||
| @@ -14,11 +14,11 @@ namespace text_sensor { | ||||
| #define LOG_TEXT_SENSOR(prefix, type, obj) \ | ||||
|   if ((obj) != nullptr) { \ | ||||
|     ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ | ||||
|     if (!(obj)->get_device_class().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Device Class: '%s'", prefix, (obj)->get_device_class().c_str()); \ | ||||
|     if (!(obj)->get_device_class_ref().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Device Class: '%s'", prefix, (obj)->get_device_class_ref().c_str()); \ | ||||
|     } \ | ||||
|     if (!(obj)->get_icon().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ | ||||
|     if (!(obj)->get_icon_ref().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \ | ||||
|     } \ | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -26,7 +26,7 @@ from esphome.const import ( | ||||
|     CONF_TIMEZONE, | ||||
|     CONF_TRIGGER_ID, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
|  | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | ||||
| @@ -340,7 +340,7 @@ async def register_time(time_var, config): | ||||
|     await setup_time_core_(time_var, config) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     if CORE.using_zephyr: | ||||
|         zephyr_add_prj_conf("POSIX_CLOCK", True) | ||||
|   | ||||
| @@ -13,7 +13,7 @@ from esphome.const import ( | ||||
|     CONF_SWAP_XY, | ||||
|     CONF_TRANSFORM, | ||||
| ) | ||||
| from esphome.core import coroutine_with_priority | ||||
| from esphome.core import CoroPriority, coroutine_with_priority | ||||
|  | ||||
| CODEOWNERS = ["@jesserockz", "@nielsnl68"] | ||||
| DEPENDENCIES = ["display"] | ||||
| @@ -152,7 +152,7 @@ async def register_touchscreen(var, config): | ||||
|         ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(touchscreen_ns.using) | ||||
|     cg.add_define("USE_TOUCHSCREEN") | ||||
|   | ||||
| @@ -14,7 +14,7 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_FIRMWARE, | ||||
|     ENTITY_CATEGORY_CONFIG, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -124,7 +124,7 @@ async def new_update(config): | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(update_ns.using) | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,7 @@ from esphome.const import ( | ||||
|     DEVICE_CLASS_GAS, | ||||
|     DEVICE_CLASS_WATER, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity | ||||
| from esphome.cpp_generator import MockObjClass | ||||
|  | ||||
| @@ -233,6 +233,6 @@ async def valve_control_to_code(config, action_id, template_arg, args): | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config): | ||||
|     cg.add_global(valve_ns.using) | ||||
|   | ||||
| @@ -19,8 +19,8 @@ const extern float VALVE_CLOSED; | ||||
|     if (traits_.get_is_assumed_state()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Assumed State: YES", prefix); \ | ||||
|     } \ | ||||
|     if (!(obj)->get_device_class().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Device Class: '%s'", prefix, (obj)->get_device_class().c_str()); \ | ||||
|     if (!(obj)->get_device_class_ref().empty()) { \ | ||||
|       ESP_LOGCONFIG(TAG, "%s  Device Class: '%s'", prefix, (obj)->get_device_class_ref().c_str()); \ | ||||
|     } \ | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -31,7 +31,7 @@ from esphome.const import ( | ||||
|     PLATFORM_LN882X, | ||||
|     PLATFORM_RTL87XX, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| import esphome.final_validate as fv | ||||
| from esphome.types import ConfigType | ||||
|  | ||||
| @@ -269,7 +269,7 @@ def add_resource_as_progmem( | ||||
|     cg.add_global(cg.RawExpression(size_t)) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(40.0) | ||||
| @coroutine_with_priority(CoroPriority.WEB) | ||||
| async def to_code(config): | ||||
|     paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,7 @@ from esphome.components.esp32 import add_idf_component | ||||
| from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
|  | ||||
| CODEOWNERS = ["@esphome/core"] | ||||
| DEPENDENCIES = ["network", "web_server_base"] | ||||
| @@ -22,7 +22,7 @@ CONFIG_SCHEMA = ( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(52.0) | ||||
| @coroutine_with_priority(CoroPriority.COMMUNICATION) | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await ota_to_code(var, config) | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
|  | ||||
| CODEOWNERS = ["@esphome/core"] | ||||
| DEPENDENCIES = ["network"] | ||||
| @@ -26,7 +26,7 @@ CONFIG_SCHEMA = cv.Schema( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(65.0) | ||||
| @coroutine_with_priority(CoroPriority.COMMUNICATION) | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await cg.register_component(var, config) | ||||
|   | ||||
| @@ -44,7 +44,7 @@ from esphome.const import ( | ||||
|     CONF_USERNAME, | ||||
|     PlatformFramework, | ||||
| ) | ||||
| from esphome.core import CORE, HexInt, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, HexInt, coroutine_with_priority | ||||
| import esphome.final_validate as fv | ||||
|  | ||||
| from . import wpa2_eap | ||||
| @@ -370,7 +370,7 @@ def wifi_network(config, ap, static_ip): | ||||
|     return ap | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(60.0) | ||||
| @coroutine_with_priority(CoroPriority.COMMUNICATION) | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     cg.add(var.set_use_address(config[CONF_USE_ADDRESS])) | ||||
|   | ||||
| @@ -654,12 +654,14 @@ const char *get_disconnect_reason_str(uint8_t reason) { | ||||
|       return "Association comeback time too long"; | ||||
|     case WIFI_REASON_SA_QUERY_TIMEOUT: | ||||
|       return "SA query timeout"; | ||||
| #if (ESP_IDF_VERSION_MAJOR >= 5) && (ESP_IDF_VERSION_MINOR >= 2) | ||||
|     case WIFI_REASON_NO_AP_FOUND_W_COMPATIBLE_SECURITY: | ||||
|       return "No AP found with compatible security"; | ||||
|     case WIFI_REASON_NO_AP_FOUND_IN_AUTHMODE_THRESHOLD: | ||||
|       return "No AP found in auth mode threshold"; | ||||
|     case WIFI_REASON_NO_AP_FOUND_IN_RSSI_THRESHOLD: | ||||
|       return "No AP found in RSSI threshold"; | ||||
| #endif | ||||
|     case WIFI_REASON_UNSPECIFIED: | ||||
|     default: | ||||
|       return "Unspecified"; | ||||
|   | ||||
| @@ -29,6 +29,7 @@ from esphome.const import ( | ||||
|  | ||||
| # pylint: disable=unused-import | ||||
| from esphome.coroutine import (  # noqa: F401 | ||||
|     CoroPriority, | ||||
|     FakeAwaitable as _FakeAwaitable, | ||||
|     FakeEventLoop as _FakeEventLoop, | ||||
|     coroutine, | ||||
|   | ||||
| @@ -39,7 +39,7 @@ from esphome.const import ( | ||||
|     PlatformFramework, | ||||
|     __version__ as ESPHOME_VERSION, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.core import CORE, CoroPriority, coroutine_with_priority | ||||
| from esphome.helpers import ( | ||||
|     copy_file_if_changed, | ||||
|     fnv1a_32bit_hash, | ||||
| @@ -359,7 +359,7 @@ ARDUINO_GLUE_CODE = """\ | ||||
| """ | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(-999.0) | ||||
| @coroutine_with_priority(CoroPriority.WORKAROUNDS) | ||||
| async def add_arduino_global_workaround(): | ||||
|     # The Arduino framework defined these itself in the global | ||||
|     # namespace. For the esphome codebase that is not a problem, | ||||
| @@ -376,7 +376,7 @@ async def add_arduino_global_workaround(): | ||||
|         cg.add_global(cg.RawStatement(line)) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(-1000.0) | ||||
| @coroutine_with_priority(CoroPriority.FINAL) | ||||
| async def add_includes(includes): | ||||
|     # Add includes at the very end, so that the included files can access global variables | ||||
|     for include in includes: | ||||
| @@ -392,7 +392,7 @@ async def add_includes(includes): | ||||
|             include_file(path, basename) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(-1000.0) | ||||
| @coroutine_with_priority(CoroPriority.FINAL) | ||||
| async def _add_platformio_options(pio_options): | ||||
|     # Add includes at the very end, so that they override everything | ||||
|     for key, val in pio_options.items(): | ||||
| @@ -401,7 +401,7 @@ async def _add_platformio_options(pio_options): | ||||
|         cg.add_platformio_option(key, val) | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(30.0) | ||||
| @coroutine_with_priority(CoroPriority.AUTOMATION) | ||||
| async def _add_automations(config): | ||||
|     for conf in config.get(CONF_ON_BOOT, []): | ||||
|         trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], conf.get(CONF_PRIORITY)) | ||||
| @@ -423,7 +423,7 @@ async def _add_automations(config): | ||||
| DATETIME_SUBTYPES = {"date", "time", "datetime"} | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(-100.0) | ||||
| @coroutine_with_priority(CoroPriority.FINAL) | ||||
| async def _add_platform_defines() -> None: | ||||
|     # Generate compile-time defines for platforms that have actual entities | ||||
|     # Only add USE_* and count defines when there are entities | ||||
| @@ -442,7 +442,7 @@ async def _add_platform_defines() -> None: | ||||
|             cg.add_define(f"USE_{platform_name.upper()}") | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(100.0) | ||||
| @coroutine_with_priority(CoroPriority.CORE) | ||||
| async def to_code(config: ConfigType) -> None: | ||||
|     cg.add_global(cg.global_ns.namespace("esphome").using) | ||||
|     # These can be used by user lambdas, put them to default scope | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user