mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 05:24:53 +01:00
MCP23XXX Refactor (#1560)
* Refactor MCP23XXX classes to consolidate shared code * Update test mcp23xxx pin schemas
This commit is contained in:
parent
69879920eb
commit
570ec36fe3
25 changed files with 603 additions and 740 deletions
|
@ -46,8 +46,13 @@ esphome/components/ledc/* @OttoWinter
|
|||
esphome/components/light/* @esphome/core
|
||||
esphome/components/logger/* @esphome/core
|
||||
esphome/components/max7219digit/* @rspaargaren
|
||||
esphome/components/mcp23s08/* @SenexCrenshaw
|
||||
esphome/components/mcp23s17/* @SenexCrenshaw
|
||||
esphome/components/mcp23008/* @jesserockz
|
||||
esphome/components/mcp23017/* @jesserockz
|
||||
esphome/components/mcp23s08/* @SenexCrenshaw @jesserockz
|
||||
esphome/components/mcp23s17/* @SenexCrenshaw @jesserockz
|
||||
esphome/components/mcp23x08_base/* @jesserockz
|
||||
esphome/components/mcp23x17_base/* @jesserockz
|
||||
esphome/components/mcp23xxx_base/* @jesserockz
|
||||
esphome/components/mcp2515/* @danielschramm @mvturnho
|
||||
esphome/components/mcp9808/* @k7hpn
|
||||
esphome/components/network/* @esphome/core
|
||||
|
|
|
@ -1,76 +1,28 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.components import i2c
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_NUMBER,
|
||||
CONF_MODE,
|
||||
CONF_INVERTED,
|
||||
CONF_OPEN_DRAIN_INTERRUPT,
|
||||
)
|
||||
from esphome.components import i2c, mcp23x08_base, mcp23xxx_base
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
AUTO_LOAD = ["mcp23x08_base"]
|
||||
CODEOWNERS = ["@jesserockz"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
MULTI_CONF = True
|
||||
|
||||
mcp23008_ns = cg.esphome_ns.namespace("mcp23008")
|
||||
MCP23008GPIOMode = mcp23008_ns.enum("MCP23008GPIOMode")
|
||||
MCP23008_GPIO_MODES = {
|
||||
"INPUT": MCP23008GPIOMode.MCP23008_INPUT,
|
||||
"INPUT_PULLUP": MCP23008GPIOMode.MCP23008_INPUT_PULLUP,
|
||||
"OUTPUT": MCP23008GPIOMode.MCP23008_OUTPUT,
|
||||
}
|
||||
|
||||
MCP23008 = mcp23008_ns.class_("MCP23008", cg.Component, i2c.I2CDevice)
|
||||
MCP23008GPIOPin = mcp23008_ns.class_("MCP23008GPIOPin", cg.GPIOPin)
|
||||
MCP23008 = mcp23008_ns.class_("MCP23008", mcp23x08_base.MCP23X08Base, i2c.I2CDevice)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.declare_id(MCP23008),
|
||||
cv.Optional(CONF_OPEN_DRAIN_INTERRUPT, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(mcp23xxx_base.MCP23XXX_CONFIG_SCHEMA)
|
||||
.extend(i2c.i2c_device_schema(0x20))
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
var = yield mcp23xxx_base.register_mcp23xxx(config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
cg.add(var.set_open_drain_ints(config[CONF_OPEN_DRAIN_INTERRUPT]))
|
||||
|
||||
|
||||
CONF_MCP23008 = "mcp23008"
|
||||
MCP23008_OUTPUT_PIN_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_MCP23008): cv.use_id(MCP23008),
|
||||
cv.Required(CONF_NUMBER): cv.int_,
|
||||
cv.Optional(CONF_MODE, default="OUTPUT"): cv.enum(
|
||||
MCP23008_GPIO_MODES, upper=True
|
||||
),
|
||||
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
MCP23008_INPUT_PIN_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_MCP23008): cv.use_id(MCP23008),
|
||||
cv.Required(CONF_NUMBER): cv.int_,
|
||||
cv.Optional(CONF_MODE, default="INPUT"): cv.enum(
|
||||
MCP23008_GPIO_MODES, upper=True
|
||||
),
|
||||
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@pins.PIN_SCHEMA_REGISTRY.register(
|
||||
CONF_MCP23008, (MCP23008_OUTPUT_PIN_SCHEMA, MCP23008_INPUT_PIN_SCHEMA)
|
||||
)
|
||||
def mcp23008_pin_to_code(config):
|
||||
parent = yield cg.get_variable(config[CONF_MCP23008])
|
||||
yield MCP23008GPIOPin.new(
|
||||
parent, config[CONF_NUMBER], config[CONF_MODE], config[CONF_INVERTED]
|
||||
)
|
||||
|
|
|
@ -9,85 +9,32 @@ static const char *TAG = "mcp23008";
|
|||
void MCP23008::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up MCP23008...");
|
||||
uint8_t iocon;
|
||||
if (!this->read_reg_(MCP23008_IOCON, &iocon)) {
|
||||
if (!this->read_reg(mcp23x08_base::MCP23X08_IOCON, &iocon)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->open_drain_ints_) {
|
||||
// enable open-drain interrupt pins, 3.3V-safe
|
||||
this->write_reg_(MCP23008_IOCON, 0x04);
|
||||
this->write_reg(mcp23x08_base::MCP23X08_IOCON, 0x04);
|
||||
}
|
||||
}
|
||||
bool MCP23008::digital_read(uint8_t pin) {
|
||||
uint8_t bit = pin % 8;
|
||||
uint8_t reg_addr = MCP23008_GPIO;
|
||||
uint8_t value = 0;
|
||||
this->read_reg_(reg_addr, &value);
|
||||
return value & (1 << bit);
|
||||
}
|
||||
void MCP23008::digital_write(uint8_t pin, bool value) {
|
||||
uint8_t reg_addr = MCP23008_OLAT;
|
||||
this->update_reg_(pin, value, reg_addr);
|
||||
}
|
||||
void MCP23008::pin_mode(uint8_t pin, uint8_t mode) {
|
||||
uint8_t iodir = MCP23008_IODIR;
|
||||
uint8_t gppu = MCP23008_GPPU;
|
||||
switch (mode) {
|
||||
case MCP23008_INPUT:
|
||||
this->update_reg_(pin, true, iodir);
|
||||
break;
|
||||
case MCP23008_INPUT_PULLUP:
|
||||
this->update_reg_(pin, true, iodir);
|
||||
this->update_reg_(pin, true, gppu);
|
||||
break;
|
||||
case MCP23008_OUTPUT:
|
||||
this->update_reg_(pin, false, iodir);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
float MCP23008::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
bool MCP23008::read_reg_(uint8_t reg, uint8_t *value) {
|
||||
|
||||
void MCP23008::dump_config() { ESP_LOGCONFIG(TAG, "MCP23008:"); }
|
||||
|
||||
bool MCP23008::read_reg(uint8_t reg, uint8_t *value) {
|
||||
if (this->is_failed())
|
||||
return false;
|
||||
|
||||
return this->read_byte(reg, value);
|
||||
}
|
||||
bool MCP23008::write_reg_(uint8_t reg, uint8_t value) {
|
||||
|
||||
bool MCP23008::write_reg(uint8_t reg, uint8_t value) {
|
||||
if (this->is_failed())
|
||||
return false;
|
||||
|
||||
return this->write_byte(reg, value);
|
||||
}
|
||||
void MCP23008::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 == MCP23008_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 == MCP23008_OLAT) {
|
||||
this->olat_ = reg_value;
|
||||
}
|
||||
}
|
||||
|
||||
MCP23008GPIOPin::MCP23008GPIOPin(MCP23008 *parent, uint8_t pin, uint8_t mode, bool inverted)
|
||||
: GPIOPin(pin, mode, inverted), parent_(parent) {}
|
||||
void MCP23008GPIOPin::setup() { this->pin_mode(this->mode_); }
|
||||
void MCP23008GPIOPin::pin_mode(uint8_t mode) { this->parent_->pin_mode(this->pin_, mode); }
|
||||
bool MCP23008GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
|
||||
void MCP23008GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
|
||||
|
||||
} // namespace mcp23008
|
||||
} // namespace esphome
|
||||
|
|
|
@ -1,71 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/mcp23x08_base/mcp23x08_base.h"
|
||||
#include "esphome/core/esphal.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace mcp23008 {
|
||||
|
||||
/// Modes for MCP23008 pins
|
||||
enum MCP23008GPIOMode : uint8_t {
|
||||
MCP23008_INPUT = INPUT, // 0x00
|
||||
MCP23008_INPUT_PULLUP = INPUT_PULLUP, // 0x02
|
||||
MCP23008_OUTPUT = OUTPUT // 0x01
|
||||
};
|
||||
|
||||
enum MCP23008GPIORegisters {
|
||||
// A side
|
||||
MCP23008_IODIR = 0x00,
|
||||
MCP23008_IPOL = 0x01,
|
||||
MCP23008_GPINTEN = 0x02,
|
||||
MCP23008_DEFVAL = 0x03,
|
||||
MCP23008_INTCON = 0x04,
|
||||
MCP23008_IOCON = 0x05,
|
||||
MCP23008_GPPU = 0x06,
|
||||
MCP23008_INTF = 0x07,
|
||||
MCP23008_INTCAP = 0x08,
|
||||
MCP23008_GPIO = 0x09,
|
||||
MCP23008_OLAT = 0x0A,
|
||||
};
|
||||
|
||||
class MCP23008 : public Component, public i2c::I2CDevice {
|
||||
class MCP23008 : public mcp23x08_base::MCP23X08Base, public i2c::I2CDevice {
|
||||
public:
|
||||
MCP23008() = default;
|
||||
|
||||
void setup() 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_open_drain_ints(const bool value) { open_drain_ints_ = value; }
|
||||
|
||||
float get_setup_priority() const override;
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
// 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);
|
||||
|
||||
uint8_t olat_{0x00};
|
||||
bool open_drain_ints_;
|
||||
};
|
||||
|
||||
class MCP23008GPIOPin : public GPIOPin {
|
||||
public:
|
||||
MCP23008GPIOPin(MCP23008 *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:
|
||||
MCP23008 *parent_;
|
||||
bool read_reg(uint8_t reg, uint8_t *value) override;
|
||||
bool write_reg(uint8_t reg, uint8_t value) override;
|
||||
};
|
||||
|
||||
} // namespace mcp23008
|
||||
|
|
|
@ -1,76 +1,28 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.components import i2c
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_NUMBER,
|
||||
CONF_MODE,
|
||||
CONF_INVERTED,
|
||||
CONF_OPEN_DRAIN_INTERRUPT,
|
||||
)
|
||||
from esphome.components import i2c, mcp23x17_base, mcp23xxx_base
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
AUTO_LOAD = ["mcp23x17_base"]
|
||||
CODEOWNERS = ["@jesserockz"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
MULTI_CONF = True
|
||||
|
||||
mcp23017_ns = cg.esphome_ns.namespace("mcp23017")
|
||||
MCP23017GPIOMode = mcp23017_ns.enum("MCP23017GPIOMode")
|
||||
MCP23017_GPIO_MODES = {
|
||||
"INPUT": MCP23017GPIOMode.MCP23017_INPUT,
|
||||
"INPUT_PULLUP": MCP23017GPIOMode.MCP23017_INPUT_PULLUP,
|
||||
"OUTPUT": MCP23017GPIOMode.MCP23017_OUTPUT,
|
||||
}
|
||||
|
||||
MCP23017 = mcp23017_ns.class_("MCP23017", cg.Component, i2c.I2CDevice)
|
||||
MCP23017GPIOPin = mcp23017_ns.class_("MCP23017GPIOPin", cg.GPIOPin)
|
||||
MCP23017 = mcp23017_ns.class_("MCP23017", mcp23x17_base.MCP23X17Base, i2c.I2CDevice)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.declare_id(MCP23017),
|
||||
cv.Optional(CONF_OPEN_DRAIN_INTERRUPT, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(mcp23xxx_base.MCP23XXX_CONFIG_SCHEMA)
|
||||
.extend(i2c.i2c_device_schema(0x20))
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
var = yield mcp23xxx_base.register_mcp23xxx(config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
cg.add(var.set_open_drain_ints(config[CONF_OPEN_DRAIN_INTERRUPT]))
|
||||
|
||||
|
||||
CONF_MCP23017 = "mcp23017"
|
||||
MCP23017_OUTPUT_PIN_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_MCP23017): cv.use_id(MCP23017),
|
||||
cv.Required(CONF_NUMBER): cv.int_,
|
||||
cv.Optional(CONF_MODE, default="OUTPUT"): cv.enum(
|
||||
MCP23017_GPIO_MODES, upper=True
|
||||
),
|
||||
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
MCP23017_INPUT_PIN_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_MCP23017): cv.use_id(MCP23017),
|
||||
cv.Required(CONF_NUMBER): cv.int_,
|
||||
cv.Optional(CONF_MODE, default="INPUT"): cv.enum(
|
||||
MCP23017_GPIO_MODES, upper=True
|
||||
),
|
||||
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@pins.PIN_SCHEMA_REGISTRY.register(
|
||||
CONF_MCP23017, (MCP23017_OUTPUT_PIN_SCHEMA, MCP23017_INPUT_PIN_SCHEMA)
|
||||
)
|
||||
def mcp23017_pin_to_code(config):
|
||||
parent = yield cg.get_variable(config[CONF_MCP23017])
|
||||
yield MCP23017GPIOPin.new(
|
||||
parent, config[CONF_NUMBER], config[CONF_MODE], config[CONF_INVERTED]
|
||||
)
|
||||
|
|
|
@ -9,90 +9,32 @@ static const char *TAG = "mcp23017";
|
|||
void MCP23017::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up MCP23017...");
|
||||
uint8_t iocon;
|
||||
if (!this->read_reg_(MCP23017_IOCONA, &iocon)) {
|
||||
if (!this->read_reg(mcp23x17_base::MCP23X17_IOCONA, &iocon)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->open_drain_ints_) {
|
||||
// enable open-drain interrupt pins, 3.3V-safe
|
||||
this->write_reg_(MCP23017_IOCONA, 0x04);
|
||||
this->write_reg_(MCP23017_IOCONB, 0x04);
|
||||
this->write_reg(mcp23x17_base::MCP23X17_IOCONA, 0x04);
|
||||
this->write_reg(mcp23x17_base::MCP23X17_IOCONB, 0x04);
|
||||
}
|
||||
}
|
||||
bool MCP23017::digital_read(uint8_t pin) {
|
||||
uint8_t bit = pin % 8;
|
||||
uint8_t reg_addr = pin < 8 ? MCP23017_GPIOA : MCP23017_GPIOB;
|
||||
uint8_t value = 0;
|
||||
this->read_reg_(reg_addr, &value);
|
||||
return value & (1 << bit);
|
||||
}
|
||||
void MCP23017::digital_write(uint8_t pin, bool value) {
|
||||
uint8_t reg_addr = pin < 8 ? MCP23017_OLATA : MCP23017_OLATB;
|
||||
this->update_reg_(pin, value, reg_addr);
|
||||
}
|
||||
void MCP23017::pin_mode(uint8_t pin, uint8_t mode) {
|
||||
uint8_t iodir = pin < 8 ? MCP23017_IODIRA : MCP23017_IODIRB;
|
||||
uint8_t gppu = pin < 8 ? MCP23017_GPPUA : MCP23017_GPPUB;
|
||||
switch (mode) {
|
||||
case MCP23017_INPUT:
|
||||
this->update_reg_(pin, true, iodir);
|
||||
break;
|
||||
case MCP23017_INPUT_PULLUP:
|
||||
this->update_reg_(pin, true, iodir);
|
||||
this->update_reg_(pin, true, gppu);
|
||||
break;
|
||||
case MCP23017_OUTPUT:
|
||||
this->update_reg_(pin, false, iodir);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
float MCP23017::get_setup_priority() const { return setup_priority::IO; }
|
||||
bool MCP23017::read_reg_(uint8_t reg, uint8_t *value) {
|
||||
|
||||
void MCP23017::dump_config() { ESP_LOGCONFIG(TAG, "MCP23017:"); }
|
||||
|
||||
bool MCP23017::read_reg(uint8_t reg, uint8_t *value) {
|
||||
if (this->is_failed())
|
||||
return false;
|
||||
|
||||
return this->read_byte(reg, value);
|
||||
}
|
||||
bool MCP23017::write_reg_(uint8_t reg, uint8_t value) {
|
||||
bool MCP23017::write_reg(uint8_t reg, uint8_t value) {
|
||||
if (this->is_failed())
|
||||
return false;
|
||||
|
||||
return this->write_byte(reg, value);
|
||||
}
|
||||
void MCP23017::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 == MCP23017_OLATA) {
|
||||
reg_value = this->olat_a_;
|
||||
} else if (reg_addr == MCP23017_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 == MCP23017_OLATA) {
|
||||
this->olat_a_ = reg_value;
|
||||
} else if (reg_addr == MCP23017_OLATB) {
|
||||
this->olat_b_ = reg_value;
|
||||
}
|
||||
}
|
||||
|
||||
MCP23017GPIOPin::MCP23017GPIOPin(MCP23017 *parent, uint8_t pin, uint8_t mode, bool inverted)
|
||||
: GPIOPin(pin, mode, inverted), parent_(parent) {}
|
||||
void MCP23017GPIOPin::setup() { this->pin_mode(this->mode_); }
|
||||
void MCP23017GPIOPin::pin_mode(uint8_t mode) { this->parent_->pin_mode(this->pin_, mode); }
|
||||
bool MCP23017GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
|
||||
void MCP23017GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
|
||||
|
||||
} // namespace mcp23017
|
||||
} // namespace esphome
|
||||
|
|
|
@ -1,84 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/mcp23x17_base/mcp23x17_base.h"
|
||||
#include "esphome/core/esphal.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace mcp23017 {
|
||||
|
||||
/// Modes for MCP23017 pins
|
||||
enum MCP23017GPIOMode : uint8_t {
|
||||
MCP23017_INPUT = INPUT, // 0x00
|
||||
MCP23017_INPUT_PULLUP = INPUT_PULLUP, // 0x02
|
||||
MCP23017_OUTPUT = OUTPUT // 0x01
|
||||
};
|
||||
|
||||
enum MCP23017GPIORegisters {
|
||||
// A side
|
||||
MCP23017_IODIRA = 0x00,
|
||||
MCP23017_IPOLA = 0x02,
|
||||
MCP23017_GPINTENA = 0x04,
|
||||
MCP23017_DEFVALA = 0x06,
|
||||
MCP23017_INTCONA = 0x08,
|
||||
MCP23017_IOCONA = 0x0A,
|
||||
MCP23017_GPPUA = 0x0C,
|
||||
MCP23017_INTFA = 0x0E,
|
||||
MCP23017_INTCAPA = 0x10,
|
||||
MCP23017_GPIOA = 0x12,
|
||||
MCP23017_OLATA = 0x14,
|
||||
// B side
|
||||
MCP23017_IODIRB = 0x01,
|
||||
MCP23017_IPOLB = 0x03,
|
||||
MCP23017_GPINTENB = 0x05,
|
||||
MCP23017_DEFVALB = 0x07,
|
||||
MCP23017_INTCONB = 0x09,
|
||||
MCP23017_IOCONB = 0x0B,
|
||||
MCP23017_GPPUB = 0x0D,
|
||||
MCP23017_INTFB = 0x0F,
|
||||
MCP23017_INTCAPB = 0x11,
|
||||
MCP23017_GPIOB = 0x13,
|
||||
MCP23017_OLATB = 0x15,
|
||||
};
|
||||
|
||||
class MCP23017 : public Component, public i2c::I2CDevice {
|
||||
class MCP23017 : public mcp23x17_base::MCP23X17Base, public i2c::I2CDevice {
|
||||
public:
|
||||
MCP23017() = default;
|
||||
|
||||
void setup() 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_open_drain_ints(const bool value) { open_drain_ints_ = value; }
|
||||
|
||||
float get_setup_priority() const override;
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
// 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);
|
||||
|
||||
uint8_t olat_a_{0x00};
|
||||
uint8_t olat_b_{0x00};
|
||||
bool open_drain_ints_;
|
||||
};
|
||||
|
||||
class MCP23017GPIOPin : public GPIOPin {
|
||||
public:
|
||||
MCP23017GPIOPin(MCP23017 *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:
|
||||
MCP23017 *parent_;
|
||||
bool read_reg(uint8_t reg, uint8_t *value) override;
|
||||
bool write_reg(uint8_t reg, uint8_t value) override;
|
||||
};
|
||||
|
||||
} // namespace mcp23017
|
||||
|
|
|
@ -1,26 +1,18 @@
|
|||
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"]
|
||||
from esphome.components import spi, mcp23x08_base, mcp23xxx_base
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
AUTO_LOAD = ["mcp23x08_base"]
|
||||
CODEOWNERS = ["@SenexCrenshaw", "@jesserockz"]
|
||||
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)
|
||||
mcp23S08 = mcp23S08_ns.class_("MCP23S08", mcp23x08_base.MCP23X08Base, spi.SPIDevice)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
|
@ -29,47 +21,12 @@ CONFIG_SCHEMA = (
|
|||
cv.Optional(CONF_DEVICEADDRESS, default=0): cv.uint8_t,
|
||||
}
|
||||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(mcp23xxx_base.MCP23XXX_CONFIG_SCHEMA)
|
||||
.extend(spi.spi_device_schema())
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
var = yield mcp23xxx_base.register_mcp23xxx(config)
|
||||
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]
|
||||
)
|
||||
|
|
|
@ -15,14 +15,18 @@ void MCP23S08::set_device_address(uint8_t device_addr) {
|
|||
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->enable();
|
||||
uint8_t cmd = 0b01000000;
|
||||
this->transfer_byte(cmd);
|
||||
this->transfer_byte(mcp23x08_base::MCP23X08_IOCON);
|
||||
this->transfer_byte(0b00011000); // Enable HAEN pins for addressing
|
||||
this->disable();
|
||||
|
||||
if (this->open_drain_ints_) {
|
||||
// enable open-drain interrupt pins, 3.3V-safe
|
||||
this->write_reg(mcp23x08_base::MCP23X08_IOCON, 0x04);
|
||||
}
|
||||
}
|
||||
|
||||
void MCP23S08::dump_config() {
|
||||
|
@ -30,76 +34,6 @@ void MCP23S08::dump_config() {
|
|||
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();
|
||||
|
@ -110,12 +44,14 @@ bool MCP23S08::read_reg(uint8_t reg, uint8_t *value) {
|
|||
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_); }
|
||||
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;
|
||||
}
|
||||
|
||||
} // namespace mcp23s08
|
||||
} // namespace esphome
|
||||
|
|
|
@ -1,35 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/mcp23x08_base/mcp23x08_base.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,
|
||||
class MCP23S08 : public mcp23x08_base::MCP23X08Base,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
|
||||
spi::DATA_RATE_10MHZ> {
|
||||
public:
|
||||
|
@ -37,37 +16,14 @@ class MCP23S08 : public Component,
|
|||
|
||||
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:
|
||||
bool read_reg(uint8_t reg, uint8_t *value) override;
|
||||
bool write_reg(uint8_t reg, uint8_t value) override;
|
||||
|
||||
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
|
||||
|
|
|
@ -1,26 +1,18 @@
|
|||
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"]
|
||||
from esphome.components import spi, mcp23x17_base, mcp23xxx_base
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
AUTO_LOAD = ["mcp23x17_base"]
|
||||
CODEOWNERS = ["@SenexCrenshaw", "@jesserockz"]
|
||||
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)
|
||||
mcp23S17 = mcp23S17_ns.class_("MCP23S17", mcp23x17_base.MCP23X17Base, spi.SPIDevice)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
|
@ -29,47 +21,12 @@ CONFIG_SCHEMA = (
|
|||
cv.Optional(CONF_DEVICEADDRESS, default=0): cv.uint8_t,
|
||||
}
|
||||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(mcp23xxx_base.MCP23XXX_CONFIG_SCHEMA)
|
||||
.extend(spi.spi_device_schema())
|
||||
)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
var = yield mcp23xxx_base.register_mcp23xxx(config)
|
||||
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]
|
||||
)
|
||||
|
|
|
@ -19,17 +19,15 @@ void MCP23S17::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->transfer_byte(mcp23x17_base::MCP23X17_IOCONA);
|
||||
this->transfer_byte(0b00011000); // Enable HAEN pins for addressing
|
||||
this->disable();
|
||||
|
||||
if (this->open_drain_ints_) {
|
||||
// enable open-drain interrupt pins, 3.3V-safe
|
||||
this->write_reg(mcp23x17_base::MCP23X17_IOCONA, 0x04);
|
||||
this->write_reg(mcp23x17_base::MCP23X17_IOCONB, 0x04);
|
||||
}
|
||||
}
|
||||
|
||||
void MCP23S17::dump_config() {
|
||||
|
@ -37,65 +35,6 @@ void MCP23S17::dump_config() {
|
|||
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);
|
||||
|
@ -115,12 +54,5 @@ bool MCP23S17::write_reg(uint8_t reg, uint8_t value) {
|
|||
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
|
||||
|
|
|
@ -1,47 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/mcp23x17_base/mcp23x17_base.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,
|
||||
class MCP23S17 : public mcp23x17_base::MCP23X17Base,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
|
||||
spi::DATA_RATE_8MHZ> {
|
||||
public:
|
||||
|
@ -51,36 +18,11 @@ class MCP23S17 : public Component,
|
|||
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:
|
||||
bool read_reg(uint8_t reg, uint8_t *value) override;
|
||||
bool write_reg(uint8_t reg, uint8_t value) override;
|
||||
|
||||
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
|
||||
|
|
8
esphome/components/mcp23x08_base/__init__.py
Normal file
8
esphome/components/mcp23x08_base/__init__.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
import esphome.codegen as cg
|
||||
from esphome.components import mcp23xxx_base
|
||||
|
||||
AUTO_LOAD = ["mcp23xxx_base"]
|
||||
CODEOWNERS = ["@jesserockz"]
|
||||
|
||||
mcp23x08_base_ns = cg.esphome_ns.namespace("mcp23x08_base")
|
||||
MCP23X08Base = mcp23x08_base_ns.class_("MCP23X08Base", mcp23xxx_base.MCP23XXXBase)
|
89
esphome/components/mcp23x08_base/mcp23x08_base.cpp
Normal file
89
esphome/components/mcp23x08_base/mcp23x08_base.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
#include "mcp23x08_base.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace mcp23x08_base {
|
||||
|
||||
static const char *TAG = "mcp23x08_base";
|
||||
|
||||
bool MCP23X08Base::digital_read(uint8_t pin) {
|
||||
uint8_t bit = pin % 8;
|
||||
uint8_t reg_addr = mcp23x08_base::MCP23X08_GPIO;
|
||||
uint8_t value = 0;
|
||||
this->read_reg(reg_addr, &value);
|
||||
return value & (1 << bit);
|
||||
}
|
||||
|
||||
void MCP23X08Base::digital_write(uint8_t pin, bool value) {
|
||||
uint8_t reg_addr = mcp23x08_base::MCP23X08_OLAT;
|
||||
this->update_reg(pin, value, reg_addr);
|
||||
}
|
||||
|
||||
void MCP23X08Base::pin_mode(uint8_t pin, uint8_t mode) {
|
||||
uint8_t iodir = mcp23x08_base::MCP23X08_IODIR;
|
||||
uint8_t gppu = mcp23x08_base::MCP23X08_GPPU;
|
||||
switch (mode) {
|
||||
case mcp23xxx_base::MCP23XXX_INPUT:
|
||||
this->update_reg(pin, true, iodir);
|
||||
break;
|
||||
case mcp23xxx_base::MCP23XXX_INPUT_PULLUP:
|
||||
this->update_reg(pin, true, iodir);
|
||||
this->update_reg(pin, true, gppu);
|
||||
break;
|
||||
case mcp23xxx_base::MCP23XXX_OUTPUT:
|
||||
this->update_reg(pin, false, iodir);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MCP23X08Base::pin_interrupt_mode(uint8_t pin, mcp23xxx_base::MCP23XXXInterruptMode interrupt_mode) {
|
||||
uint8_t gpinten = mcp23x08_base::MCP23X08_GPINTEN;
|
||||
uint8_t intcon = mcp23x08_base::MCP23X08_INTCON;
|
||||
uint8_t defval = mcp23x08_base::MCP23X08_DEFVAL;
|
||||
|
||||
switch (interrupt_mode) {
|
||||
case mcp23xxx_base::MCP23XXX_CHANGE:
|
||||
this->update_reg(pin, true, gpinten);
|
||||
this->update_reg(pin, false, intcon);
|
||||
break;
|
||||
case mcp23xxx_base::MCP23XXX_RISING:
|
||||
this->update_reg(pin, true, gpinten);
|
||||
this->update_reg(pin, true, intcon);
|
||||
this->update_reg(pin, true, defval);
|
||||
break;
|
||||
case mcp23xxx_base::MCP23XXX_FALLING:
|
||||
this->update_reg(pin, true, gpinten);
|
||||
this->update_reg(pin, true, intcon);
|
||||
this->update_reg(pin, false, defval);
|
||||
break;
|
||||
case mcp23xxx_base::MCP23XXX_NO_INTERRUPT:
|
||||
this->update_reg(pin, false, gpinten);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MCP23X08Base::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 == mcp23x08_base::MCP23X08_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 == mcp23x08_base::MCP23X08_OLAT) {
|
||||
this->olat_ = reg_value;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mcp23x08_base
|
||||
} // namespace esphome
|
39
esphome/components/mcp23x08_base/mcp23x08_base.h
Normal file
39
esphome/components/mcp23x08_base/mcp23x08_base.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/mcp23xxx_base/mcp23xxx_base.h"
|
||||
#include "esphome/core/esphal.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace mcp23x08_base {
|
||||
|
||||
enum MCP23S08GPIORegisters {
|
||||
// A side
|
||||
MCP23X08_IODIR = 0x00,
|
||||
MCP23X08_IPOL = 0x01,
|
||||
MCP23X08_GPINTEN = 0x02,
|
||||
MCP23X08_DEFVAL = 0x03,
|
||||
MCP23X08_INTCON = 0x04,
|
||||
MCP23X08_IOCON = 0x05,
|
||||
MCP23X08_GPPU = 0x06,
|
||||
MCP23X08_INTF = 0x07,
|
||||
MCP23X08_INTCAP = 0x08,
|
||||
MCP23X08_GPIO = 0x09,
|
||||
MCP23X08_OLAT = 0x0A,
|
||||
};
|
||||
|
||||
class MCP23X08Base : public mcp23xxx_base::MCP23XXXBase {
|
||||
public:
|
||||
bool digital_read(uint8_t pin) override;
|
||||
void digital_write(uint8_t pin, bool value) override;
|
||||
void pin_mode(uint8_t pin, uint8_t mode) override;
|
||||
void pin_interrupt_mode(uint8_t pin, mcp23xxx_base::MCP23XXXInterruptMode interrupt_mode) override;
|
||||
|
||||
protected:
|
||||
void update_reg(uint8_t pin, bool pin_value, uint8_t reg_a) override;
|
||||
|
||||
uint8_t olat_{0x00};
|
||||
};
|
||||
|
||||
} // namespace mcp23x08_base
|
||||
} // namespace esphome
|
8
esphome/components/mcp23x17_base/__init__.py
Normal file
8
esphome/components/mcp23x17_base/__init__.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
import esphome.codegen as cg
|
||||
from esphome.components import mcp23xxx_base
|
||||
|
||||
AUTO_LOAD = ["mcp23xxx_base"]
|
||||
CODEOWNERS = ["@jesserockz"]
|
||||
|
||||
mcp23x17_base_ns = cg.esphome_ns.namespace("mcp23x17_base")
|
||||
MCP23X17Base = mcp23x17_base_ns.class_("MCP23X17Base", mcp23xxx_base.MCP23XXXBase)
|
93
esphome/components/mcp23x17_base/mcp23x17_base.cpp
Normal file
93
esphome/components/mcp23x17_base/mcp23x17_base.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
#include "mcp23x17_base.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace mcp23x17_base {
|
||||
|
||||
static const char *TAG = "mcp23x17_base";
|
||||
|
||||
bool MCP23X17Base::digital_read(uint8_t pin) {
|
||||
uint8_t bit = pin % 8;
|
||||
uint8_t reg_addr = pin < 8 ? mcp23x17_base::MCP23X17_GPIOA : mcp23x17_base::MCP23X17_GPIOB;
|
||||
uint8_t value = 0;
|
||||
this->read_reg(reg_addr, &value);
|
||||
return value & (1 << bit);
|
||||
}
|
||||
|
||||
void MCP23X17Base::digital_write(uint8_t pin, bool value) {
|
||||
uint8_t reg_addr = pin < 8 ? mcp23x17_base::MCP23X17_OLATA : mcp23x17_base::MCP23X17_OLATB;
|
||||
this->update_reg(pin, value, reg_addr);
|
||||
}
|
||||
|
||||
void MCP23X17Base::pin_mode(uint8_t pin, uint8_t mode) {
|
||||
uint8_t iodir = pin < 8 ? mcp23x17_base::MCP23X17_IODIRA : mcp23x17_base::MCP23X17_IODIRB;
|
||||
uint8_t gppu = pin < 8 ? mcp23x17_base::MCP23X17_GPPUA : mcp23x17_base::MCP23X17_GPPUB;
|
||||
switch (mode) {
|
||||
case mcp23xxx_base::MCP23XXX_INPUT:
|
||||
this->update_reg(pin, true, iodir);
|
||||
break;
|
||||
case mcp23xxx_base::MCP23XXX_INPUT_PULLUP:
|
||||
this->update_reg(pin, true, iodir);
|
||||
this->update_reg(pin, true, gppu);
|
||||
break;
|
||||
case mcp23xxx_base::MCP23XXX_OUTPUT:
|
||||
this->update_reg(pin, false, iodir);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MCP23X17Base::pin_interrupt_mode(uint8_t pin, mcp23xxx_base::MCP23XXXInterruptMode interrupt_mode) {
|
||||
uint8_t gpinten = pin < 8 ? mcp23x17_base::MCP23X17_GPINTENA : mcp23x17_base::MCP23X17_GPINTENB;
|
||||
uint8_t intcon = pin < 8 ? mcp23x17_base::MCP23X17_INTCONA : mcp23x17_base::MCP23X17_INTCONB;
|
||||
uint8_t defval = pin < 8 ? mcp23x17_base::MCP23X17_DEFVALA : mcp23x17_base::MCP23X17_DEFVALB;
|
||||
|
||||
switch (interrupt_mode) {
|
||||
case mcp23xxx_base::MCP23XXX_CHANGE:
|
||||
this->update_reg(pin, true, gpinten);
|
||||
this->update_reg(pin, false, intcon);
|
||||
break;
|
||||
case mcp23xxx_base::MCP23XXX_RISING:
|
||||
this->update_reg(pin, true, gpinten);
|
||||
this->update_reg(pin, true, intcon);
|
||||
this->update_reg(pin, true, defval);
|
||||
break;
|
||||
case mcp23xxx_base::MCP23XXX_FALLING:
|
||||
this->update_reg(pin, true, gpinten);
|
||||
this->update_reg(pin, true, intcon);
|
||||
this->update_reg(pin, false, defval);
|
||||
break;
|
||||
case mcp23xxx_base::MCP23XXX_NO_INTERRUPT:
|
||||
this->update_reg(pin, false, gpinten);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MCP23X17Base::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 == mcp23x17_base::MCP23X17_OLATA) {
|
||||
reg_value = this->olat_a_;
|
||||
} else if (reg_addr == mcp23x17_base::MCP23X17_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 == mcp23x17_base::MCP23X17_OLATA) {
|
||||
this->olat_a_ = reg_value;
|
||||
} else if (reg_addr == mcp23x17_base::MCP23X17_OLATB) {
|
||||
this->olat_b_ = reg_value;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mcp23x17_base
|
||||
} // namespace esphome
|
52
esphome/components/mcp23x17_base/mcp23x17_base.h
Normal file
52
esphome/components/mcp23x17_base/mcp23x17_base.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/mcp23xxx_base/mcp23xxx_base.h"
|
||||
#include "esphome/core/esphal.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace mcp23x17_base {
|
||||
|
||||
enum MCP23X17GPIORegisters {
|
||||
// A side
|
||||
MCP23X17_IODIRA = 0x00,
|
||||
MCP23X17_IPOLA = 0x02,
|
||||
MCP23X17_GPINTENA = 0x04,
|
||||
MCP23X17_DEFVALA = 0x06,
|
||||
MCP23X17_INTCONA = 0x08,
|
||||
MCP23X17_IOCONA = 0x0A,
|
||||
MCP23X17_GPPUA = 0x0C,
|
||||
MCP23X17_INTFA = 0x0E,
|
||||
MCP23X17_INTCAPA = 0x10,
|
||||
MCP23X17_GPIOA = 0x12,
|
||||
MCP23X17_OLATA = 0x14,
|
||||
// B side
|
||||
MCP23X17_IODIRB = 0x01,
|
||||
MCP23X17_IPOLB = 0x03,
|
||||
MCP23X17_GPINTENB = 0x05,
|
||||
MCP23X17_DEFVALB = 0x07,
|
||||
MCP23X17_INTCONB = 0x09,
|
||||
MCP23X17_IOCONB = 0x0B,
|
||||
MCP23X17_GPPUB = 0x0D,
|
||||
MCP23X17_INTFB = 0x0F,
|
||||
MCP23X17_INTCAPB = 0x11,
|
||||
MCP23X17_GPIOB = 0x13,
|
||||
MCP23X17_OLATB = 0x15,
|
||||
};
|
||||
|
||||
class MCP23X17Base : public mcp23xxx_base::MCP23XXXBase {
|
||||
public:
|
||||
bool digital_read(uint8_t pin) override;
|
||||
void digital_write(uint8_t pin, bool value) override;
|
||||
void pin_mode(uint8_t pin, uint8_t mode) override;
|
||||
void pin_interrupt_mode(uint8_t pin, mcp23xxx_base::MCP23XXXInterruptMode interrupt_mode) override;
|
||||
|
||||
protected:
|
||||
void update_reg(uint8_t pin, bool pin_value, uint8_t reg_a) override;
|
||||
|
||||
uint8_t olat_a_{0x00};
|
||||
uint8_t olat_b_{0x00};
|
||||
};
|
||||
|
||||
} // namespace mcp23x17_base
|
||||
} // namespace esphome
|
118
esphome/components/mcp23xxx_base/__init__.py
Normal file
118
esphome/components/mcp23xxx_base/__init__.py
Normal file
|
@ -0,0 +1,118 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_NUMBER,
|
||||
CONF_MODE,
|
||||
CONF_INVERTED,
|
||||
CONF_INTERRUPT,
|
||||
CONF_OPEN_DRAIN_INTERRUPT,
|
||||
)
|
||||
from esphome.core import coroutine
|
||||
|
||||
CODEOWNERS = ["@jesserockz"]
|
||||
|
||||
mcp23xxx_base_ns = cg.esphome_ns.namespace("mcp23xxx_base")
|
||||
MCP23XXXBase = mcp23xxx_base_ns.class_("MCP23XXXBase", cg.Component)
|
||||
MCP23XXXGPIOPin = mcp23xxx_base_ns.class_("MCP23XXXGPIOPin", cg.GPIOPin)
|
||||
MCP23XXXGPIOMode = mcp23xxx_base_ns.enum("MCP23XXXGPIOMode")
|
||||
MCP23XXXInterruptMode = mcp23xxx_base_ns.enum("MCP23XXXInterruptMode")
|
||||
|
||||
MCP23XXX_INTERRUPT_MODES = {
|
||||
"NO_INTERRUPT": MCP23XXXInterruptMode.MCP23XXX_NO_INTERRUPT,
|
||||
"CHANGE": MCP23XXXInterruptMode.MCP23XXX_CHANGE,
|
||||
"RISING": MCP23XXXInterruptMode.MCP23XXX_RISING,
|
||||
"FALLING": MCP23XXXInterruptMode.MCP23XXX_FALLING,
|
||||
}
|
||||
|
||||
MCP23XXX_GPIO_MODES = {
|
||||
"INPUT": MCP23XXXGPIOMode.MCP23XXX_INPUT,
|
||||
"INPUT_PULLUP": MCP23XXXGPIOMode.MCP23XXX_INPUT_PULLUP,
|
||||
"OUTPUT": MCP23XXXGPIOMode.MCP23XXX_OUTPUT,
|
||||
}
|
||||
|
||||
MCP23XXX_CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_OPEN_DRAIN_INTERRUPT, default=False): cv.boolean,
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
@coroutine
|
||||
def register_mcp23xxx(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
cg.add(var.set_open_drain_ints(config[CONF_OPEN_DRAIN_INTERRUPT]))
|
||||
return var
|
||||
|
||||
|
||||
CONF_MCP23XXX = "mcp23xxx"
|
||||
MCP23XXX_OUTPUT_PIN_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_MCP23XXX): cv.use_id(MCP23XXXBase),
|
||||
cv.Required(CONF_NUMBER): cv.int_,
|
||||
cv.Optional(CONF_MODE, default="OUTPUT"): cv.enum(
|
||||
MCP23XXX_GPIO_MODES, upper=True
|
||||
),
|
||||
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||
cv.Optional(CONF_INTERRUPT, default="NO_INTERRUPT"): cv.enum(
|
||||
MCP23XXX_INTERRUPT_MODES, upper=True
|
||||
),
|
||||
}
|
||||
)
|
||||
MCP23XXX_INPUT_PIN_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_MCP23XXX): cv.use_id(MCP23XXXBase),
|
||||
cv.Required(CONF_NUMBER): cv.int_,
|
||||
cv.Optional(CONF_MODE, default="INPUT"): cv.enum(
|
||||
MCP23XXX_GPIO_MODES, upper=True
|
||||
),
|
||||
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||
cv.Optional(CONF_INTERRUPT, default="NO_INTERRUPT"): cv.enum(
|
||||
MCP23XXX_INTERRUPT_MODES, upper=True
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@pins.PIN_SCHEMA_REGISTRY.register(
|
||||
CONF_MCP23XXX, (MCP23XXX_OUTPUT_PIN_SCHEMA, MCP23XXX_INPUT_PIN_SCHEMA)
|
||||
)
|
||||
def mcp23xxx_pin_to_code(config):
|
||||
parent = yield cg.get_variable(config[CONF_MCP23XXX])
|
||||
yield MCP23XXXGPIOPin.new(
|
||||
parent,
|
||||
config[CONF_NUMBER],
|
||||
config[CONF_MODE],
|
||||
config[CONF_INVERTED],
|
||||
config[CONF_INTERRUPT],
|
||||
)
|
||||
|
||||
|
||||
# BEGIN Removed pin schemas below to show error in configuration
|
||||
# TODO remove in 1.19.0
|
||||
|
||||
for id in ["mcp23008", "mcp23s08", "mcp23017", "mcp23s17"]:
|
||||
PIN_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(id): cv.invalid(
|
||||
f"'{id}:' has been removed from the pin schema in 1.17.0, please use 'mcp23xxx:'"
|
||||
),
|
||||
cv.Required(CONF_NUMBER): cv.int_,
|
||||
cv.Optional(CONF_MODE, default="INPUT"): cv.enum(
|
||||
MCP23XXX_GPIO_MODES, upper=True
|
||||
),
|
||||
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||
cv.Optional(CONF_INTERRUPT, default="NO_INTERRUPT"): cv.enum(
|
||||
MCP23XXX_INTERRUPT_MODES, upper=True
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
@pins.PIN_SCHEMA_REGISTRY.register(id, (PIN_SCHEMA, PIN_SCHEMA))
|
||||
def pin_to_code(config):
|
||||
pass
|
||||
|
||||
|
||||
# END Removed pin schemas
|
21
esphome/components/mcp23xxx_base/mcp23xxx_base.cpp
Normal file
21
esphome/components/mcp23xxx_base/mcp23xxx_base.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "mcp23xxx_base.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace mcp23xxx_base {
|
||||
|
||||
float MCP23XXXBase::get_setup_priority() const { return setup_priority::IO; }
|
||||
|
||||
MCP23XXXGPIOPin::MCP23XXXGPIOPin(MCP23XXXBase *parent, uint8_t pin, uint8_t mode, bool inverted,
|
||||
MCP23XXXInterruptMode interrupt_mode)
|
||||
: GPIOPin(pin, mode, inverted), parent_(parent), interrupt_mode_(interrupt_mode) {}
|
||||
void MCP23XXXGPIOPin::setup() { this->pin_mode(this->mode_); }
|
||||
void MCP23XXXGPIOPin::pin_mode(uint8_t mode) {
|
||||
this->parent_->pin_mode(this->pin_, mode);
|
||||
this->parent_->pin_interrupt_mode(this->pin_, this->interrupt_mode_);
|
||||
}
|
||||
bool MCP23XXXGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
|
||||
void MCP23XXXGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
|
||||
|
||||
} // namespace mcp23xxx_base
|
||||
} // namespace esphome
|
55
esphome/components/mcp23xxx_base/mcp23xxx_base.h
Normal file
55
esphome/components/mcp23xxx_base/mcp23xxx_base.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/esphal.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace mcp23xxx_base {
|
||||
|
||||
enum MCP23XXXInterruptMode : uint8_t { MCP23XXX_NO_INTERRUPT = 0, MCP23XXX_CHANGE, MCP23XXX_RISING, MCP23XXX_FALLING };
|
||||
|
||||
/// Modes for MCP23XXX pins
|
||||
enum MCP23XXXGPIOMode : uint8_t {
|
||||
MCP23XXX_INPUT = INPUT, // 0x00
|
||||
MCP23XXX_INPUT_PULLUP = INPUT_PULLUP, // 0x02
|
||||
MCP23XXX_OUTPUT = OUTPUT // 0x01
|
||||
};
|
||||
|
||||
class MCP23XXXBase : public Component {
|
||||
public:
|
||||
virtual bool digital_read(uint8_t pin);
|
||||
virtual void digital_write(uint8_t pin, bool value);
|
||||
virtual void pin_mode(uint8_t pin, uint8_t mode);
|
||||
virtual void pin_interrupt_mode(uint8_t pin, MCP23XXXInterruptMode interrupt_mode);
|
||||
|
||||
void set_open_drain_ints(const bool value) { this->open_drain_ints_ = value; }
|
||||
float get_setup_priority() const override;
|
||||
|
||||
protected:
|
||||
// read a given register
|
||||
virtual bool read_reg(uint8_t reg, uint8_t *value);
|
||||
// write a value to a given register
|
||||
virtual bool write_reg(uint8_t reg, uint8_t value);
|
||||
// update registers with given pin value.
|
||||
virtual void update_reg(uint8_t pin, bool pin_value, uint8_t reg_a);
|
||||
|
||||
bool open_drain_ints_;
|
||||
};
|
||||
|
||||
class MCP23XXXGPIOPin : public GPIOPin {
|
||||
public:
|
||||
MCP23XXXGPIOPin(MCP23XXXBase *parent, uint8_t pin, uint8_t mode, bool inverted = false,
|
||||
MCP23XXXInterruptMode interrupt_mode = MCP23XXX_NO_INTERRUPT);
|
||||
|
||||
void setup() override;
|
||||
void pin_mode(uint8_t mode) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
|
||||
protected:
|
||||
MCP23XXXBase *parent_;
|
||||
MCP23XXXInterruptMode interrupt_mode_;
|
||||
};
|
||||
|
||||
} // namespace mcp23xxx_base
|
||||
} // namespace esphome
|
|
@ -255,6 +255,7 @@ CONF_INTENSITY = "intensity"
|
|||
CONF_INTERLOCK = "interlock"
|
||||
CONF_INTERNAL = "internal"
|
||||
CONF_INTERNAL_FILTER = "internal_filter"
|
||||
CONF_INTERRUPT = "interrupt"
|
||||
CONF_INTERVAL = "interval"
|
||||
CONF_INVALID_COOLDOWN = "invalid_cooldown"
|
||||
CONF_INVERT = "invert"
|
||||
|
|
|
@ -879,7 +879,7 @@ binary_sensor:
|
|||
- platform: gpio
|
||||
name: 'MCP23S08 Pin #1'
|
||||
pin:
|
||||
mcp23s08: mcp23s08_hub
|
||||
mcp23xxx: mcp23s08_hub
|
||||
# Use pin number 1
|
||||
number: 1
|
||||
# One of INPUT or INPUT_PULLUP
|
||||
|
@ -888,12 +888,22 @@ binary_sensor:
|
|||
- platform: gpio
|
||||
name: 'MCP23S17 Pin #1'
|
||||
pin:
|
||||
mcp23s17: mcp23s17_hub
|
||||
mcp23xxx: mcp23s17_hub
|
||||
# Use pin number 1
|
||||
number: 1
|
||||
# One of INPUT or INPUT_PULLUP
|
||||
mode: INPUT_PULLUP
|
||||
inverted: False
|
||||
- platform: gpio
|
||||
name: 'MCP23S17 Pin #1 with interrupt'
|
||||
pin:
|
||||
mcp23xxx: mcp23s17_hub
|
||||
# Use pin number 1
|
||||
number: 1
|
||||
# One of INPUT or INPUT_PULLUP
|
||||
mode: INPUT_PULLUP
|
||||
inverted: False
|
||||
interrupt: FALLING
|
||||
- platform: gpio
|
||||
pin: GPIO9
|
||||
name: 'Living Room Window'
|
||||
|
@ -1012,14 +1022,14 @@ binary_sensor:
|
|||
- platform: gpio
|
||||
name: 'MCP21 binary sensor'
|
||||
pin:
|
||||
mcp23017: mcp23017_hub
|
||||
mcp23xxx: mcp23017_hub
|
||||
number: 1
|
||||
mode: INPUT
|
||||
inverted: True
|
||||
- platform: gpio
|
||||
name: 'MCP22 binary sensor'
|
||||
pin:
|
||||
mcp23008: mcp23008_hub
|
||||
mcp23xxx: mcp23008_hub
|
||||
number: 7
|
||||
mode: INPUT_PULLUP
|
||||
inverted: False
|
||||
|
@ -1176,14 +1186,14 @@ output:
|
|||
- platform: gpio
|
||||
id: id22
|
||||
pin:
|
||||
mcp23017: mcp23017_hub
|
||||
mcp23xxx: mcp23017_hub
|
||||
number: 0
|
||||
mode: OUTPUT
|
||||
inverted: False
|
||||
- platform: gpio
|
||||
id: id23
|
||||
pin:
|
||||
mcp23008: mcp23008_hub
|
||||
mcp23xxx: mcp23008_hub
|
||||
number: 0
|
||||
mode: OUTPUT
|
||||
inverted: False
|
||||
|
@ -1459,7 +1469,7 @@ switch:
|
|||
- platform: gpio
|
||||
name: 'MCP23S08 Pin #0'
|
||||
pin:
|
||||
mcp23s08: mcp23s08_hub
|
||||
mcp23xxx: mcp23s08_hub
|
||||
# Use pin number 0
|
||||
number: 0
|
||||
mode: OUTPUT
|
||||
|
@ -1467,7 +1477,7 @@ switch:
|
|||
- platform: gpio
|
||||
name: 'MCP23S17 Pin #0'
|
||||
pin:
|
||||
mcp23s17: mcp23s17_hub
|
||||
mcp23xxx: mcp23s17_hub
|
||||
# Use pin number 0
|
||||
number: 1
|
||||
mode: OUTPUT
|
||||
|
@ -1755,10 +1765,10 @@ display:
|
|||
it.print("1234");
|
||||
- platform: tm1637
|
||||
clk_pin:
|
||||
mcp23017: mcp23017_hub
|
||||
mcp23xxx: mcp23017_hub
|
||||
number: 1
|
||||
dio_pin:
|
||||
mcp23017: mcp23017_hub
|
||||
mcp23xxx: mcp23017_hub
|
||||
number: 2
|
||||
intensity: 3
|
||||
lambda: |-
|
||||
|
|
|
@ -560,14 +560,14 @@ switch:
|
|||
- platform: gpio
|
||||
id: gpio_switch1
|
||||
pin:
|
||||
mcp23017: mcp23017_hub
|
||||
mcp23xxx: mcp23017_hub
|
||||
number: 0
|
||||
mode: OUTPUT
|
||||
interlock: &interlock [gpio_switch1, gpio_switch2, gpio_switch3]
|
||||
- platform: gpio
|
||||
id: gpio_switch2
|
||||
pin:
|
||||
mcp23008: mcp23008_hub
|
||||
mcp23xxx: mcp23008_hub
|
||||
number: 0
|
||||
mode: OUTPUT
|
||||
interlock: *interlock
|
||||
|
|
Loading…
Reference in a new issue