mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Add mcp4461 quad i2c digipot/rheostat component
This commit is contained in:
		
							
								
								
									
										42
									
								
								esphome/components/mcp4461/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								esphome/components/mcp4461/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import i2c | ||||
| from esphome.const import CONF_ID | ||||
|  | ||||
| CODEOWNERS = ["@p1ngb4ck"] | ||||
| DEPENDENCIES = ["i2c"] | ||||
| MULTI_CONF = True | ||||
| CONF_DISABLE_WIPER_0 = "disable_wiper_0" | ||||
| CONF_DISABLE_WIPER_1 = "disable_wiper_1" | ||||
| CONF_DISABLE_WIPER_2 = "disable_wiper_2" | ||||
| CONF_DISABLE_WIPER_3 = "disable_wiper_3" | ||||
|  | ||||
| mcp4461_ns = cg.esphome_ns.namespace("mcp4461") | ||||
| Mcp4461Component = mcp4461_ns.class_("Mcp4461Component", cg.Component, i2c.I2CDevice) | ||||
| CONF_MCP4461_ID = "mcp4461_id" | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(Mcp4461Component), | ||||
|             cv.Optional(CONF_DISABLE_WIPER_0, default=False): cv.boolean, | ||||
|             cv.Optional(CONF_DISABLE_WIPER_1, default=False): cv.boolean, | ||||
|             cv.Optional(CONF_DISABLE_WIPER_2, default=False): cv.boolean, | ||||
|             cv.Optional(CONF_DISABLE_WIPER_3, default=False): cv.boolean, | ||||
|         } | ||||
|     ) | ||||
|     .extend(cv.COMPONENT_SCHEMA) | ||||
|     .extend(i2c.i2c_device_schema(0x2C)) | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable( | ||||
|         config[CONF_ID], | ||||
|         config[CONF_DISABLE_WIPER_0], | ||||
|         config[CONF_DISABLE_WIPER_1], | ||||
|         config[CONF_DISABLE_WIPER_2], | ||||
|         config[CONF_DISABLE_WIPER_3], | ||||
|     ) | ||||
|     await cg.register_component(var, config) | ||||
|     await i2c.register_i2c_device(var, config) | ||||
							
								
								
									
										359
									
								
								esphome/components/mcp4461/mcp4461.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								esphome/components/mcp4461/mcp4461.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,359 @@ | ||||
