mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +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/captive_portal/* @OttoWinter | ||||
| esphome/components/ccs811/* @habbie | ||||
| esphome/components/cd74hc4067/* @asoehlke | ||||
| esphome/components/climate/* @esphome/core | ||||
| esphome/components/climate_ir/* @glmnet | ||||
| 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 | ||||
|             - -50 -> -1000 | ||||
|             - -100 -> -10000 | ||||
|   - platform: cd74hc4067 | ||||
|     id: cd74hc4067_0 | ||||
|     number: 0 | ||||
|     sensor: my_sensor | ||||
|   - platform: resistance | ||||
|     sensor: my_sensor | ||||
|     configuration: DOWNSTREAM | ||||
| @@ -1345,3 +1349,9 @@ dsmr: | ||||
| daly_bms: | ||||
|   update_interval: 20s | ||||
|   uart_id: uart1 | ||||
|  | ||||
| cd74hc4067: | ||||
|   pin_s0: GPIO12 | ||||
|   pin_s1: GPIO13 | ||||
|   pin_s2: GPIO14 | ||||
|   pin_s3: GPIO15 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user