mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	stress test
This commit is contained in:
		| @@ -1,35 +0,0 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID | ||||
|  | ||||
| CODEOWNERS = ["@test"] | ||||
| AUTO_LOAD = ["api"] | ||||
|  | ||||
| api_buffer_test_component_ns = cg.esphome_ns.namespace("api_buffer_test_component") | ||||
| APIBufferTestComponent = api_buffer_test_component_ns.class_( | ||||
|     "APIBufferTestComponent", cg.Component | ||||
| ) | ||||
|  | ||||
| CONF_FILL_SIZE = "fill_size" | ||||
| CONF_FILL_COUNT = "fill_count" | ||||
| CONF_AUTO_FILL_DELAY = "auto_fill_delay" | ||||
|  | ||||
| CONFIG_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.GenerateID(): cv.declare_id(APIBufferTestComponent), | ||||
|         cv.Optional(CONF_FILL_SIZE, default=2048): cv.int_range(min=1, max=16384), | ||||
|         cv.Optional(CONF_FILL_COUNT, default=200): cv.int_range(min=1, max=1000), | ||||
|         cv.Optional( | ||||
|             CONF_AUTO_FILL_DELAY, default="2s" | ||||
|         ): cv.positive_time_period_milliseconds, | ||||
|     } | ||||
| ).extend(cv.COMPONENT_SCHEMA) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await cg.register_component(var, config) | ||||
|  | ||||
|     cg.add(var.set_fill_size(config[CONF_FILL_SIZE])) | ||||
|     cg.add(var.set_fill_count(config[CONF_FILL_COUNT])) | ||||
|     cg.add(var.set_auto_fill_delay(config[CONF_AUTO_FILL_DELAY])) | ||||
| @@ -1,166 +0,0 @@ | ||||
| #include "api_buffer_test_component.h" | ||||
| #include "esphome/core/application.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace api_buffer_test_component { | ||||
|  | ||||
| APIBufferTestComponent *global_api_buffer_test_component = | ||||
|     nullptr;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||
|  | ||||
| void APIBufferTestComponent::setup() { | ||||
|   ESP_LOGD(TAG, "API Buffer Test Component setup"); | ||||
|   this->last_fill_time_ = millis(); | ||||
|   global_api_buffer_test_component = this; | ||||
|  | ||||
|   // For testing, we'll get the API connection through a hack | ||||
|   // In a real implementation, this would be done properly through the API | ||||
|   App.scheduler.set_timeout(this, "get_api_connection", 500, [this]() { | ||||
|     auto *api_server = api::global_api_server; | ||||
|     if (api_server != nullptr) { | ||||
|       // This is a hack - in production code, use proper API subscription | ||||
|       // For testing, we'll assume there's only one connection | ||||
|       ESP_LOGD(TAG, "Looking for API connection to subscribe to"); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
|  | ||||
| void APIBufferTestComponent::loop() { | ||||
|   // Check if API server is ready and has connections | ||||
|   auto *api_server = api::global_api_server; | ||||
|   if (api_server == nullptr || !api_server->is_connected()) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // Try to get an API connection if we don't have one | ||||
|   if (this->api_connection_ == nullptr && !this->tried_subscribe_) { | ||||
|     this->tried_subscribe_ = true; | ||||
|     ESP_LOGD(TAG, "API server is connected, buffer test component ready"); | ||||
|     // For testing, we'll work with the fact that send_message is available | ||||
|     // through the global API server's connection management | ||||
|   } | ||||
|  | ||||
|   uint32_t now = millis(); | ||||
|  | ||||
|   // Auto-fill buffer after delay if configured | ||||
|   if (this->auto_fill_delay_ > 0 && !this->buffer_filled_ && api_server->is_connected()) { | ||||
|     if (now - this->last_fill_time_ > this->auto_fill_delay_) { | ||||
|       ESP_LOGD(TAG, "Auto-filling buffer after %u ms delay", this->auto_fill_delay_); | ||||
|       // For the test, we'll generate heavy log traffic instead | ||||
|       this->generate_heavy_traffic(); | ||||
|       this->buffer_filled_ = true; | ||||
|  | ||||
|       // Keep generating traffic for 5 seconds | ||||
|       this->should_keep_full_ = true; | ||||
|       this->keep_full_until_ = now + 5000; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Keep buffer full if requested | ||||
|   if (this->should_keep_full_ && now < this->keep_full_until_) { | ||||
|     // Generate more traffic to keep buffer full | ||||
|     this->generate_traffic_burst(); | ||||
|   } else if (this->should_keep_full_ && now >= this->keep_full_until_) { | ||||
|     this->should_keep_full_ = false; | ||||
|     ESP_LOGD(TAG, "Stopped keeping buffer full"); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void APIBufferTestComponent::subscribe_api_connection(api::APIConnection *api_connection) { | ||||
|   if (this->api_connection_ != nullptr) { | ||||
|     ESP_LOGE(TAG, "Already subscribed to an API connection"); | ||||
|     return; | ||||
|   } | ||||
|   this->api_connection_ = api_connection; | ||||
|   ESP_LOGD(TAG, "Subscribed to API connection"); | ||||
| } | ||||
|  | ||||
| void APIBufferTestComponent::unsubscribe_api_connection(api::APIConnection *api_connection) { | ||||
|   if (this->api_connection_ != api_connection) { | ||||
|     return; | ||||
|   } | ||||
|   this->api_connection_ = nullptr; | ||||
|   ESP_LOGD(TAG, "Unsubscribed from API connection"); | ||||
| } | ||||
|  | ||||
| void APIBufferTestComponent::fill_buffer() { | ||||
|   if (this->api_connection_ == nullptr) { | ||||
|     ESP_LOGW(TAG, "No API connection available to fill buffer"); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   ESP_LOGD(TAG, "Filling transmit buffer with %zu messages of %zu bytes each", this->fill_count_, this->fill_size_); | ||||
|  | ||||
|   // Create a large text sensor state response to fill the buffer | ||||
|   api::TextSensorStateResponse resp; | ||||
|   resp.key = 0x12345678;                            // Dummy key | ||||
|   resp.state = std::string(this->fill_size_, 'X');  // Large payload | ||||
|   resp.missing_state = false; | ||||
|  | ||||
|   // Send many messages rapidly to fill the transmit buffer | ||||
|   size_t sent_count = 0; | ||||
|   size_t failed_count = 0; | ||||
|  | ||||
|   for (size_t i = 0; i < this->fill_count_; i++) { | ||||
|     // Modify the string slightly each time | ||||
|     resp.state[0] = 'A' + (i % 26); | ||||
|  | ||||
|     // Send message directly without batching | ||||
|     bool sent = this->api_connection_->send_message(resp); | ||||
|  | ||||
|     if (!sent) { | ||||
|       failed_count++; | ||||
|       ESP_LOGV(TAG, "Message %zu failed to send - buffer likely full", i); | ||||
|     } else { | ||||
|       sent_count++; | ||||
|     } | ||||
|  | ||||
|     // Log progress | ||||
|     if (i % 50 == 0) { | ||||
|       ESP_LOGD(TAG, "Progress: %zu/%zu messages, %zu failed", i, this->fill_count_, failed_count); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ESP_LOGD(TAG, "Buffer fill complete: %zu sent, %zu failed", sent_count, failed_count); | ||||
|   this->last_fill_time_ = millis(); | ||||
| } | ||||
|  | ||||
| void APIBufferTestComponent::generate_heavy_traffic() { | ||||
|   ESP_LOGD(TAG, "Generating heavy traffic to fill transmit buffer"); | ||||
|  | ||||
|   // Generate many large log messages rapidly | ||||
|   // These will be sent over the API if log subscription is active | ||||
|   std::string large_log(this->fill_size_, 'X'); | ||||
|  | ||||
|   for (size_t i = 0; i < this->fill_count_; i++) { | ||||
|     // Modify the string to ensure each message is unique | ||||
|     large_log[0] = 'A' + (i % 26); | ||||
|  | ||||
|     // Use VERY_VERBOSE level to ensure it's sent when subscribed | ||||
|     ESP_LOGVV(TAG, "Buffer fill #%zu: %s", i, large_log.c_str()); | ||||
|  | ||||
|     // Progress logging at higher level | ||||
|     if (i % 50 == 0) { | ||||
|       ESP_LOGD(TAG, "Traffic generation progress: %zu/%zu", i, this->fill_count_); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ESP_LOGD(TAG, "Heavy traffic generation complete"); | ||||
| } | ||||
|  | ||||
| void APIBufferTestComponent::generate_traffic_burst() { | ||||
|   // Generate a burst of medium-sized messages to keep buffer topped up | ||||
|   std::string medium_log(512, 'K'); | ||||
|  | ||||
|   for (int i = 0; i < 5; i++) { | ||||
|     medium_log[0] = '0' + (i % 10); | ||||
|     ESP_LOGVV(TAG, "Keep-full burst #%d: %s", i, medium_log.c_str()); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void APIBufferTestComponent::keep_buffer_full() { | ||||
|   // Deprecated - use generate_traffic_burst instead | ||||
|   this->generate_traffic_burst(); | ||||
| } | ||||
|  | ||||
| }  // namespace api_buffer_test_component | ||||
| }  // namespace esphome | ||||
| @@ -1,52 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/log.h" | ||||
| #include "esphome/components/api/api_server.h" | ||||
| #include "esphome/components/api/api_connection.h" | ||||
| #include "esphome/components/api/api_pb2.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace api_buffer_test_component { | ||||
|  | ||||
| static const char *const TAG = "api_buffer_test"; | ||||
|  | ||||
| class APIBufferTestComponent : public Component { | ||||
|  public: | ||||
|   void setup() override; | ||||
|   void loop() override; | ||||
|  | ||||
|   float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; } | ||||
|  | ||||
|   // Subscribe to API connection (like bluetooth_proxy) | ||||
|   void subscribe_api_connection(api::APIConnection *api_connection); | ||||
|   void unsubscribe_api_connection(api::APIConnection *api_connection); | ||||
|  | ||||
|   // Test methods | ||||
|   void fill_buffer(); | ||||
|   void keep_buffer_full(); | ||||
|   void generate_heavy_traffic(); | ||||
|   void generate_traffic_burst(); | ||||
|  | ||||
|   // Configuration | ||||
|   void set_fill_size(size_t size) { this->fill_size_ = size; } | ||||
|   void set_fill_count(size_t count) { this->fill_count_ = count; } | ||||
|   void set_auto_fill_delay(uint32_t delay) { this->auto_fill_delay_ = delay; } | ||||
|  | ||||
|  protected: | ||||
|   api::APIConnection *api_connection_{nullptr}; | ||||
|   size_t fill_size_{2048}; | ||||
|   size_t fill_count_{200}; | ||||
|   uint32_t auto_fill_delay_{2000}; | ||||
|   uint32_t last_fill_time_{0}; | ||||
|   bool buffer_filled_{false}; | ||||
|   bool should_keep_full_{false}; | ||||
|   uint32_t keep_full_until_{0}; | ||||
|   bool tried_subscribe_{false}; | ||||
| }; | ||||
|  | ||||
| extern APIBufferTestComponent | ||||
|     *global_api_buffer_test_component;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||
|  | ||||
| }  // namespace api_buffer_test_component | ||||
| }  // namespace esphome | ||||
		Reference in New Issue
	
	Block a user