mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Merge branch 'integration' into memory_api
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -70,7 +70,7 @@ jobs: | |||||||
|           pip3 install build |           pip3 install build | ||||||
|           python3 -m build |           python3 -m build | ||||||
|       - name: Publish |       - name: Publish | ||||||
|         uses: pypa/gh-action-pypi-publish@v1.12.4 |         uses: pypa/gh-action-pypi-publish@v1.13.0 | ||||||
|         with: |         with: | ||||||
|           skip-existing: true |           skip-existing: true | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ from esphome.const import ( | |||||||
|     CONF_OUTPUT, |     CONF_OUTPUT, | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | AUTO_LOAD = ["gpio_expander"] | ||||||
| DEPENDENCIES = ["i2c"] | DEPENDENCIES = ["i2c"] | ||||||
| MULTI_CONF = True | MULTI_CONF = True | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,14 +22,29 @@ void MCP23016::setup() { | |||||||
|   this->write_reg_(MCP23016_IODIR0, 0xFF); |   this->write_reg_(MCP23016_IODIR0, 0xFF); | ||||||
|   this->write_reg_(MCP23016_IODIR1, 0xFF); |   this->write_reg_(MCP23016_IODIR1, 0xFF); | ||||||
| } | } | ||||||
| bool MCP23016::digital_read(uint8_t pin) { |  | ||||||
|   uint8_t bit = pin % 8; | void MCP23016::loop() { | ||||||
|  |   // Invalidate cache at the start of each loop | ||||||
|  |   this->reset_pin_cache_(); | ||||||
|  | } | ||||||
|  | bool MCP23016::digital_read_hw(uint8_t pin) { | ||||||
|   uint8_t reg_addr = pin < 8 ? MCP23016_GP0 : MCP23016_GP1; |   uint8_t reg_addr = pin < 8 ? MCP23016_GP0 : MCP23016_GP1; | ||||||
|   uint8_t value = 0; |   uint8_t value = 0; | ||||||
|   this->read_reg_(reg_addr, &value); |   if (!this->read_reg_(reg_addr, &value)) { | ||||||
|   return value & (1 << bit); |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Update the appropriate part of input_mask_ | ||||||
|  |   if (pin < 8) { | ||||||
|  |     this->input_mask_ = (this->input_mask_ & 0xFF00) | value; | ||||||
|  |   } else { | ||||||
|  |     this->input_mask_ = (this->input_mask_ & 0x00FF) | (uint16_t(value) << 8); | ||||||
|  |   } | ||||||
|  |   return true; | ||||||
| } | } | ||||||
| void MCP23016::digital_write(uint8_t pin, bool value) { |  | ||||||
|  | bool MCP23016::digital_read_cache(uint8_t pin) { return this->input_mask_ & (1 << pin); } | ||||||
|  | void MCP23016::digital_write_hw(uint8_t pin, bool value) { | ||||||
|   uint8_t reg_addr = pin < 8 ? MCP23016_OLAT0 : MCP23016_OLAT1; |   uint8_t reg_addr = pin < 8 ? MCP23016_OLAT0 : MCP23016_OLAT1; | ||||||
|   this->update_reg_(pin, value, reg_addr); |   this->update_reg_(pin, value, reg_addr); | ||||||
| } | } | ||||||
| @@ -41,7 +56,7 @@ void MCP23016::pin_mode(uint8_t pin, gpio::Flags flags) { | |||||||
|     this->update_reg_(pin, false, iodir); |     this->update_reg_(pin, false, iodir); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| float MCP23016::get_setup_priority() const { return setup_priority::HARDWARE; } | float MCP23016::get_setup_priority() const { return setup_priority::IO; } | ||||||
| bool MCP23016::read_reg_(uint8_t reg, uint8_t *value) { | bool MCP23016::read_reg_(uint8_t reg, uint8_t *value) { | ||||||
|   if (this->is_failed()) |   if (this->is_failed()) | ||||||
|     return false; |     return false; | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
| #include "esphome/components/i2c/i2c.h" | #include "esphome/components/i2c/i2c.h" | ||||||
|  | #include "esphome/components/gpio_expander/cached_gpio.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace mcp23016 { | namespace mcp23016 { | ||||||
| @@ -24,19 +25,22 @@ enum MCP23016GPIORegisters { | |||||||
|   MCP23016_IOCON1 = 0x0B, |   MCP23016_IOCON1 = 0x0B, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class MCP23016 : public Component, public i2c::I2CDevice { | class MCP23016 : public Component, public i2c::I2CDevice, public gpio_expander::CachedGpioExpander<uint8_t, 16> { | ||||||
|  public: |  public: | ||||||
|   MCP23016() = default; |   MCP23016() = default; | ||||||
|  |  | ||||||
|   void setup() override; |   void setup() override; | ||||||
|  |   void loop() override; | ||||||
|   bool digital_read(uint8_t pin); |  | ||||||
|   void digital_write(uint8_t pin, bool value); |  | ||||||
|   void pin_mode(uint8_t pin, gpio::Flags flags); |   void pin_mode(uint8_t pin, gpio::Flags flags); | ||||||
|  |  | ||||||
|   float get_setup_priority() const override; |   float get_setup_priority() const override; | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|  |   // Virtual methods from CachedGpioExpander | ||||||
|  |   bool digital_read_hw(uint8_t pin) override; | ||||||
|  |   bool digital_read_cache(uint8_t pin) override; | ||||||
|  |   void digital_write_hw(uint8_t pin, bool value) override; | ||||||
|  |  | ||||||
|   // read a given register |   // read a given register | ||||||
|   bool read_reg_(uint8_t reg, uint8_t *value); |   bool read_reg_(uint8_t reg, uint8_t *value); | ||||||
|   // write a value to a given register |   // write a value to a given register | ||||||
| @@ -46,6 +50,8 @@ class MCP23016 : public Component, public i2c::I2CDevice { | |||||||
|  |  | ||||||
|   uint8_t olat_0_{0x00}; |   uint8_t olat_0_{0x00}; | ||||||
|   uint8_t olat_1_{0x00}; |   uint8_t olat_1_{0x00}; | ||||||
|  |   // Cache for input values (16-bit combined for both banks) | ||||||
|  |   uint16_t input_mask_{0x00}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class MCP23016GPIOPin : public GPIOPin { | class MCP23016GPIOPin : public GPIOPin { | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ from esphome.const import ( | |||||||
|  |  | ||||||
| CODEOWNERS = ["@Mat931"] | CODEOWNERS = ["@Mat931"] | ||||||
| DEPENDENCIES = ["i2c"] | DEPENDENCIES = ["i2c"] | ||||||
|  | AUTO_LOAD = ["gpio_expander"] | ||||||
| MULTI_CONF = True | MULTI_CONF = True | ||||||
| pca6416a_ns = cg.esphome_ns.namespace("pca6416a") | pca6416a_ns = cg.esphome_ns.namespace("pca6416a") | ||||||
|  |  | ||||||
|   | |||||||
| @@ -51,6 +51,11 @@ void PCA6416AComponent::setup() { | |||||||
|            this->status_has_error()); |            this->status_has_error()); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void PCA6416AComponent::loop() { | ||||||
|  |   // Invalidate cache at the start of each loop | ||||||
|  |   this->reset_pin_cache_(); | ||||||
|  | } | ||||||
|  |  | ||||||
| void PCA6416AComponent::dump_config() { | void PCA6416AComponent::dump_config() { | ||||||
|   if (this->has_pullup_) { |   if (this->has_pullup_) { | ||||||
|     ESP_LOGCONFIG(TAG, "PCAL6416A:"); |     ESP_LOGCONFIG(TAG, "PCAL6416A:"); | ||||||
| @@ -63,15 +68,25 @@ void PCA6416AComponent::dump_config() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| bool PCA6416AComponent::digital_read(uint8_t pin) { | bool PCA6416AComponent::digital_read_hw(uint8_t pin) { | ||||||
|   uint8_t bit = pin % 8; |  | ||||||
|   uint8_t reg_addr = pin < 8 ? PCA6416A_INPUT0 : PCA6416A_INPUT1; |   uint8_t reg_addr = pin < 8 ? PCA6416A_INPUT0 : PCA6416A_INPUT1; | ||||||
|   uint8_t value = 0; |   uint8_t value = 0; | ||||||
|   this->read_register_(reg_addr, &value); |   if (!this->read_register_(reg_addr, &value)) { | ||||||
|   return value & (1 << bit); |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Update the appropriate part of input_mask_ | ||||||
|  |   if (pin < 8) { | ||||||
|  |     this->input_mask_ = (this->input_mask_ & 0xFF00) | value; | ||||||
|  |   } else { | ||||||
|  |     this->input_mask_ = (this->input_mask_ & 0x00FF) | (uint16_t(value) << 8); | ||||||
|  |   } | ||||||
|  |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| void PCA6416AComponent::digital_write(uint8_t pin, bool value) { | bool PCA6416AComponent::digital_read_cache(uint8_t pin) { return this->input_mask_ & (1 << pin); } | ||||||
|  |  | ||||||
|  | void PCA6416AComponent::digital_write_hw(uint8_t pin, bool value) { | ||||||
|   uint8_t reg_addr = pin < 8 ? PCA6416A_OUTPUT0 : PCA6416A_OUTPUT1; |   uint8_t reg_addr = pin < 8 ? PCA6416A_OUTPUT0 : PCA6416A_OUTPUT1; | ||||||
|   this->update_register_(pin, value, reg_addr); |   this->update_register_(pin, value, reg_addr); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,20 +3,20 @@ | |||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
| #include "esphome/components/i2c/i2c.h" | #include "esphome/components/i2c/i2c.h" | ||||||
|  | #include "esphome/components/gpio_expander/cached_gpio.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace pca6416a { | namespace pca6416a { | ||||||
|  |  | ||||||
| class PCA6416AComponent : public Component, public i2c::I2CDevice { | class PCA6416AComponent : public Component, | ||||||
|  |                           public i2c::I2CDevice, | ||||||
|  |                           public gpio_expander::CachedGpioExpander<uint8_t, 16> { | ||||||
|  public: |  public: | ||||||
|   PCA6416AComponent() = default; |   PCA6416AComponent() = default; | ||||||
|  |  | ||||||
|   /// Check i2c availability and setup masks |   /// Check i2c availability and setup masks | ||||||
|   void setup() override; |   void setup() override; | ||||||
|   /// Helper function to read the value of a pin. |   void loop() override; | ||||||
|   bool digital_read(uint8_t pin); |  | ||||||
|   /// Helper function to write the value of a pin. |  | ||||||
|   void digital_write(uint8_t pin, bool value); |  | ||||||
|   /// Helper function to set the pin mode of a pin. |   /// Helper function to set the pin mode of a pin. | ||||||
|   void pin_mode(uint8_t pin, gpio::Flags flags); |   void pin_mode(uint8_t pin, gpio::Flags flags); | ||||||
|  |  | ||||||
| @@ -25,6 +25,11 @@ class PCA6416AComponent : public Component, public i2c::I2CDevice { | |||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|  |   // Virtual methods from CachedGpioExpander | ||||||
|  |   bool digital_read_hw(uint8_t pin) override; | ||||||
|  |   bool digital_read_cache(uint8_t pin) override; | ||||||
|  |   void digital_write_hw(uint8_t pin, bool value) override; | ||||||
|  |  | ||||||
|   bool read_register_(uint8_t reg, uint8_t *value); |   bool read_register_(uint8_t reg, uint8_t *value); | ||||||
|   bool write_register_(uint8_t reg, uint8_t value); |   bool write_register_(uint8_t reg, uint8_t value); | ||||||
|   void update_register_(uint8_t pin, bool pin_value, uint8_t reg_addr); |   void update_register_(uint8_t pin, bool pin_value, uint8_t reg_addr); | ||||||
| @@ -32,6 +37,8 @@ class PCA6416AComponent : public Component, public i2c::I2CDevice { | |||||||
|   /// The mask to write as output state - 1 means HIGH, 0 means LOW |   /// The mask to write as output state - 1 means HIGH, 0 means LOW | ||||||
|   uint8_t output_0_{0x00}; |   uint8_t output_0_{0x00}; | ||||||
|   uint8_t output_1_{0x00}; |   uint8_t output_1_{0x00}; | ||||||
|  |   /// Cache for input values (16-bit combined for both banks) | ||||||
|  |   uint16_t input_mask_{0x00}; | ||||||
|   /// Storage for last I2C error seen |   /// Storage for last I2C error seen | ||||||
|   esphome::i2c::ErrorCode last_error_; |   esphome::i2c::ErrorCode last_error_; | ||||||
|   /// Only the PCAL6416A has pull-up resistors |   /// Only the PCAL6416A has pull-up resistors | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ CONF_SCAN_TIME = "scan_time" | |||||||
| CONF_DEBOUNCE_TIME = "debounce_time" | CONF_DEBOUNCE_TIME = "debounce_time" | ||||||
| CONF_SX1509_ID = "sx1509_id" | CONF_SX1509_ID = "sx1509_id" | ||||||
|  |  | ||||||
| AUTO_LOAD = ["key_provider"] | AUTO_LOAD = ["key_provider", "gpio_expander"] | ||||||
| DEPENDENCIES = ["i2c"] | DEPENDENCIES = ["i2c"] | ||||||
| MULTI_CONF = True | MULTI_CONF = True | ||||||
|  |  | ||||||
|   | |||||||
| @@ -39,6 +39,9 @@ void SX1509Component::dump_config() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void SX1509Component::loop() { | void SX1509Component::loop() { | ||||||
|  |   // Reset cache at the start of each loop | ||||||
|  |   this->reset_pin_cache_(); | ||||||
|  |  | ||||||
|   if (this->has_keypad_) { |   if (this->has_keypad_) { | ||||||
|     if (millis() - this->last_loop_timestamp_ < min_loop_period_) |     if (millis() - this->last_loop_timestamp_ < min_loop_period_) | ||||||
|       return; |       return; | ||||||
| @@ -73,18 +76,20 @@ void SX1509Component::loop() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| bool SX1509Component::digital_read(uint8_t pin) { | bool SX1509Component::digital_read_hw(uint8_t pin) { | ||||||
|  |   // Always read all pins when any input pin is accessed | ||||||
|  |   return this->read_byte_16(REG_DATA_B, &this->input_mask_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool SX1509Component::digital_read_cache(uint8_t pin) { | ||||||
|  |   // Return cached value for input pins, false for output pins | ||||||
|   if (this->ddr_mask_ & (1 << pin)) { |   if (this->ddr_mask_ & (1 << pin)) { | ||||||
|     uint16_t temp_reg_data; |     return this->input_mask_ & (1 << pin); | ||||||
|     if (!this->read_byte_16(REG_DATA_B, &temp_reg_data)) |  | ||||||
|       return false; |  | ||||||
|     if (temp_reg_data & (1 << pin)) |  | ||||||
|       return true; |  | ||||||
|   } |   } | ||||||
|   return false; |   return false; | ||||||
| } | } | ||||||
|  |  | ||||||
| void SX1509Component::digital_write(uint8_t pin, bool bit_value) { | void SX1509Component::digital_write_hw(uint8_t pin, bool bit_value) { | ||||||
|   if ((~this->ddr_mask_) & (1 << pin)) { |   if ((~this->ddr_mask_) & (1 << pin)) { | ||||||
|     // If the pin is an output, write high/low |     // If the pin is an output, write high/low | ||||||
|     uint16_t temp_reg_data = 0; |     uint16_t temp_reg_data = 0; | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ | |||||||
|  |  | ||||||
| #include "esphome/components/i2c/i2c.h" | #include "esphome/components/i2c/i2c.h" | ||||||
| #include "esphome/components/key_provider/key_provider.h" | #include "esphome/components/key_provider/key_provider.h" | ||||||
|  | #include "esphome/components/gpio_expander/cached_gpio.h" | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
| #include "sx1509_gpio_pin.h" | #include "sx1509_gpio_pin.h" | ||||||
| @@ -30,7 +31,10 @@ class SX1509Processor { | |||||||
|  |  | ||||||
| class SX1509KeyTrigger : public Trigger<uint8_t> {}; | class SX1509KeyTrigger : public Trigger<uint8_t> {}; | ||||||
|  |  | ||||||
| class SX1509Component : public Component, public i2c::I2CDevice, public key_provider::KeyProvider { | class SX1509Component : public Component, | ||||||
|  |                         public i2c::I2CDevice, | ||||||
|  |                         public gpio_expander::CachedGpioExpander<uint16_t, 16>, | ||||||
|  |                         public key_provider::KeyProvider { | ||||||
|  public: |  public: | ||||||
|   SX1509Component() = default; |   SX1509Component() = default; | ||||||
|  |  | ||||||
| @@ -39,11 +43,9 @@ class SX1509Component : public Component, public i2c::I2CDevice, public key_prov | |||||||
|   float get_setup_priority() const override { return setup_priority::HARDWARE; } |   float get_setup_priority() const override { return setup_priority::HARDWARE; } | ||||||
|   void loop() override; |   void loop() override; | ||||||
|  |  | ||||||
|   bool digital_read(uint8_t pin); |  | ||||||
|   uint16_t read_key_data(); |   uint16_t read_key_data(); | ||||||
|   void set_pin_value(uint8_t pin, uint8_t i_on) { this->write_byte(REG_I_ON[pin], i_on); }; |   void set_pin_value(uint8_t pin, uint8_t i_on) { this->write_byte(REG_I_ON[pin], i_on); }; | ||||||
|   void pin_mode(uint8_t pin, gpio::Flags flags); |   void pin_mode(uint8_t pin, gpio::Flags flags); | ||||||
|   void digital_write(uint8_t pin, bool bit_value); |  | ||||||
|   uint32_t get_clock() { return this->clk_x_; }; |   uint32_t get_clock() { return this->clk_x_; }; | ||||||
|   void set_rows_cols(uint8_t rows, uint8_t cols) { |   void set_rows_cols(uint8_t rows, uint8_t cols) { | ||||||
|     this->rows_ = rows; |     this->rows_ = rows; | ||||||
| @@ -61,10 +63,15 @@ class SX1509Component : public Component, public i2c::I2CDevice, public key_prov | |||||||
|   void setup_led_driver(uint8_t pin); |   void setup_led_driver(uint8_t pin); | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|  |   // Virtual methods from CachedGpioExpander | ||||||
|  |   bool digital_read_hw(uint8_t pin) override; | ||||||
|  |   bool digital_read_cache(uint8_t pin) override; | ||||||
|  |   void digital_write_hw(uint8_t pin, bool value) override; | ||||||
|  |  | ||||||
|   uint32_t clk_x_ = 2000000; |   uint32_t clk_x_ = 2000000; | ||||||
|   uint8_t frequency_ = 0; |   uint8_t frequency_ = 0; | ||||||
|   uint16_t ddr_mask_ = 0x00; |   uint16_t ddr_mask_ = 0x00; | ||||||
|   uint16_t input_mask_ = 0x00; |   uint16_t input_mask_ = 0x00;  // Cache for input values (16-bit for all pins) | ||||||
|   uint16_t port_mask_ = 0x00; |   uint16_t port_mask_ = 0x00; | ||||||
|   uint16_t output_state_ = 0x00; |   uint16_t output_state_ = 0x00; | ||||||
|   bool has_keypad_ = false; |   bool has_keypad_ = false; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user