mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Merge branch 'integration' into memory_api
This commit is contained in:
		
							
								
								
									
										24
									
								
								.github/workflows/needs-docs.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								.github/workflows/needs-docs.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,24 +0,0 @@ | ||||
| name: Needs Docs | ||||
|  | ||||
| on: | ||||
|   pull_request: | ||||
|     types: [labeled, unlabeled] | ||||
|  | ||||
| jobs: | ||||
|   check: | ||||
|     name: Check | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Check for needs-docs label | ||||
|         uses: actions/github-script@v7.0.1 | ||||
|         with: | ||||
|           script: | | ||||
|             const { data: labels } = await github.rest.issues.listLabelsOnIssue({ | ||||
|               owner: context.repo.owner, | ||||
|               repo: context.repo.repo, | ||||
|               issue_number: context.issue.number | ||||
|             }); | ||||
|             const needsDocs = labels.find(label => label.name === 'needs-docs'); | ||||
|             if (needsDocs) { | ||||
|               core.setFailed('Pull request needs docs'); | ||||
|             } | ||||
							
								
								
									
										30
									
								
								.github/workflows/status-check-labels.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								.github/workflows/status-check-labels.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| name: Status check labels | ||||
|  | ||||
| on: | ||||
|   pull_request: | ||||
|     types: [labeled, unlabeled] | ||||
|  | ||||
| jobs: | ||||
|   check: | ||||
|     name: Check ${{ matrix.label }} | ||||
|     runs-on: ubuntu-latest | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
|         label: | ||||
|           - needs-docs | ||||
|           - merge-after-release | ||||
|     steps: | ||||
|       - name: Check for ${{ matrix.label }} label | ||||
|         uses: actions/github-script@v7.0.1 | ||||
|         with: | ||||
|           script: | | ||||
|             const { data: labels } = await github.rest.issues.listLabelsOnIssue({ | ||||
|               owner: context.repo.owner, | ||||
|               repo: context.repo.repo, | ||||
|               issue_number: context.issue.number | ||||
|             }); | ||||
|             const hasLabel = labels.find(label => label.name === '${{ matrix.label }}'); | ||||
|             if (hasLabel) { | ||||
|               core.setFailed('Pull request cannot be merged, it is labeled as ${{ matrix.label }}'); | ||||
|             } | ||||
| @@ -382,20 +382,15 @@ float ATM90E32Component::get_setup_priority() const { return setup_priority::IO; | ||||
| // R/C registers can conly be cleared after the LastSPIData register is updated (register 78H) | ||||
| // Peakdetect period: 05H. Bit 15:8 are PeakDet_period in ms. 7:0 are Sag_period | ||||
| // Default is 143FH (20ms, 63ms) | ||||
| uint16_t ATM90E32Component::read16_transaction_(uint16_t a_register) { | ||||
| uint16_t ATM90E32Component::read16_(uint16_t a_register) { | ||||
|   this->enable(); | ||||
|   delay_microseconds_safe(1);  // min delay between CS low and first SCK is 200ns - 1us is plenty | ||||
|   uint8_t addrh = (1 << 7) | ((a_register >> 8) & 0x03); | ||||
|   uint8_t addrl = (a_register & 0xFF); | ||||
|   uint8_t data[4] = {addrh, addrl, 0x00, 0x00}; | ||||
|   this->transfer_array(data, 4); | ||||
|   uint16_t output = encode_uint16(data[2], data[3]); | ||||
|   ESP_LOGVV(TAG, "read16_ 0x%04" PRIX16 " output 0x%04" PRIX16, a_register, output); | ||||
|   return output; | ||||
| } | ||||
|  | ||||
| uint16_t ATM90E32Component::read16_(uint16_t a_register) { | ||||
|   this->enable(); | ||||
|   delay_microseconds_safe(1);  // min delay between CS low and first SCK is 200ns - 1us is plenty | ||||
|   uint16_t output = this->read16_transaction_(a_register); | ||||
|   delay_microseconds_safe(1);  // allow the last clock to propagate before releasing CS | ||||
|   this->disable(); | ||||
|   delay_microseconds_safe(1);  // meet minimum CS high time before next transaction | ||||
| @@ -403,14 +398,8 @@ uint16_t ATM90E32Component::read16_(uint16_t a_register) { | ||||
| } | ||||
|  | ||||
| int ATM90E32Component::read32_(uint16_t addr_h, uint16_t addr_l) { | ||||
|   this->enable(); | ||||
|   delay_microseconds_safe(1); | ||||
|   const uint16_t val_h = this->read16_transaction_(addr_h); | ||||
|   delay_microseconds_safe(1); | ||||
|   const uint16_t val_l = this->read16_transaction_(addr_l); | ||||
|   delay_microseconds_safe(1); | ||||
|   this->disable(); | ||||
|   delay_microseconds_safe(1); | ||||
|   const uint16_t val_h = this->read16_(addr_h); | ||||
|   const uint16_t val_l = this->read16_(addr_l); | ||||
|   const int32_t val = (val_h << 16) | val_l; | ||||
|  | ||||
|   ESP_LOGVV(TAG, | ||||
|   | ||||
| @@ -140,7 +140,6 @@ class ATM90E32Component : public PollingComponent, | ||||
|   number::Number *ref_currents_[3]{nullptr, nullptr, nullptr}; | ||||
| #endif | ||||
|   uint16_t read16_(uint16_t a_register); | ||||
|   uint16_t read16_transaction_(uint16_t a_register); | ||||
|   int read32_(uint16_t addr_h, uint16_t addr_l); | ||||
|   void write16_(uint16_t a_register, uint16_t val, bool validate = true); | ||||
|   float get_local_phase_voltage_(uint8_t phase); | ||||
|   | ||||
| @@ -375,10 +375,19 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga | ||||
|  | ||||
|   switch (event) { | ||||
|     case ESP_GATTC_DISCONNECT_EVT: { | ||||
|       this->reset_connection_(param->disconnect.reason); | ||||
|       // Don't reset connection yet - wait for CLOSE_EVT to ensure controller has freed resources | ||||
|       // This prevents race condition where we mark slot as free before controller cleanup is complete | ||||
|       ESP_LOGD(TAG, "[%d] [%s] Disconnect, reason=0x%02x", this->connection_index_, this->address_str_.c_str(), | ||||
|                param->disconnect.reason); | ||||
|       // Send disconnection notification but don't free the slot yet | ||||
|       this->proxy_->send_device_connection(this->address_, false, 0, param->disconnect.reason); | ||||
|       break; | ||||
|     } | ||||
|     case ESP_GATTC_CLOSE_EVT: { | ||||
|       ESP_LOGD(TAG, "[%d] [%s] Close, reason=0x%02x, freeing slot", this->connection_index_, this->address_str_.c_str(), | ||||
|                param->close.reason); | ||||
|       // Now the GATT connection is fully closed and controller resources are freed | ||||
|       // Safe to mark the connection slot as available | ||||
|       this->reset_connection_(param->close.reason); | ||||
|       break; | ||||
|     } | ||||
|   | ||||
| @@ -824,8 +824,9 @@ async def to_code(config): | ||||
|     cg.set_cpp_standard("gnu++20") | ||||
|     cg.add_build_flag("-DUSE_ESP32") | ||||
|     cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) | ||||
|     cg.add_build_flag(f"-DUSE_ESP32_VARIANT_{config[CONF_VARIANT]}") | ||||
|     cg.add_define("ESPHOME_VARIANT", VARIANT_FRIENDLY[config[CONF_VARIANT]]) | ||||
|     variant = config[CONF_VARIANT] | ||||
|     cg.add_build_flag(f"-DUSE_ESP32_VARIANT_{variant}") | ||||
|     cg.add_define("ESPHOME_VARIANT", VARIANT_FRIENDLY[variant]) | ||||
|     cg.add_define(ThreadModel.MULTI_ATOMICS) | ||||
|  | ||||
|     cg.add_platformio_option("lib_ldf_mode", "off") | ||||
| @@ -859,6 +860,7 @@ async def to_code(config): | ||||
|         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 | ||||
|         ) | ||||
|   | ||||
| @@ -764,7 +764,8 @@ void Nextion::process_nextion_commands_() { | ||||
|         variable_name = to_process.substr(0, index); | ||||
|         ++index; | ||||
|  | ||||
|         text_value = to_process.substr(index); | ||||
|         // Get variable value without terminating NUL byte.  Length check above ensures substr len >= 0. | ||||
|         text_value = to_process.substr(index, to_process_length - index - 1); | ||||
|  | ||||
|         ESP_LOGN(TAG, "Text sensor: %s='%s'", variable_name.c_str(), text_value.c_str()); | ||||
|  | ||||
|   | ||||
| @@ -23,20 +23,18 @@ void Pipsolar::loop() { | ||||
|   // Read message | ||||
|   if (this->state_ == STATE_IDLE) { | ||||
|     this->empty_uart_buffer_(); | ||||
|     switch (this->send_next_command_()) { | ||||
|       case 0: | ||||
|         // no command send (empty queue) time to poll | ||||
|         if (millis() - this->last_poll_ > this->update_interval_) { | ||||
|           this->send_next_poll_(); | ||||
|           this->last_poll_ = millis(); | ||||
|         } | ||||
|         return; | ||||
|         break; | ||||
|       case 1: | ||||
|         // command send | ||||
|         return; | ||||
|         break; | ||||
|  | ||||
|     if (this->send_next_command_()) { | ||||
|       // command sent | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (this->send_next_poll_()) { | ||||
|       // poll sent | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     return; | ||||
|   } | ||||
|   if (this->state_ == STATE_COMMAND_COMPLETE) { | ||||
|     if (this->check_incoming_length_(4)) { | ||||
| @@ -530,7 +528,7 @@ void Pipsolar::loop() { | ||||
|         // '(00000000000000000000000000000000' | ||||
|         // iterate over all available flag (as not all models have all flags, but at least in the same order) | ||||
|         this->value_warnings_present_ = false; | ||||
|         this->value_faults_present_ = true; | ||||
|         this->value_faults_present_ = false; | ||||
|  | ||||
|         for (size_t i = 1; i < strlen(tmp); i++) { | ||||
|           enabled = tmp[i] == '1'; | ||||
| @@ -708,6 +706,7 @@ void Pipsolar::loop() { | ||||
|         return; | ||||
|       } | ||||
|       // crc ok | ||||
|       this->used_polling_commands_[this->last_polling_command_].needs_update = false; | ||||
|       this->state_ = STATE_POLL_CHECKED; | ||||
|       return; | ||||
|     } else { | ||||
| @@ -788,7 +787,7 @@ uint8_t Pipsolar::check_incoming_crc_() { | ||||
| } | ||||
|  | ||||
| // send next command used | ||||
| uint8_t Pipsolar::send_next_command_() { | ||||
| bool Pipsolar::send_next_command_() { | ||||
|   uint16_t crc16; | ||||
|   if (!this->command_queue_[this->command_queue_position_].empty()) { | ||||
|     const char *command = this->command_queue_[this->command_queue_position_].c_str(); | ||||
| @@ -809,37 +808,43 @@ uint8_t Pipsolar::send_next_command_() { | ||||
|     // end Byte | ||||
|     this->write(0x0D); | ||||
|     ESP_LOGD(TAG, "Sending command from queue: %s with length %d", command, length); | ||||
|     return 1; | ||||
|     return true; | ||||
|   } | ||||
|   return 0; | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| void Pipsolar::send_next_poll_() { | ||||
| bool Pipsolar::send_next_poll_() { | ||||
|   uint16_t crc16; | ||||
|   this->last_polling_command_ = (this->last_polling_command_ + 1) % 15; | ||||
|   if (this->used_polling_commands_[this->last_polling_command_].length == 0) { | ||||
|     this->last_polling_command_ = 0; | ||||
|  | ||||
|   for (uint8_t i = 0; i < POLLING_COMMANDS_MAX; i++) { | ||||
|     this->last_polling_command_ = (this->last_polling_command_ + 1) % POLLING_COMMANDS_MAX; | ||||
|     if (this->used_polling_commands_[this->last_polling_command_].length == 0) { | ||||
|       // not enabled | ||||
|       continue; | ||||
|     } | ||||
|     if (!this->used_polling_commands_[this->last_polling_command_].needs_update) { | ||||
|       // no update requested | ||||
|       continue; | ||||
|     } | ||||
|     this->state_ = STATE_POLL; | ||||
|     this->command_start_millis_ = millis(); | ||||
|     this->empty_uart_buffer_(); | ||||
|     this->read_pos_ = 0; | ||||
|     crc16 = this->pipsolar_crc_(this->used_polling_commands_[this->last_polling_command_].command, | ||||
|                                 this->used_polling_commands_[this->last_polling_command_].length); | ||||
|     this->write_array(this->used_polling_commands_[this->last_polling_command_].command, | ||||
|                       this->used_polling_commands_[this->last_polling_command_].length); | ||||
|     // checksum | ||||
|     this->write(((uint8_t) ((crc16) >> 8)));   // highbyte | ||||
|     this->write(((uint8_t) ((crc16) &0xff)));  // lowbyte | ||||
|     // end Byte | ||||
|     this->write(0x0D); | ||||
|     ESP_LOGD(TAG, "Sending polling command : %s with length %d", | ||||
|              this->used_polling_commands_[this->last_polling_command_].command, | ||||
|              this->used_polling_commands_[this->last_polling_command_].length); | ||||
|     return true; | ||||
|   } | ||||
|   if (this->used_polling_commands_[this->last_polling_command_].length == 0) { | ||||
|     // no command specified | ||||
|     return; | ||||
|   } | ||||
|   this->state_ = STATE_POLL; | ||||
|   this->command_start_millis_ = millis(); | ||||
|   this->empty_uart_buffer_(); | ||||
|   this->read_pos_ = 0; | ||||
|   crc16 = this->pipsolar_crc_(this->used_polling_commands_[this->last_polling_command_].command, | ||||
|                               this->used_polling_commands_[this->last_polling_command_].length); | ||||
|   this->write_array(this->used_polling_commands_[this->last_polling_command_].command, | ||||
|                     this->used_polling_commands_[this->last_polling_command_].length); | ||||
|   // checksum | ||||
|   this->write(((uint8_t) ((crc16) >> 8)));   // highbyte | ||||
|   this->write(((uint8_t) ((crc16) &0xff)));  // lowbyte | ||||
|   // end Byte | ||||
|   this->write(0x0D); | ||||
|   ESP_LOGD(TAG, "Sending polling command : %s with length %d", | ||||
|            this->used_polling_commands_[this->last_polling_command_].command, | ||||
|            this->used_polling_commands_[this->last_polling_command_].length); | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| void Pipsolar::queue_command_(const char *command, uint8_t length) { | ||||
| @@ -869,7 +874,13 @@ void Pipsolar::dump_config() { | ||||
|     } | ||||
|   } | ||||
| } | ||||
| void Pipsolar::update() {} | ||||
| void Pipsolar::update() { | ||||
|   for (auto &used_polling_command : this->used_polling_commands_) { | ||||
|     if (used_polling_command.length != 0) { | ||||
|       used_polling_command.needs_update = true; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Pipsolar::add_polling_command_(const char *command, ENUMPollingCommand polling_command) { | ||||
|   for (auto &used_polling_command : this->used_polling_commands_) { | ||||
| @@ -891,6 +902,7 @@ void Pipsolar::add_polling_command_(const char *command, ENUMPollingCommand poll | ||||
|       used_polling_command.errors = 0; | ||||
|       used_polling_command.identifier = polling_command; | ||||
|       used_polling_command.length = length - 1; | ||||
|       used_polling_command.needs_update = true; | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -25,6 +25,7 @@ struct PollingCommand { | ||||
|   uint8_t length = 0; | ||||
|   uint8_t errors; | ||||
|   ENUMPollingCommand identifier; | ||||
|   bool needs_update; | ||||
| }; | ||||
|  | ||||
| #define PIPSOLAR_VALUED_ENTITY_(type, name, polling_command, value_type) \ | ||||
| @@ -189,14 +190,14 @@ class Pipsolar : public uart::UARTDevice, public PollingComponent { | ||||
|   static const size_t PIPSOLAR_READ_BUFFER_LENGTH = 110;  // maximum supported answer length | ||||
|   static const size_t COMMAND_QUEUE_LENGTH = 10; | ||||
|   static const size_t COMMAND_TIMEOUT = 5000; | ||||
|   uint32_t last_poll_ = 0; | ||||
|   static const size_t POLLING_COMMANDS_MAX = 15; | ||||
|   void add_polling_command_(const char *command, ENUMPollingCommand polling_command); | ||||
|   void empty_uart_buffer_(); | ||||
|   uint8_t check_incoming_crc_(); | ||||
|   uint8_t check_incoming_length_(uint8_t length); | ||||
|   uint16_t pipsolar_crc_(uint8_t *msg, uint8_t len); | ||||
|   uint8_t send_next_command_(); | ||||
|   void send_next_poll_(); | ||||
|   bool send_next_command_(); | ||||
|   bool send_next_poll_(); | ||||
|   void queue_command_(const char *command, uint8_t length); | ||||
|   std::string command_queue_[COMMAND_QUEUE_LENGTH]; | ||||
|   uint8_t command_queue_position_ = 0; | ||||
| @@ -216,7 +217,7 @@ class Pipsolar : public uart::UARTDevice, public PollingComponent { | ||||
|   }; | ||||
|  | ||||
|   uint8_t last_polling_command_ = 0; | ||||
|   PollingCommand used_polling_commands_[15]; | ||||
|   PollingCommand used_polling_commands_[POLLING_COMMANDS_MAX]; | ||||
| }; | ||||
|  | ||||
| }  // namespace pipsolar | ||||
|   | ||||
		Reference in New Issue
	
	Block a user