mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-22 11:43:51 +01:00 
			
		
		
		
	[scheduler] Properly handle millis() overflow (#8197)
This commit is contained in:
		| @@ -196,6 +196,7 @@ CONF_DC_PIN = "dc_pin" | |||||||
| CONF_DEASSERT_RTS_DTR = "deassert_rts_dtr" | CONF_DEASSERT_RTS_DTR = "deassert_rts_dtr" | ||||||
| CONF_DEBOUNCE = "debounce" | CONF_DEBOUNCE = "debounce" | ||||||
| CONF_DEBUG = "debug" | CONF_DEBUG = "debug" | ||||||
|  | CONF_DEBUG_SCHEDULER = "debug_scheduler" | ||||||
| CONF_DECAY_MODE = "decay_mode" | CONF_DECAY_MODE = "decay_mode" | ||||||
| CONF_DECELERATION = "deceleration" | CONF_DECELERATION = "deceleration" | ||||||
| CONF_DEFAULT_MODE = "default_mode" | CONF_DEFAULT_MODE = "default_mode" | ||||||
|   | |||||||
| @@ -165,10 +165,17 @@ class Component { | |||||||
|    * This will call f every interval ms. Can be cancelled via CancelInterval(). |    * This will call f every interval ms. Can be cancelled via CancelInterval(). | ||||||
|    * Similar to javascript's setInterval(). |    * Similar to javascript's setInterval(). | ||||||
|    * |    * | ||||||
|    * IMPORTANT: Do not rely on this having correct timing. This is only called from |    * IMPORTANT NOTE: | ||||||
|    * loop() and therefore can be significantly delay. If you need exact timing please |    * The only guarantee offered by this call is that the callback will be called no *earlier* than | ||||||
|  |    * the specified interval after the previous call. Any given interval may be longer due to | ||||||
|  |    * other components blocking the loop() call. | ||||||
|  |    * | ||||||
|  |    * So do not rely on this having correct timing. If you need exact timing please | ||||||
|    * use hardware timers. |    * use hardware timers. | ||||||
|    * |    * | ||||||
|  |    * Note also that the first call to f will not happen immediately, but after a random delay. This is | ||||||
|  |    * intended to prevent many interval functions from being called at the same time. | ||||||
|  |    * | ||||||
|    * @param name The identifier for this interval function. |    * @param name The identifier for this interval function. | ||||||
|    * @param interval The interval in ms. |    * @param interval The interval in ms. | ||||||
|    * @param f The function (or lambda) that should be called |    * @param f The function (or lambda) that should be called | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ from esphome.const import ( | |||||||
|     CONF_BUILD_PATH, |     CONF_BUILD_PATH, | ||||||
|     CONF_COMMENT, |     CONF_COMMENT, | ||||||
|     CONF_COMPILE_PROCESS_LIMIT, |     CONF_COMPILE_PROCESS_LIMIT, | ||||||
|  |     CONF_DEBUG_SCHEDULER, | ||||||
|     CONF_ESPHOME, |     CONF_ESPHOME, | ||||||
|     CONF_FRIENDLY_NAME, |     CONF_FRIENDLY_NAME, | ||||||
|     CONF_INCLUDES, |     CONF_INCLUDES, | ||||||
| @@ -144,6 +145,7 @@ CONFIG_SCHEMA = cv.All( | |||||||
|             cv.Optional(CONF_INCLUDES, default=[]): cv.ensure_list(valid_include), |             cv.Optional(CONF_INCLUDES, default=[]): cv.ensure_list(valid_include), | ||||||
|             cv.Optional(CONF_LIBRARIES, default=[]): cv.ensure_list(cv.string_strict), |             cv.Optional(CONF_LIBRARIES, default=[]): cv.ensure_list(cv.string_strict), | ||||||
|             cv.Optional(CONF_NAME_ADD_MAC_SUFFIX, default=False): cv.boolean, |             cv.Optional(CONF_NAME_ADD_MAC_SUFFIX, default=False): cv.boolean, | ||||||
|  |             cv.Optional(CONF_DEBUG_SCHEDULER, default=False): cv.boolean, | ||||||
|             cv.Optional(CONF_PROJECT): cv.Schema( |             cv.Optional(CONF_PROJECT): cv.Schema( | ||||||
|                 { |                 { | ||||||
|                     cv.Required(CONF_NAME): cv.All( |                     cv.Required(CONF_NAME): cv.All( | ||||||
| @@ -369,6 +371,8 @@ async def to_code(config): | |||||||
|     cg.add_build_flag("-Wno-unused-variable") |     cg.add_build_flag("-Wno-unused-variable") | ||||||
|     cg.add_build_flag("-Wno-unused-but-set-variable") |     cg.add_build_flag("-Wno-unused-but-set-variable") | ||||||
|     cg.add_build_flag("-Wno-sign-compare") |     cg.add_build_flag("-Wno-sign-compare") | ||||||
|  |     if config[CONF_DEBUG_SCHEDULER]: | ||||||
|  |         cg.add_define("ESPHOME_DEBUG_SCHEDULER") | ||||||
|  |  | ||||||
|     if CORE.using_arduino and not CORE.is_bk72xx: |     if CORE.using_arduino and not CORE.is_bk72xx: | ||||||
|         CORE.add_job(add_arduino_global_workaround) |         CORE.add_job(add_arduino_global_workaround) | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ | |||||||
| #define ESPHOME_PROJECT_VERSION "v2" | #define ESPHOME_PROJECT_VERSION "v2" | ||||||
| #define ESPHOME_PROJECT_VERSION_30 "v2" | #define ESPHOME_PROJECT_VERSION_30 "v2" | ||||||
| #define ESPHOME_VARIANT "ESP32" | #define ESPHOME_VARIANT "ESP32" | ||||||
|  | #define ESPHOME_DEBUG_SCHEDULER | ||||||
|  |  | ||||||
| // logger | // logger | ||||||
| #define ESPHOME_LOG_LEVEL ESPHOME_LOG_LEVEL_VERY_VERBOSE | #define ESPHOME_LOG_LEVEL ESPHOME_LOG_LEVEL_VERY_VERBOSE | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| #include "scheduler.h" | #include "scheduler.h" | ||||||
|  | #include "esphome/core/defines.h" | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
| #include "esphome/core/helpers.h" | #include "esphome/core/helpers.h" | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
| @@ -21,7 +22,7 @@ static const uint32_t MAX_LOGICALLY_DELETED_ITEMS = 10; | |||||||
|  |  | ||||||
| void HOT Scheduler::set_timeout(Component *component, const std::string &name, uint32_t timeout, | void HOT Scheduler::set_timeout(Component *component, const std::string &name, uint32_t timeout, | ||||||
|                                 std::function<void()> func) { |                                 std::function<void()> func) { | ||||||
|   const uint32_t now = this->millis_(); |   const auto now = this->millis_(); | ||||||
|  |  | ||||||
|   if (!name.empty()) |   if (!name.empty()) | ||||||
|     this->cancel_timeout(component, name); |     this->cancel_timeout(component, name); | ||||||
| @@ -29,17 +30,16 @@ void HOT Scheduler::set_timeout(Component *component, const std::string &name, u | |||||||
|   if (timeout == SCHEDULER_DONT_RUN) |   if (timeout == SCHEDULER_DONT_RUN) | ||||||
|     return; |     return; | ||||||
|  |  | ||||||
|   ESP_LOGVV(TAG, "set_timeout(name='%s', timeout=%" PRIu32 ")", name.c_str(), timeout); |  | ||||||
|  |  | ||||||
|   auto item = make_unique<SchedulerItem>(); |   auto item = make_unique<SchedulerItem>(); | ||||||
|   item->component = component; |   item->component = component; | ||||||
|   item->name = name; |   item->name = name; | ||||||
|   item->type = SchedulerItem::TIMEOUT; |   item->type = SchedulerItem::TIMEOUT; | ||||||
|   item->timeout = timeout; |   item->next_execution_ = now + timeout; | ||||||
|   item->last_execution = now; |  | ||||||
|   item->last_execution_major = this->millis_major_; |  | ||||||
|   item->callback = std::move(func); |   item->callback = std::move(func); | ||||||
|   item->remove = false; |   item->remove = false; | ||||||
|  | #ifdef ESPHOME_DEBUG_SCHEDULER | ||||||
|  |   ESP_LOGD(TAG, "set_timeout(name='%s/%s', timeout=%" PRIu32 ")", item->get_source(), name.c_str(), timeout); | ||||||
|  | #endif | ||||||
|   this->push_(std::move(item)); |   this->push_(std::move(item)); | ||||||
| } | } | ||||||
| bool HOT Scheduler::cancel_timeout(Component *component, const std::string &name) { | bool HOT Scheduler::cancel_timeout(Component *component, const std::string &name) { | ||||||
| @@ -47,7 +47,7 @@ bool HOT Scheduler::cancel_timeout(Component *component, const std::string &name | |||||||
| } | } | ||||||
| void HOT Scheduler::set_interval(Component *component, const std::string &name, uint32_t interval, | void HOT Scheduler::set_interval(Component *component, const std::string &name, uint32_t interval, | ||||||
|                                  std::function<void()> func) { |                                  std::function<void()> func) { | ||||||
|   const uint32_t now = this->millis_(); |   const auto now = this->millis_(); | ||||||
|  |  | ||||||
|   if (!name.empty()) |   if (!name.empty()) | ||||||
|     this->cancel_interval(component, name); |     this->cancel_interval(component, name); | ||||||
| @@ -60,19 +60,18 @@ void HOT Scheduler::set_interval(Component *component, const std::string &name, | |||||||
|   if (interval != 0) |   if (interval != 0) | ||||||
|     offset = (random_uint32() % interval) / 2; |     offset = (random_uint32() % interval) / 2; | ||||||
|  |  | ||||||
|   ESP_LOGVV(TAG, "set_interval(name='%s', interval=%" PRIu32 ", offset=%" PRIu32 ")", name.c_str(), interval, offset); |  | ||||||
|  |  | ||||||
|   auto item = make_unique<SchedulerItem>(); |   auto item = make_unique<SchedulerItem>(); | ||||||
|   item->component = component; |   item->component = component; | ||||||
|   item->name = name; |   item->name = name; | ||||||
|   item->type = SchedulerItem::INTERVAL; |   item->type = SchedulerItem::INTERVAL; | ||||||
|   item->interval = interval; |   item->interval = interval; | ||||||
|   item->last_execution = now - offset - interval; |   item->next_execution_ = now + offset; | ||||||
|   item->last_execution_major = this->millis_major_; |  | ||||||
|   if (item->last_execution > now) |  | ||||||
|     item->last_execution_major--; |  | ||||||
|   item->callback = std::move(func); |   item->callback = std::move(func); | ||||||
|   item->remove = false; |   item->remove = false; | ||||||
|  | #ifdef ESPHOME_DEBUG_SCHEDULER | ||||||
|  |   ESP_LOGD(TAG, "set_interval(name='%s/%s', interval=%" PRIu32 ", offset=%" PRIu32 ")", item->get_source(), | ||||||
|  |            name.c_str(), interval, offset); | ||||||
|  | #endif | ||||||
|   this->push_(std::move(item)); |   this->push_(std::move(item)); | ||||||
| } | } | ||||||
| bool HOT Scheduler::cancel_interval(Component *component, const std::string &name) { | bool HOT Scheduler::cancel_interval(Component *component, const std::string &name) { | ||||||
| @@ -138,36 +137,36 @@ optional<uint32_t> HOT Scheduler::next_schedule_in() { | |||||||
|   if (this->empty_()) |   if (this->empty_()) | ||||||
|     return {}; |     return {}; | ||||||
|   auto &item = this->items_[0]; |   auto &item = this->items_[0]; | ||||||
|   const uint32_t now = this->millis_(); |   const auto now = this->millis_(); | ||||||
|   uint32_t next_time = item->last_execution + item->interval; |   if (item->next_execution_ < now) | ||||||
|   if (next_time < now) |  | ||||||
|     return 0; |     return 0; | ||||||
|   return next_time - now; |   return item->next_execution_ - now; | ||||||
| } | } | ||||||
| void HOT Scheduler::call() { | void HOT Scheduler::call() { | ||||||
|   const uint32_t now = this->millis_(); |   const auto now = this->millis_(); | ||||||
|   this->process_to_add(); |   this->process_to_add(); | ||||||
|  |  | ||||||
| #ifdef ESPHOME_DEBUG_SCHEDULER | #ifdef ESPHOME_DEBUG_SCHEDULER | ||||||
|   static uint32_t last_print = 0; |   static uint64_t last_print = 0; | ||||||
|  |  | ||||||
|   if (now - last_print > 2000) { |   if (now - last_print > 2000) { | ||||||
|     last_print = now; |     last_print = now; | ||||||
|     std::vector<std::unique_ptr<SchedulerItem>> old_items; |     std::vector<std::unique_ptr<SchedulerItem>> old_items; | ||||||
|     ESP_LOGVV(TAG, "Items: count=%u, now=%" PRIu32, this->items_.size(), now); |     ESP_LOGD(TAG, "Items: count=%u, now=%" PRIu64 " (%u, %" PRIu32 ")", this->items_.size(), now, this->millis_major_, | ||||||
|  |              this->last_millis_); | ||||||
|     while (!this->empty_()) { |     while (!this->empty_()) { | ||||||
|       this->lock_.lock(); |       this->lock_.lock(); | ||||||
|       auto item = std::move(this->items_[0]); |       auto item = std::move(this->items_[0]); | ||||||
|       this->pop_raw_(); |       this->pop_raw_(); | ||||||
|       this->lock_.unlock(); |       this->lock_.unlock(); | ||||||
|  |  | ||||||
|       ESP_LOGVV(TAG, "  %s '%s' interval=%" PRIu32 " last_execution=%" PRIu32 " (%u) next=%" PRIu32 " (%u)", |       ESP_LOGD(TAG, "  %s '%s/%s' interval=%" PRIu32 " next_execution in %" PRIu64 "ms at %" PRIu64, | ||||||
|                 item->get_type_str(), item->name.c_str(), item->interval, item->last_execution, |                item->get_type_str(), item->get_source(), item->name.c_str(), item->interval, | ||||||
|                 item->last_execution_major, item->next_execution(), item->next_execution_major()); |                item->next_execution_ - now, item->next_execution_); | ||||||
|  |  | ||||||
|       old_items.push_back(std::move(item)); |       old_items.push_back(std::move(item)); | ||||||
|     } |     } | ||||||
|     ESP_LOGVV(TAG, "\n"); |     ESP_LOGD(TAG, "\n"); | ||||||
|  |  | ||||||
|     { |     { | ||||||
|       LockGuard guard{this->lock_}; |       LockGuard guard{this->lock_}; | ||||||
| @@ -206,14 +205,10 @@ void HOT Scheduler::call() { | |||||||
|     { |     { | ||||||
|       // Don't copy-by value yet |       // Don't copy-by value yet | ||||||
|       auto &item = this->items_[0]; |       auto &item = this->items_[0]; | ||||||
|       if ((now - item->last_execution) < item->interval) { |       if (item->next_execution_ > now) { | ||||||
|         // Not reached timeout yet, done for this call |         // Not reached timeout yet, done for this call | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
|       uint8_t major = item->next_execution_major(); |  | ||||||
|       if (this->millis_major_ - major > 1) |  | ||||||
|         break; |  | ||||||
|  |  | ||||||
|       // Don't run on failed components |       // Don't run on failed components | ||||||
|       if (item->component != nullptr && item->component->is_failed()) { |       if (item->component != nullptr && item->component->is_failed()) { | ||||||
|         LockGuard guard{this->lock_}; |         LockGuard guard{this->lock_}; | ||||||
| @@ -221,9 +216,10 @@ void HOT Scheduler::call() { | |||||||
|         continue; |         continue; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE | #ifdef ESPHOME_DEBUG_SCHEDULER | ||||||
|       ESP_LOGVV(TAG, "Running %s '%s' with interval=%" PRIu32 " last_execution=%" PRIu32 " (now=%" PRIu32 ")", |       ESP_LOGV(TAG, "Running %s '%s/%s' with interval=%" PRIu32 " next_execution=%" PRIu64 " (now=%" PRIu64 ")", | ||||||
|                 item->get_type_str(), item->name.c_str(), item->interval, item->last_execution, now); |                item->get_type_str(), item->get_source(), item->name.c_str(), item->interval, item->next_execution_, | ||||||
|  |                now); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|       // Warning: During callback(), a lot of stuff can happen, including: |       // Warning: During callback(), a lot of stuff can happen, including: | ||||||
| @@ -254,13 +250,7 @@ void HOT Scheduler::call() { | |||||||
|       } |       } | ||||||
|  |  | ||||||
|       if (item->type == SchedulerItem::INTERVAL) { |       if (item->type == SchedulerItem::INTERVAL) { | ||||||
|         if (item->interval != 0) { |         item->next_execution_ = now + item->interval; | ||||||
|           const uint32_t before = item->last_execution; |  | ||||||
|           const uint32_t amount = (now - item->last_execution) / item->interval; |  | ||||||
|           item->last_execution += amount * item->interval; |  | ||||||
|           if (item->last_execution < before) |  | ||||||
|             item->last_execution_major++; |  | ||||||
|         } |  | ||||||
|         this->push_(std::move(item)); |         this->push_(std::move(item)); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -322,43 +312,20 @@ bool HOT Scheduler::cancel_item_(Component *component, const std::string &name, | |||||||
|  |  | ||||||
|   return ret; |   return ret; | ||||||
| } | } | ||||||
| uint32_t Scheduler::millis_() { | uint64_t Scheduler::millis_() { | ||||||
|   const uint32_t now = millis(); |   const uint32_t now = millis(); | ||||||
|   if (now < this->last_millis_) { |   if (now < this->last_millis_) { | ||||||
|     ESP_LOGD(TAG, "Incrementing scheduler major"); |  | ||||||
|     this->millis_major_++; |     this->millis_major_++; | ||||||
|  |     ESP_LOGD(TAG, "Incrementing scheduler major at %" PRIu64 "ms", | ||||||
|  |              now + (static_cast<uint64_t>(this->millis_major_) << 32)); | ||||||
|   } |   } | ||||||
|   this->last_millis_ = now; |   this->last_millis_ = now; | ||||||
|   return now; |   return now + (static_cast<uint64_t>(this->millis_major_) << 32); | ||||||
| } | } | ||||||
|  |  | ||||||
| bool HOT Scheduler::SchedulerItem::cmp(const std::unique_ptr<SchedulerItem> &a, | bool HOT Scheduler::SchedulerItem::cmp(const std::unique_ptr<SchedulerItem> &a, | ||||||
|                                        const std::unique_ptr<SchedulerItem> &b) { |                                        const std::unique_ptr<SchedulerItem> &b) { | ||||||
|   // min-heap |   return a->next_execution_ > b->next_execution_; | ||||||
|   // return true if *a* will happen after *b* |  | ||||||
|   uint32_t a_next_exec = a->next_execution(); |  | ||||||
|   uint8_t a_next_exec_major = a->next_execution_major(); |  | ||||||
|   uint32_t b_next_exec = b->next_execution(); |  | ||||||
|   uint8_t b_next_exec_major = b->next_execution_major(); |  | ||||||
|  |  | ||||||
|   if (a_next_exec_major != b_next_exec_major) { |  | ||||||
|     // The "major" calculation is quite complicated. |  | ||||||
|     // Basically, we need to check if the major value lies in the future or |  | ||||||
|     // |  | ||||||
|  |  | ||||||
|     // Here are some cases to think about: |  | ||||||
|     // Format: a_major,b_major -> expected result (a-b, b-a) |  | ||||||
|     // a=255,b=0 -> false (255, 1) |  | ||||||
|     // a=0,b=1 -> false   (255, 1) |  | ||||||
|     // a=1,b=0 -> true    (1, 255) |  | ||||||
|     // a=0,b=255 -> true  (1, 255) |  | ||||||
|  |  | ||||||
|     uint8_t diff1 = a_next_exec_major - b_next_exec_major; |  | ||||||
|     uint8_t diff2 = b_next_exec_major - a_next_exec_major; |  | ||||||
|     return diff1 < diff2; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return a_next_exec > b_next_exec; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -32,23 +32,10 @@ class Scheduler { | |||||||
|     Component *component; |     Component *component; | ||||||
|     std::string name; |     std::string name; | ||||||
|     enum Type { TIMEOUT, INTERVAL } type; |     enum Type { TIMEOUT, INTERVAL } type; | ||||||
|     union { |     uint32_t interval; | ||||||
|       uint32_t interval; |     uint64_t next_execution_; | ||||||
|       uint32_t timeout; |  | ||||||
|     }; |  | ||||||
|     uint32_t last_execution; |  | ||||||
|     std::function<void()> callback; |     std::function<void()> callback; | ||||||
|     bool remove; |     bool remove; | ||||||
|     uint8_t last_execution_major; |  | ||||||
|  |  | ||||||
|     inline uint32_t next_execution() { return this->last_execution + this->timeout; } |  | ||||||
|     inline uint8_t next_execution_major() { |  | ||||||
|       uint32_t next_exec = this->next_execution(); |  | ||||||
|       uint8_t next_exec_major = this->last_execution_major; |  | ||||||
|       if (next_exec < this->last_execution) |  | ||||||
|         next_exec_major++; |  | ||||||
|       return next_exec_major; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     static bool cmp(const std::unique_ptr<SchedulerItem> &a, const std::unique_ptr<SchedulerItem> &b); |     static bool cmp(const std::unique_ptr<SchedulerItem> &a, const std::unique_ptr<SchedulerItem> &b); | ||||||
|     const char *get_type_str() { |     const char *get_type_str() { | ||||||
| @@ -61,9 +48,12 @@ class Scheduler { | |||||||
|           return ""; |           return ""; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |     const char *get_source() { | ||||||
|  |       return this->component != nullptr ? this->component->get_component_source() : "unknown"; | ||||||
|  |     } | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   uint32_t millis_(); |   uint64_t millis_(); | ||||||
|   void cleanup_(); |   void cleanup_(); | ||||||
|   void pop_raw_(); |   void pop_raw_(); | ||||||
|   void push_(std::unique_ptr<SchedulerItem> item); |   void push_(std::unique_ptr<SchedulerItem> item); | ||||||
| @@ -77,7 +67,7 @@ class Scheduler { | |||||||
|   std::vector<std::unique_ptr<SchedulerItem>> items_; |   std::vector<std::unique_ptr<SchedulerItem>> items_; | ||||||
|   std::vector<std::unique_ptr<SchedulerItem>> to_add_; |   std::vector<std::unique_ptr<SchedulerItem>> to_add_; | ||||||
|   uint32_t last_millis_{0}; |   uint32_t last_millis_{0}; | ||||||
|   uint8_t millis_major_{0}; |   uint16_t millis_major_{0}; | ||||||
|   uint32_t to_remove_{0}; |   uint32_t to_remove_{0}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								tests/components/esphome/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								tests/components/esphome/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | esphome: | ||||||
|  |   debug_scheduler: true | ||||||
|  |   platformio_options: | ||||||
|  |     board_build.flash_mode: dio | ||||||
|  |   area: testing | ||||||
|  |   on_boot: | ||||||
|  |     logger.log: on_boot | ||||||
|  |   on_shutdown: | ||||||
|  |     logger.log: on_shutdown | ||||||
|  |   on_loop: | ||||||
|  |     logger.log: on_loop | ||||||
|  |   compile_process_limit: 1 | ||||||
|  |   min_version: "2025.1" | ||||||
|  |   name_add_mac_suffix: true | ||||||
|  |   project: | ||||||
|  |     name: esphome.test | ||||||
|  |     version: "1.1" | ||||||
|  |     on_update: | ||||||
|  |       logger.log: on_update | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								tests/components/esphome/test.esp32-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/components/esphome/test.esp32-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | <<: !include common.yaml | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								tests/components/esphome/test.esp32-c3-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/components/esphome/test.esp32-c3-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | <<: !include common.yaml | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								tests/components/esphome/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/components/esphome/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										1
									
								
								tests/components/esphome/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/components/esphome/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										1
									
								
								tests/components/esphome/test.esp8266-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/components/esphome/test.esp8266-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										1
									
								
								tests/components/esphome/test.host.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/components/esphome/test.host.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										1
									
								
								tests/components/esphome/test.rp2040-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/components/esphome/test.rp2040-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | <<: !include common.yaml | ||||||
		Reference in New Issue
	
	Block a user