| #include "mcp4461.h" | ||||
|  | ||||
| #include "esphome/core/helpers.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace mcp4461 { | ||||
|  | ||||
| static const char *const TAG = "mcp4461"; | ||||
|  | ||||
| void Mcp4461Component::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up mcp4461 (0x%02X)...", this->address_); | ||||
|   auto err = this->write(nullptr, 0); | ||||
|   if (err != i2c::ERROR_OK) { | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   } | ||||
|   this->begin_(); | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::begin_() { | ||||
|   for (uint8_t i = 0; i < 8; i++) { | ||||
|     if (this->reg_[i].enabled) { | ||||
|       this->reg_[i].state = this->get_wiper_level(i); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "mcp4461:"); | ||||
|   LOG_I2C_DEVICE(this); | ||||
|   if (this->is_failed()) { | ||||
|     ESP_LOGE(TAG, "Communication with mcp4461 failed!"); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::loop() { | ||||
|   if (this->update_) { | ||||
|     uint8_t i; | ||||
|     for (i = 0; i < 8; i++) { | ||||
|       // set wiper i state if changed | ||||
|       if (this->reg_[i].state != this->get_wiper_level(i)) { | ||||
|         this->write_wiper_level_(i, this->reg_[i].state); | ||||
|       } | ||||
|       // terminal register changes only applicable to wipers 0-3 ! | ||||
|       if (i < 4) { | ||||
|         // set terminal register changes | ||||
|         if (i == 0 || i == 2) { | ||||
|           Mcp4461TerminalIdx terminal_connector = Mcp4461TerminalIdx::MCP4461_TERMINAL_0; | ||||
|           if (i > 0) { | ||||
|             terminal_connector = Mcp4461TerminalIdx::MCP4461_TERMINAL_1; | ||||
|           } | ||||
|           uint8_t new_terminal_value = this->calc_terminal_connector_byte_(terminal_connector); | ||||
|           if (new_terminal_value != this->get_terminal_register(terminal_connector)) { | ||||
|             ESP_LOGV(TAG, "updating terminal %d to new value %d", (uint8_t) terminal_connector, new_terminal_value); | ||||
|             this->set_terminal_register(terminal_connector, new_terminal_value); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     this->update_ = false; | ||||
|   } | ||||
| } | ||||
|  | ||||
| uint16_t Mcp4461Component::get_status_register() { | ||||
|   uint8_t reg = 0; | ||||
|   reg |= (uint8_t) Mcp4461Addresses::MCP4461_STATUS; | ||||
|   reg |= (uint8_t) Mcp4461Commands::READ; | ||||
|   uint16_t buf; | ||||
|   if (!this->read_byte_16(reg, &buf)) { | ||||
|     this->status_set_warning(); | ||||
|     ESP_LOGW(TAG, "Error fetching status register value"); | ||||
|     return 0; | ||||
|   } | ||||
|   return buf; | ||||
| } | ||||
|  | ||||
| bool Mcp4461Component::is_writing_() { return (bool) ((this->get_status_register() >> 4) & 0x01); } | ||||
|  | ||||
| uint8_t Mcp4461Component::get_wiper_address_(uint8_t wiper) { | ||||
|   uint8_t addr; | ||||
|   bool nonvolatile = false; | ||||
|   if (wiper > 3) { | ||||
|     nonvolatile = true; | ||||
|     wiper = wiper - 4; | ||||
|   } | ||||
|   switch (wiper) { | ||||
|     case 0: | ||||
|       addr = (uint8_t) Mcp4461Addresses::MCP4461_VW0; | ||||
|       break; | ||||
|     case 1: | ||||
|       addr = (uint8_t) Mcp4461Addresses::MCP4461_VW1; | ||||
|       break; | ||||
|     case 2: | ||||
|       addr = (uint8_t) Mcp4461Addresses::MCP4461_VW2; | ||||
|       break; | ||||
|     case 3: | ||||
|       addr = (uint8_t) Mcp4461Addresses::MCP4461_VW3; | ||||
|       break; | ||||
|     default: | ||||
|       ESP_LOGE(TAG, "unknown wiper specified"); | ||||
|       return 0; | ||||
|   } | ||||
|   if (nonvolatile) { | ||||
|     addr = addr + 0x20; | ||||
|   } | ||||
|   return addr; | ||||
| } | ||||
|  | ||||
| uint16_t Mcp4461Component::get_wiper_level(uint8_t wiper) { | ||||
|   uint8_t reg = 0; | ||||
|   uint16_t buf = 0; | ||||
|   reg |= this->get_wiper_address_(wiper); | ||||
|   reg |= (uint8_t) Mcp4461Commands::READ; | ||||
|   if (wiper > 3) { | ||||
|     while (this->is_writing_()) { | ||||
|       ESP_LOGV(TAG, "delaying during eeprom write"); | ||||
|     } | ||||
|   } | ||||
|   if (!this->read_byte_16(reg, &buf)) { | ||||
|     this->status_set_warning(); | ||||
|     if (wiper > 3) { | ||||
|       this->status_set_warning(); | ||||
|       ESP_LOGW(TAG, "Error fetching nonvolatile wiper %d value", wiper); | ||||
|     } else { | ||||
|       this->status_set_warning(); | ||||
|       ESP_LOGW(TAG, "Error fetching wiper %d value", wiper); | ||||
|     } | ||||
|     return 0; | ||||
|   } | ||||
|   return buf; | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::update_wiper_level(uint8_t wiper) { | ||||
|   uint16_t data; | ||||
|   data = this->get_wiper_level(wiper); | ||||
|   ESP_LOGV(TAG, "Got value %d from wiper %d", data, wiper); | ||||
|   this->reg_[wiper].state = data; | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::set_wiper_level(uint8_t wiper, uint16_t value) { | ||||
|   ESP_LOGV(TAG, "Setting MCP4461 wiper %d to %d!", wiper, value); | ||||
|   this->reg_[wiper].state = value; | ||||
|   this->update_ = true; | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::write_wiper_level_(uint8_t wiper, uint16_t value) { | ||||
|   if (wiper > 3) { | ||||
|     while (this->is_writing_()) { | ||||
|       ESP_LOGV(TAG, "delaying during eeprom write"); | ||||
|     } | ||||
|   } | ||||
|   this->mcp4461_write_(this->get_wiper_address_(wiper), value); | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::enable_wiper(uint8_t wiper) { | ||||
|   ESP_LOGV(TAG, "Enabling wiper %d", wiper); | ||||
|   this->reg_[wiper].terminal_hw = true; | ||||
|   this->update_ = true; | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::disable_wiper(uint8_t wiper) { | ||||
|   ESP_LOGV(TAG, "Disabling wiper %d", wiper); | ||||
|   this->reg_[wiper].terminal_hw = false; | ||||
|   this->update_ = true; | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::increase_wiper(uint8_t wiper) { | ||||
|   ESP_LOGV(TAG, "Increasing wiper %d", wiper); | ||||
|   uint8_t reg = 0; | ||||
|   uint8_t addr; | ||||
|   addr = this->get_wiper_address_(wiper); | ||||
|   reg |= addr; | ||||
|   reg |= (uint8_t) Mcp4461Commands::INCREMENT; | ||||
|   this->write(&this->address_, reg, sizeof(reg)); | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::decrease_wiper(uint8_t wiper) { | ||||
|   ESP_LOGV(TAG, "Decreasing wiper %d", wiper); | ||||
|   uint8_t reg = 0; | ||||
|   uint8_t addr; | ||||
|   addr = this->get_wiper_address_(wiper); | ||||
|   reg |= addr; | ||||
|   reg |= (uint8_t) Mcp4461Commands::DECREMENT; | ||||
|   this->write(&this->address_, reg, sizeof(reg)); | ||||
| } | ||||
|  | ||||
| uint8_t Mcp4461Component::calc_terminal_connector_byte_(Mcp4461TerminalIdx terminal_connector) { | ||||
|   uint8_t i; | ||||
|   if (((uint8_t) terminal_connector == 0 || (uint8_t) terminal_connector == 1)) { | ||||
|     i = 0; | ||||
|   } else { | ||||
|     i = 2; | ||||
|   } | ||||
|   uint8_t new_value_byte_array[8]; | ||||
|   new_value_byte_array[0] = (uint8_t) this->reg_[i].terminal_b; | ||||
|   new_value_byte_array[1] = (uint8_t) this->reg_[i].terminal_w; | ||||
|   new_value_byte_array[2] = (uint8_t) this->reg_[i].terminal_a; | ||||
|   new_value_byte_array[3] = (uint8_t) this->reg_[i].terminal_hw; | ||||
|   new_value_byte_array[4] = (uint8_t) this->reg_[(i + 1)].terminal_b; | ||||
|   new_value_byte_array[5] = (uint8_t) this->reg_[(i + 1)].terminal_w; | ||||
|   new_value_byte_array[6] = (uint8_t) this->reg_[(i + 1)].terminal_a; | ||||
|   new_value_byte_array[7] = (uint8_t) this->reg_[(i + 1)].terminal_hw; | ||||
|   unsigned char new_value_byte = 0; | ||||
|   uint8_t b; | ||||
|   for (b = 0; b < 8; b++) { | ||||
|     new_value_byte += (new_value_byte_array[b] << (7 - b)); | ||||
|   } | ||||
|   return (uint8_t) new_value_byte; | ||||
| } | ||||
|  | ||||
| uint8_t Mcp4461Component::get_terminal_register(Mcp4461TerminalIdx terminal_connector) { | ||||
|   uint8_t reg = 0; | ||||
|   if ((uint8_t) terminal_connector == 0) { | ||||
|     reg |= (uint8_t) Mcp4461Addresses::MCP4461_TCON0; | ||||
|   } else { | ||||
|     reg |= (uint8_t) Mcp4461Addresses::MCP4461_TCON1; | ||||
|   } | ||||
|   reg |= (uint8_t) Mcp4461Commands::READ; | ||||
|   uint16_t buf; | ||||
|   if (!this->read_byte_16(reg, &buf)) { | ||||
|     this->status_set_warning(); | ||||
|     ESP_LOGW(TAG, "Error fetching terminal register value"); | ||||
|     return 0; | ||||
|   } | ||||
|   return (uint8_t) (buf & 0x00ff); | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::update_terminal_register(Mcp4461TerminalIdx terminal_connector) { | ||||
|   if (((uint8_t) terminal_connector != 0 && (uint8_t) terminal_connector != 1)) { | ||||
|     return; | ||||
|   } | ||||
|   uint8_t terminal_data; | ||||
|   terminal_data = this->get_terminal_register(terminal_connector); | ||||
|   ESP_LOGV(TAG, "Got terminal register %d data %0xh", (uint8_t) terminal_connector, terminal_data); | ||||
|   uint8_t wiper_index = 0; | ||||
|   if ((uint8_t) terminal_connector == 1) { | ||||
|     wiper_index = 2; | ||||
|   } | ||||
|   this->reg_[wiper_index].terminal_b = ((terminal_data >> 0) & 0x01); | ||||
|   this->reg_[wiper_index].terminal_w = ((terminal_data >> 1) & 0x01); | ||||
|   this->reg_[wiper_index].terminal_a = ((terminal_data >> 2) & 0x01); | ||||
|   this->reg_[wiper_index].terminal_hw = ((terminal_data >> 3) & 0x01); | ||||
|   this->reg_[(wiper_index + 1)].terminal_b = ((terminal_data >> 4) & 0x01); | ||||
|   this->reg_[(wiper_index + 1)].terminal_w = ((terminal_data >> 5) & 0x01); | ||||
|   this->reg_[(wiper_index + 1)].terminal_a = ((terminal_data >> 6) & 0x01); | ||||
|   this->reg_[(wiper_index + 1)].terminal_hw = ((terminal_data >> 7) & 0x01); | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::set_terminal_register(Mcp4461TerminalIdx terminal_connector, uint8_t data) { | ||||
|   uint8_t addr; | ||||
|   if ((uint8_t) terminal_connector == 0) { | ||||
|     addr = (uint8_t) Mcp4461Addresses::MCP4461_TCON0; | ||||
|   } else if ((uint8_t) terminal_connector == 1) { | ||||
|     addr = (uint8_t) Mcp4461Addresses::MCP4461_TCON1; | ||||
|   } else { | ||||
|     return; | ||||
|   } | ||||
|   this->mcp4461_write_(addr, data); | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::enable_terminal(uint8_t wiper, char terminal) { | ||||
|   if (wiper > 3) { | ||||
|     return; | ||||
|   } | ||||
|   ESP_LOGV(TAG, "Enabling terminal %c of wiper %d", terminal, wiper); | ||||
|   switch (terminal) { | ||||
|     case 'h': | ||||
|       this->reg_[wiper].terminal_hw = true; | ||||
|       break; | ||||
|     case 'a': | ||||
|       this->reg_[wiper].terminal_a = true; | ||||
|       break; | ||||
|     case 'b': | ||||
|       this->reg_[wiper].terminal_b = true; | ||||
|       break; | ||||
|     case 'w': | ||||
|       this->reg_[wiper].terminal_w = true; | ||||
|       break; | ||||
|     default: | ||||
|       this->status_set_warning(); | ||||
|       ESP_LOGW(TAG, "Unknown terminal %c specified", terminal); | ||||
|       return; | ||||
|   } | ||||
|   this->update_ = true; | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::disable_terminal(uint8_t wiper, char terminal) { | ||||
|   if (wiper > 3) { | ||||
|     return; | ||||
|   } | ||||
|   ESP_LOGV(TAG, "Disabling terminal %c of wiper %d", terminal, wiper); | ||||
|   switch (terminal) { | ||||
|     case 'h': | ||||
|       this->reg_[wiper].terminal_hw = false; | ||||
|       break; | ||||
|     case 'a': | ||||
|       this->reg_[wiper].terminal_a = false; | ||||
|       break; | ||||
|     case 'b': | ||||
|       this->reg_[wiper].terminal_b = false; | ||||
|       break; | ||||
|     case 'w': | ||||
|       this->reg_[wiper].terminal_w = false; | ||||
|       break; | ||||
|     default: | ||||
|       this->status_set_warning(); | ||||
|       ESP_LOGW(TAG, "Unknown terminal %c specified", terminal); | ||||
|       return; | ||||
|   } | ||||
|   this->update_ = true; | ||||
| } | ||||
|  | ||||
| uint16_t Mcp4461Component::get_eeprom_value(MCP4461EEPRomLocation location) { | ||||
|   uint8_t reg = 0; | ||||
|   reg |= (uint8_t) (MCP4461_EEPROM_1 + ((uint8_t) location * 0x10)); | ||||
|   reg |= (uint8_t) Mcp4461Commands::READ; | ||||
|   uint16_t buf; | ||||
|   if (!this->read_byte_16(reg, &buf)) { | ||||
|     this->status_set_warning(); | ||||
|     ESP_LOGW(TAG, "Error fetching EEPRom location value"); | ||||
|     return 0; | ||||
|   } | ||||
|   return buf; | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::set_eeprom_value(MCP4461EEPRomLocation location, uint16_t value) { | ||||
|   uint8_t addr = 0; | ||||
|   if (value > 256) { | ||||
|     return; | ||||
|   } else if (value == 256) { | ||||
|     addr = 1; | ||||
|   } | ||||
|   uint8_t data; | ||||
|   addr |= (uint8_t) (MCP4461_EEPROM_1 + ((uint8_t) location * 0x10)); | ||||
|   data = (uint8_t) (value & 0x00ff); | ||||
|   while (this->is_writing_()) { | ||||
|     ESP_LOGV(TAG, "delaying during eeprom write"); | ||||
|   } | ||||
|   this->write_byte(addr, data); | ||||
| } | ||||
|  | ||||
| void Mcp4461Component::mcp4461_write_(uint8_t addr, uint16_t data) { | ||||
|   uint8_t reg = 0; | ||||
|   if (data > 0x100) { | ||||
|     return; | ||||
|   } | ||||
|   if (data > 0xFF) { | ||||
|     reg = 1; | ||||
|   } | ||||
|   uint8_t value_byte; | ||||
|   value_byte = (uint8_t) (data & 0x00ff); | ||||
|   ESP_LOGV(TAG, "Writing value %d", data); | ||||
|   reg |= addr; | ||||
|   reg |= (uint8_t) Mcp4461Commands::WRITE; | ||||
|   this->write_byte(reg, value_byte); | ||||
| } | ||||
| }  // namespace mcp4461 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										104
									
								
								esphome/components/mcp4461/mcp4461.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								esphome/components/mcp4461/mcp4461.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/i2c/i2c.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace mcp4461 { | ||||
|  | ||||
| struct WiperState { | ||||
|   bool terminal_a = true; | ||||
|   bool terminal_b = true; | ||||
|   bool terminal_w = true; | ||||
|   bool terminal_hw = true; | ||||
|   uint16_t state; | ||||
|   bool enabled = true; | ||||
| }; | ||||
|  | ||||
| enum class Mcp4461Defaults { WIPER_VALUE = 0x80 }; | ||||
| enum class Mcp4461Commands { WRITE = 0x0, INCREMENT = 0x4, DECREMENT = 0x8, READ = 0xC }; | ||||
|  | ||||
| enum class Mcp4461Addresses { | ||||
|   MCP4461_VW0 = 0x00, | ||||
|   MCP4461_VW1 = 0x10, | ||||
|   MCP4461_VW2 = 0x60, | ||||
|   MCP4461_VW3 = 0x70, | ||||
|   MCP4461_STATUS = 0x50, | ||||
|   MCP4461_TCON0 = 0x40, | ||||
|   MCP4461_TCON1 = 0xA0, | ||||
|   MCP4461_EEPROM_1 = 0xB0 | ||||
| }; | ||||
|  | ||||
| enum MCP4461WiperIdx { | ||||
|   MCP4461_WIPER_0 = 0, | ||||
|   MCP4461_WIPER_1 = 1, | ||||
|   MCP4461_WIPER_2 = 2, | ||||
|   MCP4461_WIPER_3 = 3, | ||||
|   MCP4461_WIPER_4 = 4, | ||||
|   MCP4461_WIPER_5 = 5, | ||||
|   MCP4461_WIPER_6 = 6, | ||||
|   MCP4461_WIPER_7 = 7 | ||||
| }; | ||||
|  | ||||
| enum MCP4461EEPRomLocation { | ||||
|   MCP4461_EEPROM_0 = 0, | ||||
|   MCP4461_EEPROM_1 = 1, | ||||
|   MCP4461_EEPROM_2 = 2, | ||||
|   MCP4461_EEPROM_3 = 3, | ||||
|   MCP4461_EEPROM_4 = 4 | ||||
| }; | ||||
|  | ||||
| enum class Mcp4461TerminalIdx { MCP4461_TERMINAL_0 = 0, MCP4461_TERMINAL_1 = 1 }; | ||||
|  | ||||
| class Mcp4461Wiper; | ||||
|  | ||||
| // Mcp4461Component | ||||
| class Mcp4461Component : public Component, public i2c::I2CDevice { | ||||
|  public: | ||||
|   Mcp4461Component(bool disable_wiper_0, bool disable_wiper_1, bool disable_wiper_2, bool disable_wiper_3) | ||||
|       : wiper_0_enabled_(false), wiper_1_enabled_(false), wiper_2_enabled_(false), wiper_3_enabled_(false) { | ||||
|     this->reg_[0].enabled = this->wiper_0_enabled_; | ||||
|     this->reg_[1].enabled = this->wiper_1_enabled_; | ||||
|     this->reg_[2].enabled = this->wiper_2_enabled_; | ||||
|     this->reg_[3].enabled = this->wiper_3_enabled_; | ||||
|   } | ||||
|  | ||||
|   void setup() override; | ||||
|   void dump_config() override; | ||||
|   float get_setup_priority() const override { return setup_priority::HARDWARE; } | ||||
|   void loop() override; | ||||
|   uint16_t get_status_register(); | ||||
|   uint16_t get_wiper_level(uint8_t wiper); | ||||
|   void set_wiper_level(uint8_t wiper, uint16_t value); | ||||
|   void update_wiper_level(uint8_t wiper); | ||||
|   void enable_wiper(uint8_t wiper); | ||||
|   void disable_wiper(uint8_t wiper); | ||||
|   void increase_wiper(uint8_t wiper); | ||||
|   void decrease_wiper(uint8_t wiper); | ||||
|   void enable_terminal(uint8_t wiper, char terminal); | ||||
|   void disable_terminal(uint8_t wiper, char terminal); | ||||
|   void update_terminal_register(Mcp4461TerminalIdx terminal_connector); | ||||
|   uint8_t get_terminal_register(Mcp4461TerminalIdx terminal_connector); | ||||
|   void set_terminal_register(Mcp4461TerminalIdx terminal_connector, uint8_t data); | ||||
|   uint16_t get_eeprom_value(MCP4461EEPRomLocation location); | ||||
|   void set_eeprom_value(MCP4461EEPRomLocation location, uint16_t value); | ||||
|  | ||||
|  protected: | ||||
|   friend Mcp4461Wiper; | ||||
|   bool is_writing_(); | ||||
|   uint8_t get_wiper_address_(uint8_t wiper); | ||||
|   void write_wiper_level_(uint8_t wiper, uint16_t value); | ||||
|   void mcp4461_write_(uint8_t addr, uint16_t data); | ||||
|   uint8_t calc_terminal_connector_byte_(Mcp4461TerminalIdx terminal_connector); | ||||
|  | ||||
|  private: | ||||
|   WiperState reg_[8]; | ||||
|   void begin_(); | ||||
|   bool update_ = false; | ||||
|   bool wiper_0_enabled_ = true; | ||||
|   bool wiper_1_enabled_ = true; | ||||
|   bool wiper_2_enabled_ = true; | ||||
|   bool wiper_3_enabled_ = true; | ||||
| }; | ||||
| }  // namespace mcp4461 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										52
									
								
								esphome/components/mcp4461/output/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								esphome/components/mcp4461/output/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import output | ||||
| from esphome.const import CONF_CHANNEL, CONF_ID | ||||
| from .. import Mcp4461Component, CONF_MCP4461_ID, mcp4461_ns | ||||
|  | ||||
| DEPENDENCIES = ["mcp4461"] | ||||
|  | ||||
| Mcp4461Wiper = mcp4461_ns.class_("Mcp4461Wiper", output.FloatOutput) | ||||
|  | ||||
| MCP4461WiperIdx = mcp4461_ns.enum("MCP4461WiperIdx") | ||||
| CHANNEL_OPTIONS = { | ||||
|     "A": MCP4461WiperIdx.MCP4461_WIPER_0, | ||||
|     "B": MCP4461WiperIdx.MCP4461_WIPER_1, | ||||
|     "C": MCP4461WiperIdx.MCP4461_WIPER_2, | ||||
|     "D": MCP4461WiperIdx.MCP4461_WIPER_3, | ||||
|     "E": MCP4461WiperIdx.MCP4461_WIPER_4, | ||||
|     "F": MCP4461WiperIdx.MCP4461_WIPER_5, | ||||
|     "G": MCP4461WiperIdx.MCP4461_WIPER_6, | ||||
|     "H": MCP4461WiperIdx.MCP4461_WIPER_7, | ||||
| } | ||||
|  | ||||
| CONF_ENABLE = "enable" | ||||
| CONF_TERMINAL_A = "terminal_a" | ||||
| CONF_TERMINAL_B = "terminal_b" | ||||
| CONF_TERMINAL_W = "terminal_w" | ||||
|  | ||||
| CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend( | ||||
|     { | ||||
|         cv.Required(CONF_ID): cv.declare_id(Mcp4461Wiper), | ||||
|         cv.GenerateID(CONF_MCP4461_ID): cv.use_id(Mcp4461Component), | ||||
|         cv.Required(CONF_CHANNEL): cv.enum(CHANNEL_OPTIONS, upper=True), | ||||
|         cv.Optional(CONF_ENABLE, default=True): cv.boolean, | ||||
|         cv.Optional(CONF_TERMINAL_A, default=True): cv.boolean, | ||||
|         cv.Optional(CONF_TERMINAL_B, default=True): cv.boolean, | ||||
|         cv.Optional(CONF_TERMINAL_W, default=True): cv.boolean, | ||||
|     } | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     parent = await cg.get_variable(config[CONF_MCP4461_ID]) | ||||
|     var = cg.new_Pvariable( | ||||
|         config[CONF_ID], | ||||
|         parent, | ||||
|         config[CONF_CHANNEL], | ||||
|         config[CONF_ENABLE], | ||||
|         config[CONF_TERMINAL_A], | ||||
|         config[CONF_TERMINAL_B], | ||||
|         config[CONF_TERMINAL_W], | ||||
|     ) | ||||
|     await output.register_output(var, config) | ||||
							
								
								
									
										87
									
								
								esphome/components/mcp4461/output/mcp4461_output.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								esphome/components/mcp4461/output/mcp4461_output.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| #include "mcp4461_output.h" | ||||
| #include <cmath> | ||||
|  | ||||
| #include "esphome/core/helpers.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace mcp4461 { | ||||
|  | ||||
| static const char *const TAG = "mcp4461"; | ||||
|  | ||||
| void Mcp4461Wiper::write_state(float state) { | ||||
|   ESP_LOGV(TAG, "Got value %02f from frontend", state); | ||||
|   const float max_taps = 256.0; | ||||
|   state = state * 1000.0; | ||||
|   if (state > max_taps) { | ||||
|     ESP_LOGW(TAG, "Cannot set taps > 0.256 for wiper %d, clamping to 0.256!", this->wiper_); | ||||
|     state = 256.0; | ||||
|   } | ||||
|   uint16_t taps; | ||||
|   taps = static_cast<uint16_t>(state); | ||||
|   ESP_LOGV(TAG, "Setting wiper %d to value %d", this->wiper_, taps); | ||||
|   this->state_ = state; | ||||
|   this->parent_->set_wiper_level(this->wiper_, taps); | ||||
| } | ||||
|  | ||||
| uint16_t Mcp4461Wiper::get_wiper_level() { return this->parent_->get_wiper_level(this->wiper_); } | ||||
|  | ||||
| void Mcp4461Wiper::save_level() { | ||||
|   if (this->wiper_ > 3) { | ||||
|     ESP_LOGW(TAG, "Cannot save level for nonvolatile wiper %d !", this->wiper_); | ||||
|     return; | ||||
|   } | ||||
|   uint8_t nonvolatile_wiper = this->wiper_ + 4; | ||||
|   this->parent_->set_wiper_level(nonvolatile_wiper, this->state_); | ||||
| } | ||||
|  | ||||
| void Mcp4461Wiper::enable_wiper() { | ||||
|   if (this->wiper_ > 3) { | ||||
|     ESP_LOGW(TAG, "Cannot enable nonvolatile wiper %d !", this->wiper_); | ||||
|     return; | ||||
|   } | ||||
|   this->parent_->enable_wiper(this->wiper_); | ||||
| } | ||||
|  | ||||
| void Mcp4461Wiper::disable_wiper() { | ||||
|   if (this->wiper_ > 3) { | ||||
|     ESP_LOGW(TAG, "Cannot disable nonvolatile wiper %d !", this->wiper_); | ||||
|     return; | ||||
|   } | ||||
|   this->parent_->disable_wiper(this->wiper_); | ||||
| } | ||||
|  | ||||
| void Mcp4461Wiper::increase_wiper() { | ||||
|   if (this->wiper_ > 3) { | ||||
|     ESP_LOGW(TAG, "Cannot increase nonvolatile wiper %d !", this->wiper_); | ||||
|     return; | ||||
|   } | ||||
|   this->parent_->increase_wiper(this->wiper_); | ||||
| } | ||||
|  | ||||
| void Mcp4461Wiper::decrease_wiper() { | ||||
|   if (this->wiper_ > 3) { | ||||
|     ESP_LOGW(TAG, "Cannot decrease nonvolatile wiper %d !", this->wiper_); | ||||
|     return; | ||||
|   } | ||||
|   this->parent_->decrease_wiper(this->wiper_); | ||||
| } | ||||
|  | ||||
| void Mcp4461Wiper::enable_terminal(char terminal) { | ||||
|   if (this->wiper_ > 3) { | ||||
|     ESP_LOGW(TAG, "Cannot get/set terminals nonvolatile wiper %d !", this->wiper_); | ||||
|     return; | ||||
|   } | ||||
|   this->parent_->enable_terminal(this->wiper_, terminal); | ||||
| } | ||||
|  | ||||
| void Mcp4461Wiper::disable_terminal(char terminal) { | ||||
|   if (this->wiper_ > 3) { | ||||
|     ESP_LOGW(TAG, "Cannot get/set terminals for nonvolatile wiper %d !", this->wiper_); | ||||
|     return; | ||||
|   } | ||||
|   this->parent_->disable_terminal(this->wiper_, terminal); | ||||
| } | ||||
|  | ||||
| }  // namespace mcp4461 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										54
									
								
								esphome/components/mcp4461/output/mcp4461_output.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								esphome/components/mcp4461/output/mcp4461_output.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "../mcp4461.h" | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/output/float_output.h" | ||||
| #include "esphome/components/i2c/i2c.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace mcp4461 { | ||||
|  | ||||
| class Mcp4461Wiper : public output::FloatOutput { | ||||
|  public: | ||||
|   Mcp4461Wiper(Mcp4461Component *parent, MCP4461WiperIdx wiper, bool enable, bool terminal_a, bool terminal_b, | ||||
|                bool terminal_w) | ||||
|       : parent_(parent), | ||||
|         wiper_(wiper), | ||||
|         enable_(enable), | ||||
|         terminal_a_(terminal_a), | ||||
|         terminal_b_(terminal_b), | ||||
|         terminal_w_(terminal_w) { | ||||
|     // update wiper connection state | ||||
|     if (!enable && wiper < 4) { | ||||
|       parent->reg_[wiper].enabled = false; | ||||
|       parent->disable_terminal(wiper, 'h'); | ||||
|     } | ||||
|     if (!terminal_a && wiper < 4) | ||||
|       parent->disable_terminal(wiper, 'a'); | ||||
|     if (!terminal_b && wiper < 4) | ||||
|       parent->disable_terminal(wiper, 'b'); | ||||
|     if (!terminal_w && wiper < 4) | ||||
|       parent->disable_terminal(wiper, 'w'); | ||||
|   } | ||||
|   uint16_t get_wiper_level(); | ||||
|   void save_level(); | ||||
|   void enable_wiper(); | ||||
|   void disable_wiper(); | ||||
|   void increase_wiper(); | ||||
|   void decrease_wiper(); | ||||
|   void enable_terminal(char terminal); | ||||
|   void disable_terminal(char terminal); | ||||
|  | ||||
|  protected: | ||||
|   void write_state(float state) override; | ||||
|   Mcp4461Component *parent_; | ||||
|   MCP4461WiperIdx wiper_; | ||||
|   bool enable_; | ||||
|   uint16_t state_; | ||||
|   bool terminal_a_; | ||||
|   bool terminal_b_; | ||||
|   bool terminal_w_; | ||||
| }; | ||||
|  | ||||
| }  // namespace mcp4461 | ||||
| }  // namespace esphome | ||||
		Reference in New Issue
	
	Block a user