mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	CH422G support (#7356)
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							3a7aabb2eb
						
					
				
				
					commit
					6490fc9c62
				
			| @@ -83,6 +83,7 @@ esphome/components/cap1188/* @mreditor97 | |||||||
| esphome/components/captive_portal/* @OttoWinter | esphome/components/captive_portal/* @OttoWinter | ||||||
| esphome/components/ccs811/* @habbie | esphome/components/ccs811/* @habbie | ||||||
| esphome/components/cd74hc4067/* @asoehlke | esphome/components/cd74hc4067/* @asoehlke | ||||||
|  | esphome/components/ch422g/* @jesterret | ||||||
| esphome/components/climate/* @esphome/core | esphome/components/climate/* @esphome/core | ||||||
| esphome/components/climate_ir/* @glmnet | esphome/components/climate_ir/* @glmnet | ||||||
| esphome/components/color_temperature/* @jesserockz | esphome/components/color_temperature/* @jesserockz | ||||||
|   | |||||||
							
								
								
									
										67
									
								
								esphome/components/ch422g/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								esphome/components/ch422g/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | from esphome import pins | ||||||
|  | import esphome.codegen as cg | ||||||
|  | from esphome.components import i2c | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_INPUT, | ||||||
|  |     CONF_INVERTED, | ||||||
|  |     CONF_MODE, | ||||||
|  |     CONF_NUMBER, | ||||||
|  |     CONF_OUTPUT, | ||||||
|  |     CONF_RESTORE_VALUE, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@jesterret"] | ||||||
|  | DEPENDENCIES = ["i2c"] | ||||||
|  | MULTI_CONF = True | ||||||
|  | ch422g_ns = cg.esphome_ns.namespace("ch422g") | ||||||
|  |  | ||||||
|  | CH422GComponent = ch422g_ns.class_("CH422GComponent", cg.Component, i2c.I2CDevice) | ||||||
|  | CH422GGPIOPin = ch422g_ns.class_( | ||||||
|  |     "CH422GGPIOPin", cg.GPIOPin, cg.Parented.template(CH422GComponent) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONF_CH422G = "ch422g" | ||||||
|  | CONFIG_SCHEMA = ( | ||||||
|  |     cv.Schema( | ||||||
|  |         { | ||||||
|  |             cv.Required(CONF_ID): cv.declare_id(CH422GComponent), | ||||||
|  |             cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean, | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |     .extend(cv.COMPONENT_SCHEMA) | ||||||
|  |     .extend(i2c.i2c_device_schema(0x24)) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     cg.add(var.set_restore_value(config[CONF_RESTORE_VALUE])) | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |     await i2c.register_i2c_device(var, config) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CH422G_PIN_SCHEMA = pins.gpio_base_schema( | ||||||
|  |     CH422GGPIOPin, | ||||||
|  |     cv.int_range(min=0, max=7), | ||||||
|  |     modes=[CONF_INPUT, CONF_OUTPUT], | ||||||
|  | ).extend( | ||||||
|  |     { | ||||||
|  |         cv.Required(CONF_CH422G): cv.use_id(CH422GComponent), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pins.PIN_SCHEMA_REGISTRY.register(CONF_CH422G, CH422G_PIN_SCHEMA) | ||||||
|  | async def ch422g_pin_to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     parent = await cg.get_variable(config[CONF_CH422G]) | ||||||
|  |  | ||||||
|  |     cg.add(var.set_parent(parent)) | ||||||
|  |  | ||||||
|  |     num = config[CONF_NUMBER] | ||||||
|  |     cg.add(var.set_pin(num)) | ||||||
|  |     cg.add(var.set_inverted(config[CONF_INVERTED])) | ||||||
|  |     cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) | ||||||
|  |     return var | ||||||
							
								
								
									
										122
									
								
								esphome/components/ch422g/ch422g.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								esphome/components/ch422g/ch422g.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | |||||||
|  | #include "ch422g.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace ch422g { | ||||||
|  |  | ||||||
|  | const uint8_t CH422G_REG_IN = 0x26; | ||||||
|  | const uint8_t CH422G_REG_OUT = 0x38; | ||||||
|  | const uint8_t OUT_REG_DEFAULT_VAL = 0xdf; | ||||||
|  |  | ||||||
|  | static const char *const TAG = "ch422g"; | ||||||
|  |  | ||||||
|  | void CH422GComponent::setup() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up CH422G..."); | ||||||
|  |   // Test to see if device exists | ||||||
|  |   if (!this->read_inputs_()) { | ||||||
|  |     ESP_LOGE(TAG, "CH422G not detected at 0x%02X", this->address_); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // restore defaults over whatever got saved on last boot | ||||||
|  |   if (!this->restore_value_) { | ||||||
|  |     this->write_output_(OUT_REG_DEFAULT_VAL); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ESP_LOGD(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(), | ||||||
|  |            this->status_has_error()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void CH422GComponent::loop() { | ||||||
|  |   // Clear all the previously read flags. | ||||||
|  |   this->pin_read_cache_ = 0x00; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void CH422GComponent::dump_config() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "CH422G:"); | ||||||
|  |   LOG_I2C_DEVICE(this) | ||||||
|  |   if (this->is_failed()) { | ||||||
|  |     ESP_LOGE(TAG, "Communication with CH422G failed!"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ch422g doesn't have any flag support (needs docs?) | ||||||
|  | void CH422GComponent::pin_mode(uint8_t pin, gpio::Flags flags) {} | ||||||
|  |  | ||||||
|  | bool CH422GComponent::digital_read(uint8_t pin) { | ||||||
|  |   if (this->pin_read_cache_ == 0 || this->pin_read_cache_ & (1 << pin)) { | ||||||
|  |     // Read values on first access or in case it's being read again in the same loop | ||||||
|  |     this->read_inputs_(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->pin_read_cache_ |= (1 << pin); | ||||||
|  |   return this->state_mask_ & (1 << pin); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void CH422GComponent::digital_write(uint8_t pin, bool value) { | ||||||
|  |   if (value) { | ||||||
|  |     this->write_output_(this->state_mask_ | (1 << pin)); | ||||||
|  |   } else { | ||||||
|  |     this->write_output_(this->state_mask_ & ~(1 << pin)); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool CH422GComponent::read_inputs_() { | ||||||
|  |   if (this->is_failed()) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   uint8_t temp = 0; | ||||||
|  |   if ((this->last_error_ = this->read(&temp, 1)) != esphome::i2c::ERROR_OK) { | ||||||
|  |     this->status_set_warning(str_sprintf("read_inputs_(): I2C I/O error: %d", (int) this->last_error_).c_str()); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   uint8_t output = 0; | ||||||
|  |   if ((this->last_error_ = this->bus_->read(CH422G_REG_IN, &output, 1)) != esphome::i2c::ERROR_OK) { | ||||||
|  |     this->status_set_warning(str_sprintf("read_inputs_(): I2C I/O error: %d", (int) this->last_error_).c_str()); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->state_mask_ = output; | ||||||
|  |   this->status_clear_warning(); | ||||||
|  |  | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool CH422GComponent::write_output_(uint8_t value) { | ||||||
|  |   const uint8_t temp = 1; | ||||||
|  |   if ((this->last_error_ = this->write(&temp, 1, false)) != esphome::i2c::ERROR_OK) { | ||||||
|  |     this->status_set_warning(str_sprintf("write_output_(): I2C I/O error: %d", (int) this->last_error_).c_str()); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   uint8_t write_mask = value; | ||||||
|  |   if ((this->last_error_ = this->bus_->write(CH422G_REG_OUT, &write_mask, 1)) != esphome::i2c::ERROR_OK) { | ||||||
|  |     this->status_set_warning( | ||||||
|  |         str_sprintf("write_output_(): I2C I/O error: %d for write_mask: %d", (int) this->last_error_, (int) write_mask) | ||||||
|  |             .c_str()); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->state_mask_ = value; | ||||||
|  |   this->status_clear_warning(); | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float CH422GComponent::get_setup_priority() const { return setup_priority::IO; } | ||||||
|  |  | ||||||
|  | // Run our loop() method very early in the loop, so that we cache read values | ||||||
|  | // before other components call our digital_read() method. | ||||||
|  | float CH422GComponent::get_loop_priority() const { return 9.0f; }  // Just after WIFI | ||||||
|  |  | ||||||
|  | void CH422GGPIOPin::setup() { pin_mode(flags_); } | ||||||
|  | void CH422GGPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); } | ||||||
|  | bool CH422GGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; } | ||||||
|  |  | ||||||
|  | void CH422GGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); } | ||||||
|  | std::string CH422GGPIOPin::dump_summary() const { return str_sprintf("EXIO%u via CH422G", pin_); } | ||||||
|  |  | ||||||
|  | }  // namespace ch422g | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										70
									
								
								esphome/components/ch422g/ch422g.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								esphome/components/ch422g/ch422g.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/hal.h" | ||||||
|  | #include "esphome/components/i2c/i2c.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace ch422g { | ||||||
|  |  | ||||||
|  | class CH422GComponent : public Component, public i2c::I2CDevice { | ||||||
|  |  public: | ||||||
|  |   CH422GComponent() = default; | ||||||
|  |  | ||||||
|  |   /// Check i2c availability and setup masks | ||||||
|  |   void setup() override; | ||||||
|  |   /// Poll for input changes periodically | ||||||
|  |   void loop() override; | ||||||
|  |   /// Helper function to read the value of a pin. | ||||||
|  |   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. | ||||||
|  |   void pin_mode(uint8_t pin, gpio::Flags flags); | ||||||
|  |  | ||||||
|  |   float get_setup_priority() const override; | ||||||
|  |  | ||||||
|  |   float get_loop_priority() const override; | ||||||
|  |  | ||||||
|  |   void dump_config() override; | ||||||
|  |  | ||||||
|  |   void set_restore_value(bool restore_value) { this->restore_value_ = restore_value; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool read_inputs_(); | ||||||
|  |  | ||||||
|  |   bool write_output_(uint8_t value); | ||||||
|  |  | ||||||
|  |   /// The mask to write as output state - 1 means HIGH, 0 means LOW | ||||||
|  |   uint8_t state_mask_{0x00}; | ||||||
|  |   /// Flags to check if read previously during this loop | ||||||
|  |   uint8_t pin_read_cache_ = {0x00}; | ||||||
|  |   /// Storage for last I2C error seen | ||||||
|  |   esphome::i2c::ErrorCode last_error_; | ||||||
|  |   /// Whether we want to override stored values on expander | ||||||
|  |   bool restore_value_{false}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// Helper class to expose a CH422G pin as an internal input GPIO pin. | ||||||
|  | class CH422GGPIOPin : public GPIOPin { | ||||||
|  |  public: | ||||||
|  |   void setup() override; | ||||||
|  |   void pin_mode(gpio::Flags flags) override; | ||||||
|  |   bool digital_read() override; | ||||||
|  |   void digital_write(bool value) override; | ||||||
|  |   std::string dump_summary() const override; | ||||||
|  |  | ||||||
|  |   void set_parent(CH422GComponent *parent) { parent_ = parent; } | ||||||
|  |   void set_pin(uint8_t pin) { pin_ = pin; } | ||||||
|  |   void set_inverted(bool inverted) { inverted_ = inverted; } | ||||||
|  |   void set_flags(gpio::Flags flags) { flags_ = flags; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   CH422GComponent *parent_; | ||||||
|  |   uint8_t pin_; | ||||||
|  |   bool inverted_; | ||||||
|  |   gpio::Flags flags_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace ch422g | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										20
									
								
								tests/components/ch422g/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								tests/components/ch422g/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | ch422g: | ||||||
|  |   - id: ch422g_hub | ||||||
|  |     address: 0x24 | ||||||
|  |  | ||||||
|  | binary_sensor: | ||||||
|  |   - platform: gpio | ||||||
|  |     id: ch422g_input | ||||||
|  |     name: CH422G Binary Sensor | ||||||
|  |     pin: | ||||||
|  |       ch422g: ch422g_hub | ||||||
|  |       number: 1 | ||||||
|  |       mode: INPUT | ||||||
|  |       inverted: true | ||||||
|  |   - platform: gpio | ||||||
|  |     id: ch422g_output | ||||||
|  |     pin: | ||||||
|  |       ch422g: ch422g_hub | ||||||
|  |       number: 0 | ||||||
|  |       mode: OUTPUT | ||||||
|  |       inverted: false | ||||||
							
								
								
									
										6
									
								
								tests/components/ch422g/test.esp32-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tests/components/ch422g/test.esp32-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | i2c: | ||||||
|  |   - id: i2c_ch422g | ||||||
|  |     scl: 16 | ||||||
|  |     sda: 17 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										6
									
								
								tests/components/ch422g/test.esp32-c3-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tests/components/ch422g/test.esp32-c3-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | i2c: | ||||||
|  |   - id: i2c_ch422g | ||||||
|  |     scl: 5 | ||||||
|  |     sda: 4 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										6
									
								
								tests/components/ch422g/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tests/components/ch422g/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | i2c: | ||||||
|  |   - id: i2c_ch422g | ||||||
|  |     scl: 5 | ||||||
|  |     sda: 4 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										6
									
								
								tests/components/ch422g/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tests/components/ch422g/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | i2c: | ||||||
|  |   - id: i2c_ch422g | ||||||
|  |     scl: 16 | ||||||
|  |     sda: 17 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										6
									
								
								tests/components/ch422g/test.esp8266-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tests/components/ch422g/test.esp8266-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | i2c: | ||||||
|  |   - id: i2c_ch422g | ||||||
|  |     scl: 5 | ||||||
|  |     sda: 4 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										6
									
								
								tests/components/ch422g/test.rp2040-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tests/components/ch422g/test.rp2040-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | i2c: | ||||||
|  |   - id: i2c_ch422g | ||||||
|  |     scl: 5 | ||||||
|  |     sda: 4 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
		Reference in New Issue
	
	Block a user