mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 06:33:51 +00:00 
			
		
		
		
	MCP23SXX I/O Expander - SPI (#1068)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -40,6 +40,8 @@ esphome/components/json/* @OttoWinter | ||||
| esphome/components/ledc/* @OttoWinter | ||||
| esphome/components/light/* @esphome/core | ||||
| esphome/components/logger/* @esphome/core | ||||
| esphome/components/mcp23s08/* @SenexCrenshaw | ||||
| esphome/components/mcp23s17/* @SenexCrenshaw | ||||
| esphome/components/mcp9808/* @k7hpn | ||||
| esphome/components/network/* @esphome/core | ||||
| esphome/components/ota/* @esphome/core | ||||
|   | ||||
							
								
								
									
										58
									
								
								esphome/components/mcp23s08/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								esphome/components/mcp23s08/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome import pins | ||||
| from esphome.components import spi | ||||
| from esphome.const import CONF_ID, CONF_NUMBER, CONF_MODE, CONF_INVERTED | ||||
|  | ||||
| CODEOWNERS = ['@SenexCrenshaw'] | ||||
|  | ||||
| DEPENDENCIES = ['spi'] | ||||
| MULTI_CONF = True | ||||
|  | ||||
| CONF_DEVICEADDRESS = "deviceaddress" | ||||
|  | ||||
| mcp23S08_ns = cg.esphome_ns.namespace('mcp23s08') | ||||
| mcp23S08GPIOMode = mcp23S08_ns.enum('MCP23S08GPIOMode') | ||||
| mcp23S08_GPIO_MODES = { | ||||
|     'INPUT': mcp23S08GPIOMode.MCP23S08_INPUT, | ||||
|     'INPUT_PULLUP': mcp23S08GPIOMode.MCP23S08_INPUT_PULLUP, | ||||
|     'OUTPUT': mcp23S08GPIOMode.MCP23S08_OUTPUT, | ||||
| } | ||||
|  | ||||
| mcp23S08 = mcp23S08_ns.class_('MCP23S08', cg.Component, spi.SPIDevice) | ||||
| mcp23S08GPIOPin = mcp23S08_ns.class_('MCP23S08GPIOPin', cg.GPIOPin) | ||||
|  | ||||
| CONFIG_SCHEMA = cv.Schema({ | ||||
|     cv.Required(CONF_ID): cv.declare_id(mcp23S08), | ||||
|     cv.Optional(CONF_DEVICEADDRESS, default=0): cv.uint8_t, | ||||
| }).extend(cv.COMPONENT_SCHEMA).extend(spi.spi_device_schema()) | ||||
|  | ||||
|  | ||||
| def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     cg.add(var.set_device_address(config[CONF_DEVICEADDRESS])) | ||||
|     yield cg.register_component(var, config) | ||||
|     yield spi.register_spi_device(var, config) | ||||
|  | ||||
|  | ||||
| CONF_MCP23S08 = 'mcp23s08' | ||||
|  | ||||
| mcp23S08_OUTPUT_PIN_SCHEMA = cv.Schema({ | ||||
|     cv.GenerateID(CONF_MCP23S08): cv.use_id(mcp23S08), | ||||
|     cv.Required(CONF_NUMBER): cv.int_, | ||||
|     cv.Optional(CONF_MODE, default="OUTPUT"): cv.enum(mcp23S08_GPIO_MODES, upper=True), | ||||
|     cv.Optional(CONF_INVERTED, default=False): cv.boolean, | ||||
| }) | ||||
| mcp23S08_INPUT_PIN_SCHEMA = cv.Schema({ | ||||
|     cv.GenerateID(CONF_MCP23S08): cv.use_id(mcp23S08), | ||||
|     cv.Required(CONF_NUMBER): cv.int_range(0, 7), | ||||
|     cv.Optional(CONF_MODE, default="INPUT"): cv.enum(mcp23S08_GPIO_MODES, upper=True), | ||||
|     cv.Optional(CONF_INVERTED, default=False): cv.boolean, | ||||
| }) | ||||
|  | ||||
|  | ||||
| @pins.PIN_SCHEMA_REGISTRY.register(CONF_MCP23S08, | ||||
|                                    (mcp23S08_OUTPUT_PIN_SCHEMA, mcp23S08_INPUT_PIN_SCHEMA)) | ||||
| def mcp23S08_pin_to_code(config): | ||||
|     parent = yield cg.get_variable(config[CONF_MCP23S08]) | ||||
|     yield mcp23S08GPIOPin.new(parent, config[CONF_NUMBER], config[CONF_MODE], config[CONF_INVERTED]) | ||||
							
								
								
									
										121
									
								
								esphome/components/mcp23s08/mcp23s08.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								esphome/components/mcp23s08/mcp23s08.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| #include "mcp23s08.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace mcp23s08 { | ||||
|  | ||||
| static const char *TAG = "mcp23s08"; | ||||
|  | ||||
| void MCP23S08::set_device_address(uint8_t device_addr) { | ||||
|   if (device_addr != 0) { | ||||
|     this->device_opcode_ |= ((device_addr & 0x03) << 1); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void MCP23S08::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up MCP23S08..."); | ||||
|   this->spi_setup(); | ||||
|   this->enable(); | ||||
|  | ||||
|   this->transfer_byte(MCP23S08_IODIR); | ||||
|   this->transfer_byte(0xFF); | ||||
|   for (uint8_t i = 0; i < MCP23S08_OLAT; i++) { | ||||
|     this->transfer_byte(0x00); | ||||
|   } | ||||
|   this->disable(); | ||||
| } | ||||
|  | ||||
| void MCP23S08::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "MCP23S08:"); | ||||
|   LOG_PIN("  CS Pin: ", this->cs_); | ||||
| } | ||||
|  | ||||
| float MCP23S08::get_setup_priority() const { return setup_priority::HARDWARE; } | ||||
|  | ||||
| bool MCP23S08::digital_read(uint8_t pin) { | ||||
|   if (pin > 7) { | ||||
|     return false; | ||||
|   } | ||||
|   uint8_t bit = pin % 8; | ||||
|   uint8_t reg_addr = MCP23S08_GPIO; | ||||
|   uint8_t value = 0; | ||||
|   this->read_reg(reg_addr, &value); | ||||
|   return value & (1 << bit); | ||||
| } | ||||
|  | ||||
| void MCP23S08::digital_write(uint8_t pin, bool value) { | ||||
|   if (pin > 7) { | ||||
|     return; | ||||
|   } | ||||
|   uint8_t reg_addr = MCP23S08_OLAT; | ||||
|   this->update_reg(pin, value, reg_addr); | ||||
| } | ||||
|  | ||||
| void MCP23S08::pin_mode(uint8_t pin, uint8_t mode) { | ||||
|   uint8_t iodir = MCP23S08_IODIR; | ||||
|   uint8_t gppu = MCP23S08_GPPU; | ||||
|   switch (mode) { | ||||
|     case MCP23S08_INPUT: | ||||
|       this->update_reg(pin, true, iodir); | ||||
|       break; | ||||
|     case MCP23S08_INPUT_PULLUP: | ||||
|       this->update_reg(pin, true, iodir); | ||||
|       this->update_reg(pin, true, gppu); | ||||
|       break; | ||||
|     case MCP23S08_OUTPUT: | ||||
|       this->update_reg(pin, false, iodir); | ||||
|       break; | ||||
|     default: | ||||
|       break; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void MCP23S08::update_reg(uint8_t pin, bool pin_value, uint8_t reg_addr) { | ||||
|   uint8_t bit = pin % 8; | ||||
|   uint8_t reg_value = 0; | ||||
|   if (reg_addr == MCP23S08_OLAT) { | ||||
|     reg_value = this->olat_; | ||||
|   } else { | ||||
|     this->read_reg(reg_addr, ®_value); | ||||
|   } | ||||
|  | ||||
|   if (pin_value) | ||||
|     reg_value |= 1 << bit; | ||||
|   else | ||||
|     reg_value &= ~(1 << bit); | ||||
|  | ||||
|   this->write_reg(reg_addr, reg_value); | ||||
|  | ||||
|   if (reg_addr == MCP23S08_OLAT) { | ||||
|     this->olat_ = reg_value; | ||||
|   } | ||||
| } | ||||
|  | ||||
| bool MCP23S08::write_reg(uint8_t reg, uint8_t value) { | ||||
|   this->enable(); | ||||
|   this->transfer_byte(this->device_opcode_); | ||||
|   this->transfer_byte(reg); | ||||
|   this->transfer_byte(value); | ||||
|   this->disable(); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool MCP23S08::read_reg(uint8_t reg, uint8_t *value) { | ||||
|   uint8_t data; | ||||
|   this->enable(); | ||||
|   this->transfer_byte(this->device_opcode_ | 1); | ||||
|   this->transfer_byte(reg); | ||||
|   *value = this->transfer_byte(0); | ||||
|   this->disable(); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| MCP23S08GPIOPin::MCP23S08GPIOPin(MCP23S08 *parent, uint8_t pin, uint8_t mode, bool inverted) | ||||
|     : GPIOPin(pin, mode, inverted), parent_(parent) {} | ||||
| void MCP23S08GPIOPin::setup() { this->pin_mode(this->mode_); } | ||||
| void MCP23S08GPIOPin::pin_mode(uint8_t mode) { this->parent_->pin_mode(this->pin_, mode); } | ||||
| bool MCP23S08GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; } | ||||
| void MCP23S08GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); } | ||||
|  | ||||
| }  // namespace mcp23s08 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										74
									
								
								esphome/components/mcp23s08/mcp23s08.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								esphome/components/mcp23s08/mcp23s08.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/esphal.h" | ||||
| #include "esphome/components/spi/spi.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace mcp23s08 { | ||||
|  | ||||
| /// Modes for MCP23S08 pins | ||||
| enum MCP23S08GPIOMode : uint8_t { | ||||
|   MCP23S08_INPUT = INPUT,                // 0x00 | ||||
|   MCP23S08_INPUT_PULLUP = INPUT_PULLUP,  // 0x02 | ||||
|   MCP23S08_OUTPUT = OUTPUT               // 0x01 | ||||
| }; | ||||
|  | ||||
| enum MCP23S08GPIORegisters { | ||||
|   // A side | ||||
|   MCP23S08_IODIR = 0x00, | ||||
|   MCP23S08_IPOL = 0x01, | ||||
|   MCP23S08_GPINTEN = 0x02, | ||||
|   MCP23S08_DEFVAL = 0x03, | ||||
|   MCP23S08_INTCON = 0x04, | ||||
|   MCP23S08_IOCON = 0x05, | ||||
|   MCP23S08_GPPU = 0x06, | ||||
|   MCP23S08_INTF = 0x07, | ||||
|   MCP23S08_INTCAP = 0x08, | ||||
|   MCP23S08_GPIO = 0x09, | ||||
|   MCP23S08_OLAT = 0x0A, | ||||
| }; | ||||
|  | ||||
| class MCP23S08 : public Component, | ||||
|                  public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING, | ||||
|                                        spi::DATA_RATE_10MHZ> { | ||||
|  public: | ||||
|   MCP23S08() = default; | ||||
|  | ||||
|   void setup() override; | ||||
|   void dump_config() override; | ||||
|   bool digital_read(uint8_t pin); | ||||
|   void digital_write(uint8_t pin, bool value); | ||||
|   void pin_mode(uint8_t pin, uint8_t mode); | ||||
|  | ||||
|   void set_device_address(uint8_t device_addr); | ||||
|  | ||||
|   float get_setup_priority() const override; | ||||
|  | ||||
|   // read a given register | ||||
|   bool read_reg(uint8_t reg, uint8_t *value); | ||||
|   // write a value to a given register | ||||
|   bool write_reg(uint8_t reg, uint8_t value); | ||||
|   // update registers with given pin value. | ||||
|   void update_reg(uint8_t pin, bool pin_value, uint8_t reg_a); | ||||
|  | ||||
|  protected: | ||||
|   uint8_t device_opcode_ = 0x40; | ||||
|   uint8_t olat_{0x00}; | ||||
| }; | ||||
|  | ||||
| class MCP23S08GPIOPin : public GPIOPin { | ||||
|  public: | ||||
|   MCP23S08GPIOPin(MCP23S08 *parent, uint8_t pin, uint8_t mode, bool inverted = false); | ||||
|  | ||||
|   void setup() override; | ||||
|   void pin_mode(uint8_t mode) override; | ||||
|   bool digital_read() override; | ||||
|   void digital_write(bool value) override; | ||||
|  | ||||
|  protected: | ||||
|   MCP23S08 *parent_; | ||||
| }; | ||||
|  | ||||
| }  // namespace mcp23s08 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										58
									
								
								esphome/components/mcp23s17/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								esphome/components/mcp23s17/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome import pins | ||||
| from esphome.components import spi | ||||
| from esphome.const import CONF_ID, CONF_NUMBER, CONF_MODE, CONF_INVERTED | ||||
|  | ||||
| CODEOWNERS = ['@SenexCrenshaw'] | ||||
|  | ||||
| DEPENDENCIES = ['spi'] | ||||
| MULTI_CONF = True | ||||
|  | ||||
| CONF_DEVICEADDRESS = "deviceaddress" | ||||
|  | ||||
| mcp23S17_ns = cg.esphome_ns.namespace('mcp23s17') | ||||
| mcp23S17GPIOMode = mcp23S17_ns.enum('MCP23S17GPIOMode') | ||||
| mcp23S17_GPIO_MODES = { | ||||
|     'INPUT': mcp23S17GPIOMode.MCP23S17_INPUT, | ||||
|     'INPUT_PULLUP': mcp23S17GPIOMode.MCP23S17_INPUT_PULLUP, | ||||
|     'OUTPUT': mcp23S17GPIOMode.MCP23S17_OUTPUT, | ||||
| } | ||||
|  | ||||
| mcp23S17 = mcp23S17_ns.class_('MCP23S17', cg.Component, spi.SPIDevice) | ||||
| mcp23S17GPIOPin = mcp23S17_ns.class_('MCP23S17GPIOPin', cg.GPIOPin) | ||||
|  | ||||
| CONFIG_SCHEMA = cv.Schema({ | ||||
|     cv.Required(CONF_ID): cv.declare_id(mcp23S17), | ||||
|     cv.Optional(CONF_DEVICEADDRESS, default=0): cv.uint8_t, | ||||
| }).extend(cv.COMPONENT_SCHEMA).extend(spi.spi_device_schema()) | ||||
|  | ||||
|  | ||||
| def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     cg.add(var.set_device_address(config[CONF_DEVICEADDRESS])) | ||||
|     yield cg.register_component(var, config) | ||||
|     yield spi.register_spi_device(var, config) | ||||
|  | ||||
|  | ||||
| CONF_MCP23S17 = 'mcp23s17' | ||||
|  | ||||
| mcp23S17_OUTPUT_PIN_SCHEMA = cv.Schema({ | ||||
|     cv.GenerateID(CONF_MCP23S17): cv.use_id(mcp23S17), | ||||
|     cv.Required(CONF_NUMBER): cv.int_, | ||||
|     cv.Optional(CONF_MODE, default="OUTPUT"): cv.enum(mcp23S17_GPIO_MODES, upper=True), | ||||
|     cv.Optional(CONF_INVERTED, default=False): cv.boolean, | ||||
| }) | ||||
| mcp23S17_INPUT_PIN_SCHEMA = cv.Schema({ | ||||
|     cv.Required(CONF_MCP23S17): cv.use_id(mcp23S17), | ||||
|     cv.Required(CONF_NUMBER): cv.int_range(0, 15), | ||||
|     cv.Optional(CONF_MODE, default="INPUT"): cv.enum(mcp23S17_GPIO_MODES, upper=True), | ||||
|     cv.Optional(CONF_INVERTED, default=False): cv.boolean, | ||||
| }) | ||||
|  | ||||
|  | ||||
| @pins.PIN_SCHEMA_REGISTRY.register(CONF_MCP23S17, | ||||
|                                    (mcp23S17_OUTPUT_PIN_SCHEMA, mcp23S17_INPUT_PIN_SCHEMA)) | ||||
| def mcp23S17_pin_to_code(config): | ||||
|     parent = yield cg.get_variable(config[CONF_MCP23S17]) | ||||
|     yield mcp23S17GPIOPin.new(parent, config[CONF_NUMBER], config[CONF_MODE], config[CONF_INVERTED]) | ||||
							
								
								
									
										126
									
								
								esphome/components/mcp23s17/mcp23s17.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								esphome/components/mcp23s17/mcp23s17.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| #include "mcp23s17.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace mcp23s17 { | ||||
|  | ||||
| static const char *TAG = "mcp23s17"; | ||||
|  | ||||
| void MCP23S17::set_device_address(uint8_t device_addr) { | ||||
|   if (device_addr != 0) { | ||||
|     this->device_opcode_ |= ((device_addr & 0b111) << 1); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void MCP23S17::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up MCP23S17..."); | ||||
|   this->spi_setup(); | ||||
|  | ||||
|   this->enable(); | ||||
|   uint8_t cmd = 0b01000000; | ||||
|   this->transfer_byte(cmd); | ||||
|   this->transfer_byte(0x18); | ||||
|   this->transfer_byte(0x0A); | ||||
|   this->transfer_byte(this->device_opcode_); | ||||
|   this->transfer_byte(0); | ||||
|   this->transfer_byte(0xFF); | ||||
|   this->transfer_byte(0xFF); | ||||
|  | ||||
|   for (uint8_t i = 0; i < 20; i++) { | ||||
|     this->transfer_byte(0); | ||||
|   } | ||||
|   this->disable(); | ||||
| } | ||||
|  | ||||
| void MCP23S17::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "MCP23S17:"); | ||||
|   LOG_PIN("  CS Pin: ", this->cs_); | ||||
| } | ||||
|  | ||||
| float MCP23S17::get_setup_priority() const { return setup_priority::HARDWARE; } | ||||
|  | ||||
| bool MCP23S17::digital_read(uint8_t pin) { | ||||
|   uint8_t bit = pin % 8; | ||||
|   uint8_t reg_addr = pin < 8 ? MCP23S17_GPIOA : MCP23S17_GPIOB; | ||||
|   uint8_t value = 0; | ||||
|   this->read_reg(reg_addr, &value); | ||||
|   return value & (1 << bit); | ||||
| } | ||||
|  | ||||
| void MCP23S17::digital_write(uint8_t pin, bool value) { | ||||
|   uint8_t reg_addr = pin < 8 ? MCP23S17_OLATA : MCP23S17_OLATB; | ||||
|   this->update_reg(pin, value, reg_addr); | ||||
| } | ||||
|  | ||||
| void MCP23S17::pin_mode(uint8_t pin, uint8_t mode) { | ||||
|   uint8_t iodir = pin < 8 ? MCP23S17_IODIRA : MCP23S17_IODIRB; | ||||
|   uint8_t gppu = pin < 8 ? MCP23S17_GPPUA : MCP23S17_GPPUB; | ||||
|   switch (mode) { | ||||
|     case MCP23S17_INPUT: | ||||
|       this->update_reg(pin, true, iodir); | ||||
|       break; | ||||
|     case MCP23S17_INPUT_PULLUP: | ||||
|       this->update_reg(pin, true, iodir); | ||||
|       this->update_reg(pin, true, gppu); | ||||
|       break; | ||||
|     case MCP23S17_OUTPUT: | ||||
|       this->update_reg(pin, false, iodir); | ||||
|       break; | ||||
|     default: | ||||
|       break; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void MCP23S17::update_reg(uint8_t pin, bool pin_value, uint8_t reg_addr) { | ||||
|   uint8_t bit = pin % 8; | ||||
|   uint8_t reg_value = 0; | ||||
|   if (reg_addr == MCP23S17_OLATA) { | ||||
|     reg_value = this->olat_a_; | ||||
|   } else if (reg_addr == MCP23S17_OLATB) { | ||||
|     reg_value = this->olat_b_; | ||||
|   } else { | ||||
|     this->read_reg(reg_addr, ®_value); | ||||
|   } | ||||
|  | ||||
|   if (pin_value) | ||||
|     reg_value |= 1 << bit; | ||||
|   else | ||||
|     reg_value &= ~(1 << bit); | ||||
|  | ||||
|   this->write_reg(reg_addr, reg_value); | ||||
|  | ||||
|   if (reg_addr == MCP23S17_OLATA) { | ||||
|     this->olat_a_ = reg_value; | ||||
|   } else if (reg_addr == MCP23S17_OLATB) { | ||||
|     this->olat_b_ = reg_value; | ||||
|   } | ||||
| } | ||||
|  | ||||
| bool MCP23S17::read_reg(uint8_t reg, uint8_t *value) { | ||||
|   this->enable(); | ||||
|   this->transfer_byte(this->device_opcode_ | 1); | ||||
|   this->transfer_byte(reg); | ||||
|   *value = this->transfer_byte(0xFF); | ||||
|   this->disable(); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool MCP23S17::write_reg(uint8_t reg, uint8_t value) { | ||||
|   this->enable(); | ||||
|   this->transfer_byte(this->device_opcode_); | ||||
|   this->transfer_byte(reg); | ||||
|   this->transfer_byte(value); | ||||
|  | ||||
|   this->disable(); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| MCP23S17GPIOPin::MCP23S17GPIOPin(MCP23S17 *parent, uint8_t pin, uint8_t mode, bool inverted) | ||||
|     : GPIOPin(pin, mode, inverted), parent_(parent) {} | ||||
| void MCP23S17GPIOPin::setup() { this->pin_mode(this->mode_); } | ||||
| void MCP23S17GPIOPin::pin_mode(uint8_t mode) { this->parent_->pin_mode(this->pin_, mode); } | ||||
| bool MCP23S17GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; } | ||||
| void MCP23S17GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); } | ||||
|  | ||||
| }  // namespace mcp23s17 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										87
									
								
								esphome/components/mcp23s17/mcp23s17.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								esphome/components/mcp23s17/mcp23s17.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/esphal.h" | ||||
| #include "esphome/components/spi/spi.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace mcp23s17 { | ||||
|  | ||||
| /// Modes for MCP23S17 pins | ||||
| enum MCP23S17GPIOMode : uint8_t { | ||||
|   MCP23S17_INPUT = INPUT,                // 0x00 | ||||
|   MCP23S17_INPUT_PULLUP = INPUT_PULLUP,  // 0x02 | ||||
|   MCP23S17_OUTPUT = OUTPUT               // 0x01 | ||||
| }; | ||||
|  | ||||
| enum MCP23S17GPIORegisters { | ||||
|   // A side | ||||
|   MCP23S17_IODIRA = 0x00, | ||||
|   MCP23S17_IPOLA = 0x02, | ||||
|   MCP23S17_GPINTENA = 0x04, | ||||
|   MCP23S17_DEFVALA = 0x06, | ||||
|   MCP23S17_INTCONA = 0x08, | ||||
|   MCP23S17_IOCONA = 0x0A, | ||||
|   MCP23S17_GPPUA = 0x0C, | ||||
|   MCP23S17_INTFA = 0x0E, | ||||
|   MCP23S17_INTCAPA = 0x10, | ||||
|   MCP23S17_GPIOA = 0x12, | ||||
|   MCP23S17_OLATA = 0x14, | ||||
|   // B side | ||||
|   MCP23S17_IODIRB = 0x01, | ||||
|   MCP23S17_IPOLB = 0x03, | ||||
|   MCP23S17_GPINTENB = 0x05, | ||||
|   MCP23S17_DEFVALB = 0x07, | ||||
|   MCP23S17_INTCONB = 0x09, | ||||
|   MCP23S17_IOCONB = 0x0B, | ||||
|   MCP23S17_GPPUB = 0x0D, | ||||
|   MCP23S17_INTFB = 0x0F, | ||||
|   MCP23S17_INTCAPB = 0x11, | ||||
|   MCP23S17_GPIOB = 0x13, | ||||
|   MCP23S17_OLATB = 0x15, | ||||
| }; | ||||
|  | ||||
| class MCP23S17 : public Component, | ||||
|                  public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING, | ||||
|                                        spi::DATA_RATE_8MHZ> { | ||||
|  public: | ||||
|   MCP23S17() = default; | ||||
|  | ||||
|   void setup() override; | ||||
|   void dump_config() override; | ||||
|   void set_device_address(uint8_t device_addr); | ||||
|  | ||||
|   bool digital_read(uint8_t pin); | ||||
|   void digital_write(uint8_t pin, bool value); | ||||
|   void pin_mode(uint8_t pin, uint8_t mode); | ||||
|  | ||||
|   float get_setup_priority() const override; | ||||
|  | ||||
|   // read a given register | ||||
|   bool read_reg(uint8_t reg, uint8_t *value); | ||||
|   // write a value to a given register | ||||
|   bool write_reg(uint8_t reg, uint8_t value); | ||||
|   // update registers with given pin value. | ||||
|   void update_reg(uint8_t pin, bool pin_value, uint8_t reg_a); | ||||
|  | ||||
|  protected: | ||||
|   uint8_t device_opcode_ = 0x40; | ||||
|   uint8_t olat_a_{0x00}; | ||||
|   uint8_t olat_b_{0x00}; | ||||
| }; | ||||
|  | ||||
| class MCP23S17GPIOPin : public GPIOPin { | ||||
|  public: | ||||
|   MCP23S17GPIOPin(MCP23S17 *parent, uint8_t pin, uint8_t mode, bool inverted = false); | ||||
|  | ||||
|   void setup() override; | ||||
|   void pin_mode(uint8_t mode) override; | ||||
|   bool digital_read() override; | ||||
|   void digital_write(bool value) override; | ||||
|  | ||||
|  protected: | ||||
|   MCP23S17 *parent_; | ||||
| }; | ||||
|  | ||||
| }  // namespace mcp23s17 | ||||
| }  // namespace esphome | ||||
| @@ -55,6 +55,7 @@ enum SPIDataRate : uint32_t { | ||||
|   DATA_RATE_2MHZ = 2000000, | ||||
|   DATA_RATE_4MHZ = 4000000, | ||||
|   DATA_RATE_8MHZ = 8000000, | ||||
|   DATA_RATE_10MHZ = 10000000, | ||||
|   DATA_RATE_20MHZ = 20000000, | ||||
|   DATA_RATE_40MHZ = 40000000, | ||||
| }; | ||||
|   | ||||
| @@ -197,6 +197,16 @@ wled: | ||||
|  | ||||
| adalight: | ||||
|  | ||||
| mcp23s08: | ||||
|   - id: 'mcp23s08_hub' | ||||
|     cs_pin: GPIO12 | ||||
|     deviceaddress: 0 | ||||
|      | ||||
| mcp23s17: | ||||
|   - id: 'mcp23s17_hub' | ||||
|     cs_pin: GPIO12 | ||||
|     deviceaddress: 1 | ||||
|  | ||||
| sensor: | ||||
|   - platform: adc | ||||
|     pin: A0 | ||||
| @@ -802,6 +812,24 @@ esp32_touch: | ||||
|   voltage_attenuation: 1.5V | ||||
|  | ||||
| binary_sensor: | ||||
|   - platform: gpio | ||||
|     name: "MCP23S08 Pin #1" | ||||
|     pin: | ||||
|       mcp23s08: mcp23s08_hub | ||||
|       # Use pin number 1 | ||||
|       number: 1 | ||||
|       # One of INPUT or INPUT_PULLUP | ||||
|       mode: INPUT_PULLUP | ||||
|       inverted: False | ||||
|   - platform: gpio | ||||
|     name: "MCP23S17 Pin #1" | ||||
|     pin: | ||||
|       mcp23s17: mcp23s17_hub | ||||
|       # Use pin number 1 | ||||
|       number: 1 | ||||
|       # One of INPUT or INPUT_PULLUP | ||||
|       mode: INPUT_PULLUP | ||||
|       inverted: False | ||||
|   - platform: gpio | ||||
|     pin: GPIO9 | ||||
|     name: 'Living Room Window' | ||||
| @@ -1362,6 +1390,22 @@ climate: | ||||
|     name: Hitachi Climate | ||||
|  | ||||
| switch: | ||||
|   - platform: gpio | ||||
|     name: "MCP23S08 Pin #0" | ||||
|     pin: | ||||
|       mcp23s08: mcp23s08_hub | ||||
|       # Use pin number 0 | ||||
|       number: 0 | ||||
|       mode: OUTPUT | ||||
|       inverted: False | ||||
|   - platform: gpio | ||||
|     name: "MCP23S17 Pin #0" | ||||
|     pin: | ||||
|       mcp23s17: mcp23s17_hub | ||||
|       # Use pin number 0 | ||||
|       number: 1 | ||||
|       mode: OUTPUT | ||||
|       inverted: False | ||||
|   - platform: gpio | ||||
|     pin: GPIO25 | ||||
|     name: 'Living Room Dehumidifier' | ||||
|   | ||||
		Reference in New Issue
	
	Block a user