mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Add cd74hc4067 multiplexer (#2431)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: asoehlke <git@soehlke.de>
This commit is contained in:
		| @@ -37,6 +37,7 @@ esphome/components/canbus/* @danielschramm @mvturnho | |||||||
| esphome/components/cap1188/* @MrEditor97 | 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/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 | ||||||
|   | |||||||
							
								
								
									
										53
									
								
								esphome/components/cd74hc4067/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								esphome/components/cd74hc4067/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | from esphome import pins | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_DELAY, | ||||||
|  |     CONF_ID, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@asoehlke"] | ||||||
|  | AUTO_LOAD = ["sensor", "voltage_sampler"] | ||||||
|  |  | ||||||
|  | cd74hc4067_ns = cg.esphome_ns.namespace("cd74hc4067") | ||||||
|  |  | ||||||
|  | CD74HC4067Component = cd74hc4067_ns.class_( | ||||||
|  |     "CD74HC4067Component", cg.Component, cg.PollingComponent | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONF_PIN_S0 = "pin_s0" | ||||||
|  | CONF_PIN_S1 = "pin_s1" | ||||||
|  | CONF_PIN_S2 = "pin_s2" | ||||||
|  | CONF_PIN_S3 = "pin_s3" | ||||||
|  |  | ||||||
|  | DEFAULT_DELAY = "2ms" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.declare_id(CD74HC4067Component), | ||||||
|  |         cv.Required(CONF_PIN_S0): pins.internal_gpio_output_pin_schema, | ||||||
|  |         cv.Required(CONF_PIN_S1): pins.internal_gpio_output_pin_schema, | ||||||
|  |         cv.Required(CONF_PIN_S2): pins.internal_gpio_output_pin_schema, | ||||||
|  |         cv.Required(CONF_PIN_S3): pins.internal_gpio_output_pin_schema, | ||||||
|  |         cv.Optional( | ||||||
|  |             CONF_DELAY, default=DEFAULT_DELAY | ||||||
|  |         ): 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) | ||||||
|  |  | ||||||
|  |     pin_s0 = await cg.gpio_pin_expression(config[CONF_PIN_S0]) | ||||||
|  |     cg.add(var.set_pin_s0(pin_s0)) | ||||||
|  |     pin_s1 = await cg.gpio_pin_expression(config[CONF_PIN_S1]) | ||||||
|  |     cg.add(var.set_pin_s1(pin_s1)) | ||||||
|  |     pin_s2 = await cg.gpio_pin_expression(config[CONF_PIN_S2]) | ||||||
|  |     cg.add(var.set_pin_s2(pin_s2)) | ||||||
|  |     pin_s3 = await cg.gpio_pin_expression(config[CONF_PIN_S3]) | ||||||
|  |     cg.add(var.set_pin_s3(pin_s3)) | ||||||
|  |  | ||||||
|  |     cg.add(var.set_switch_delay(config[CONF_DELAY])) | ||||||
							
								
								
									
										86
									
								
								esphome/components/cd74hc4067/cd74hc4067.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								esphome/components/cd74hc4067/cd74hc4067.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | |||||||
|  | #include "cd74hc4067.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace cd74hc4067 { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "cd74hc4067"; | ||||||
|  |  | ||||||
|  | float CD74HC4067Component::get_setup_priority() const { return setup_priority::DATA; } | ||||||
|  |  | ||||||
|  | void CD74HC4067Component::setup() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up CD74HC4067..."); | ||||||
|  |  | ||||||
|  |   this->pin_s0_->setup(); | ||||||
|  |   this->pin_s1_->setup(); | ||||||
|  |   this->pin_s2_->setup(); | ||||||
|  |   this->pin_s3_->setup(); | ||||||
|  |  | ||||||
|  |   // set other pin, so that activate_pin will really switch | ||||||
|  |   this->active_pin_ = 1; | ||||||
|  |   this->activate_pin(0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void CD74HC4067Component::dump_config() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "CD74HC4067 Multiplexer:"); | ||||||
|  |   LOG_PIN("  S0 Pin: ", this->pin_s0_); | ||||||
|  |   LOG_PIN("  S1 Pin: ", this->pin_s1_); | ||||||
|  |   LOG_PIN("  S2 Pin: ", this->pin_s2_); | ||||||
|  |   LOG_PIN("  S3 Pin: ", this->pin_s3_); | ||||||
|  |   ESP_LOGCONFIG(TAG, "switch delay: %d", this->switch_delay_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void CD74HC4067Component::activate_pin(uint8_t pin) { | ||||||
|  |   if (this->active_pin_ != pin) { | ||||||
|  |     ESP_LOGD(TAG, "switch to input %d", pin); | ||||||
|  |  | ||||||
|  |     static int mux_channel[16][4] = { | ||||||
|  |         {0, 0, 0, 0},  // channel 0 | ||||||
|  |         {1, 0, 0, 0},  // channel 1 | ||||||
|  |         {0, 1, 0, 0},  // channel 2 | ||||||
|  |         {1, 1, 0, 0},  // channel 3 | ||||||
|  |         {0, 0, 1, 0},  // channel 4 | ||||||
|  |         {1, 0, 1, 0},  // channel 5 | ||||||
|  |         {0, 1, 1, 0},  // channel 6 | ||||||
|  |         {1, 1, 1, 0},  // channel 7 | ||||||
|  |         {0, 0, 0, 1},  // channel 8 | ||||||
|  |         {1, 0, 0, 1},  // channel 9 | ||||||
|  |         {0, 1, 0, 1},  // channel 10 | ||||||
|  |         {1, 1, 0, 1},  // channel 11 | ||||||
|  |         {0, 0, 1, 1},  // channel 12 | ||||||
|  |         {1, 0, 1, 1},  // channel 13 | ||||||
|  |         {0, 1, 1, 1},  // channel 14 | ||||||
|  |         {1, 1, 1, 1}   // channel 15 | ||||||
|  |     }; | ||||||
|  |     this->pin_s0_->digital_write(mux_channel[pin][0]); | ||||||
|  |     this->pin_s1_->digital_write(mux_channel[pin][1]); | ||||||
|  |     this->pin_s2_->digital_write(mux_channel[pin][2]); | ||||||
|  |     this->pin_s3_->digital_write(mux_channel[pin][3]); | ||||||
|  |     // small delay is needed to let the multiplexer switch | ||||||
|  |     delay(this->switch_delay_); | ||||||
|  |     this->active_pin_ = pin; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CD74HC4067Sensor::CD74HC4067Sensor(CD74HC4067Component *parent) : parent_(parent) {} | ||||||
|  |  | ||||||
|  | void CD74HC4067Sensor::update() { | ||||||
|  |   float value_v = this->sample(); | ||||||
|  |   this->publish_state(value_v); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float CD74HC4067Sensor::get_setup_priority() const { return this->parent_->get_setup_priority() - 1.0f; } | ||||||
|  |  | ||||||
|  | float CD74HC4067Sensor::sample() { | ||||||
|  |   this->parent_->activate_pin(this->pin_); | ||||||
|  |   return this->source_->sample(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void CD74HC4067Sensor::dump_config() { | ||||||
|  |   LOG_SENSOR(TAG, "CD74HC4067 Sensor", this); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Pin: %u", this->pin_); | ||||||
|  |   LOG_UPDATE_INTERVAL(this); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace cd74hc4067 | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										65
									
								
								esphome/components/cd74hc4067/cd74hc4067.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								esphome/components/cd74hc4067/cd74hc4067.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/hal.h" | ||||||
|  | #include "esphome/components/sensor/sensor.h" | ||||||
|  | #include "esphome/components/voltage_sampler/voltage_sampler.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace cd74hc4067 { | ||||||
|  |  | ||||||
|  | class CD74HC4067Component : public Component { | ||||||
|  |  public: | ||||||
|  |   /// Set up the internal sensor array. | ||||||
|  |   void setup() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |   float get_setup_priority() const override; | ||||||
|  |  | ||||||
|  |   /// setting pin active by setting the right combination of the four multiplexer input pins | ||||||
|  |   void activate_pin(uint8_t pin); | ||||||
|  |  | ||||||
|  |   /// set the pin connected to multiplexer control pin 0 | ||||||
|  |   void set_pin_s0(InternalGPIOPin *pin) { this->pin_s0_ = pin; } | ||||||
|  |   /// set the pin connected to multiplexer control pin 1 | ||||||
|  |   void set_pin_s1(InternalGPIOPin *pin) { this->pin_s1_ = pin; } | ||||||
|  |   /// set the pin connected to multiplexer control pin 2 | ||||||
|  |   void set_pin_s2(InternalGPIOPin *pin) { this->pin_s2_ = pin; } | ||||||
|  |   /// set the pin connected to multiplexer control pin 3 | ||||||
|  |   void set_pin_s3(InternalGPIOPin *pin) { this->pin_s3_ = pin; } | ||||||
|  |  | ||||||
|  |   /// set the delay needed after an input switch | ||||||
|  |   void set_switch_delay(uint32_t switch_delay) { this->switch_delay_ = switch_delay; } | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   InternalGPIOPin *pin_s0_; | ||||||
|  |   InternalGPIOPin *pin_s1_; | ||||||
|  |   InternalGPIOPin *pin_s2_; | ||||||
|  |   InternalGPIOPin *pin_s3_; | ||||||
|  |   /// the currently active pin | ||||||
|  |   uint8_t active_pin_; | ||||||
|  |   uint32_t switch_delay_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class CD74HC4067Sensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler { | ||||||
|  |  public: | ||||||
|  |   CD74HC4067Sensor(CD74HC4067Component *parent); | ||||||
|  |  | ||||||
|  |   void update() override; | ||||||
|  |  | ||||||
|  |   void dump_config() override; | ||||||
|  |   /// `HARDWARE_LATE` setup priority. | ||||||
|  |   float get_setup_priority() const override; | ||||||
|  |   void set_pin(uint8_t pin) { this->pin_ = pin; } | ||||||
|  |   void set_source(voltage_sampler::VoltageSampler *source) { this->source_ = source; } | ||||||
|  |  | ||||||
|  |   float sample() override; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   CD74HC4067Component *parent_; | ||||||
|  |   /// The sampling source to read values from. | ||||||
|  |   voltage_sampler::VoltageSampler *source_; | ||||||
|  |  | ||||||
|  |   uint8_t pin_; | ||||||
|  | }; | ||||||
|  | }  // namespace cd74hc4067 | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										55
									
								
								esphome/components/cd74hc4067/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								esphome/components/cd74hc4067/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import sensor, voltage_sampler | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_SENSOR, | ||||||
|  |     CONF_NUMBER, | ||||||
|  |     ICON_FLASH, | ||||||
|  |     UNIT_VOLT, | ||||||
|  |     STATE_CLASS_MEASUREMENT, | ||||||
|  |     DEVICE_CLASS_VOLTAGE, | ||||||
|  | ) | ||||||
|  | from . import cd74hc4067_ns, CD74HC4067Component | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ["cd74hc4067"] | ||||||
|  |  | ||||||
|  | CD74HC4067Sensor = cd74hc4067_ns.class_( | ||||||
|  |     "CD74HC4067Sensor", | ||||||
|  |     sensor.Sensor, | ||||||
|  |     cg.PollingComponent, | ||||||
|  |     voltage_sampler.VoltageSampler, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONF_CD74HC4067_ID = "cd74hc4067_id" | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = ( | ||||||
|  |     sensor.sensor_schema( | ||||||
|  |         unit_of_measurement=UNIT_VOLT, | ||||||
|  |         accuracy_decimals=3, | ||||||
|  |         device_class=DEVICE_CLASS_VOLTAGE, | ||||||
|  |         state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |         icon=ICON_FLASH, | ||||||
|  |     ) | ||||||
|  |     .extend( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(CD74HC4067Sensor), | ||||||
|  |             cv.GenerateID(CONF_CD74HC4067_ID): cv.use_id(CD74HC4067Component), | ||||||
|  |             cv.Required(CONF_NUMBER): cv.int_range(0, 15), | ||||||
|  |             cv.Required(CONF_SENSOR): cv.use_id(voltage_sampler.VoltageSampler), | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |     .extend(cv.polling_component_schema("60s")) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     parent = await cg.get_variable(config[CONF_CD74HC4067_ID]) | ||||||
|  |  | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID], parent) | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |     await sensor.register_sensor(var, config) | ||||||
|  |     cg.add(var.set_pin(config[CONF_NUMBER])) | ||||||
|  |  | ||||||
|  |     sens = await cg.get_variable(config[CONF_SENSOR]) | ||||||
|  |     cg.add(var.set_source(sens)) | ||||||
| @@ -378,6 +378,10 @@ sensor: | |||||||
|             - 400 -> 500 |             - 400 -> 500 | ||||||
|             - -50 -> -1000 |             - -50 -> -1000 | ||||||
|             - -100 -> -10000 |             - -100 -> -10000 | ||||||
|  |   - platform: cd74hc4067 | ||||||
|  |     id: cd74hc4067_0 | ||||||
|  |     number: 0 | ||||||
|  |     sensor: my_sensor | ||||||
|   - platform: resistance |   - platform: resistance | ||||||
|     sensor: my_sensor |     sensor: my_sensor | ||||||
|     configuration: DOWNSTREAM |     configuration: DOWNSTREAM | ||||||
| @@ -1345,3 +1349,9 @@ dsmr: | |||||||
| daly_bms: | daly_bms: | ||||||
|   update_interval: 20s |   update_interval: 20s | ||||||
|   uart_id: uart1 |   uart_id: uart1 | ||||||
|  |  | ||||||
|  | cd74hc4067: | ||||||
|  |   pin_s0: GPIO12 | ||||||
|  |   pin_s1: GPIO13 | ||||||
|  |   pin_s2: GPIO14 | ||||||
|  |   pin_s3: GPIO15 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user