This commit is contained in:
2024-05-23 21:24:52 +02:00
commit a3efe8274b
166 changed files with 15713 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
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
DEPENDENCIES = ['i2c']
MULTI_CONF = True
pca9554_ns = cg.esphome_ns.namespace('pca9554')
PCA9554GPIOMode = pca9554_ns.enum('PCA9554GPIOMode')
PCF8674_GPIO_MODES = {
'INPUT': PCA9554GPIOMode.PCA9554_INPUT,
'OUTPUT': PCA9554GPIOMode.PCA9554_OUTPUT,
}
PCA9554Component = pca9554_ns.class_('PCA9554Component', cg.Component, i2c.I2CDevice)
PCA9554GPIOPin = pca9554_ns.class_('PCA9554GPIOPin', cg.GPIOPin)
CONF_PCA9554 = 'pca9554'
CONF_PCF8575 = 'pcf8575'
CONFIG_SCHEMA = cv.Schema({
cv.Required(CONF_ID): cv.declare_id(PCA9554Component),
cv.Optional(CONF_PCF8575, default=False): cv.boolean,
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x20))
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
cg.add(var.set_pcf8575(config[CONF_PCF8575]))
def validate_pca9554_gpio_mode(value):
value = cv.string(value)
return cv.enum(PCF8674_GPIO_MODES, upper=True)(value)
PCA9554_OUTPUT_PIN_SCHEMA = cv.Schema({
cv.Required(CONF_PCA9554): cv.use_id(PCA9554Component),
cv.Required(CONF_NUMBER): cv.int_,
cv.Optional(CONF_MODE, default="OUTPUT"): validate_pca9554_gpio_mode,
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
})
PCA9554_INPUT_PIN_SCHEMA = cv.Schema({
cv.Required(CONF_PCA9554): cv.use_id(PCA9554Component),
cv.Required(CONF_NUMBER): cv.int_,
cv.Optional(CONF_MODE, default="INPUT"): validate_pca9554_gpio_mode,
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
})
@pins.PIN_SCHEMA_REGISTRY.register('pca9554', (PCA9554_OUTPUT_PIN_SCHEMA, PCA9554_INPUT_PIN_SCHEMA))
def pca9554_pin_to_code(config):
parent = yield cg.get_variable(config[CONF_PCA9554])
yield PCA9554GPIOPin.new(parent, config[CONF_NUMBER], config[CONF_MODE], config[CONF_INVERTED])

View File

@@ -0,0 +1,96 @@
#include "pca9554.h"
#include "esphome/core/log.h"
namespace esphome {
namespace pca9554 {
static const char *TAG = "pca9554";
void PCA9554Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up PCA9554...");
if (!this->read_gpio_()) {
ESP_LOGE(TAG, "PCA9554 not available under 0x%02X", this->address_);
this->mark_failed();
return;
}
this->write_gpio_();
this->read_gpio_();
}
void PCA9554Component::dump_config() {
ESP_LOGCONFIG(TAG, "PCA9554:");
LOG_I2C_DEVICE(this)
if (this->is_failed()) {
ESP_LOGE(TAG, "Communication with PCA9554 failed!");
}
}
bool PCA9554Component::digital_read(uint8_t pin) {
this->read_gpio_();
return this->input_mask_ & (1 << pin);
}
void PCA9554Component::digital_write(uint8_t pin, bool value) {
if (value) {
this->output_mask_ |= (1 << pin);
} else {
this->output_mask_ &= ~(1 << pin);
}
this->write_gpio_();
}
void PCA9554Component::pin_mode(uint8_t pin, uint8_t mode) {
switch (mode) {
case PCA9554_OUTPUT:
// Clear mode mask bit
this->mode_mask_ &= ~(1 << pin);
// Write GPIO to enable input mode
this->write_gpio_();
break;
case PCA9554_INPUT:
// Set mode mask bit
this->mode_mask_ |= 1 << pin;
break;
default:
break;
}
}
bool PCA9554Component::read_gpio_() {
if (this->is_failed())
return false;
bool success;
uint8_t data[2];
if (!success) {
this->status_set_warning();
return false;
}
this->status_clear_warning();
return true;
}
bool PCA9554Component::write_gpio_() {
if (this->is_failed())
return false;
uint16_t value = 0;
// Pins in OUTPUT mode and where pin is HIGH.
value |= this->mode_mask_ & this->output_mask_;
// Pins in INPUT mode must also be set here
value |= ~this->mode_mask_;
uint8_t data[2];
data[0] = value;
data[1] = value >> 8;
this->status_clear_warning();
return true;
}
float PCA9554Component::get_setup_priority() const { return setup_priority::IO; }
void PCA9554GPIOPin::setup() { this->pin_mode(this->mode_); }
bool PCA9554GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
void PCA9554GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
void PCA9554GPIOPin::pin_mode(uint8_t mode) { this->parent_->pin_mode(this->pin_, mode); }
PCA9554GPIOPin::PCA9554GPIOPin(PCA9554Component *parent, uint8_t pin, uint8_t mode, bool inverted)
: GPIOPin(pin, mode, inverted), parent_(parent) {}
} // namespace pca9554
} // namespace esphome

View File

@@ -0,0 +1,61 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/esphal.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace pca9554 {
/// Modes for PCA9554 pins
enum PCA9554GPIOMode : uint8_t {
PCA9554_INPUT = INPUT,
PCA9554_OUTPUT = OUTPUT,
};
class PCA9554Component : public Component, public i2c::I2CDevice {
public:
PCA9554Component() = default;
/// Check i2c availability and setup masks
void setup() override;
/// Helper function to read the value of a pin.
bool digital_read(uint8_t pin);
/// Helper function to write the value of a pin.
void digital_write(uint8_t pin, bool value);
/// Helper function to set the pin mode of a pin.
void pin_mode(uint8_t pin, uint8_t mode);
float get_setup_priority() const override;
void dump_config() override;
protected:
bool read_gpio_();
bool write_gpio_();
/// Mask for the pin mode - 1 means input, 0 means output
uint16_t mode_mask_{0x00};
/// The mask to write as output state - 1 means HIGH, 0 means LOW
uint16_t output_mask_{0x00};
/// The state read in read_gpio_ - 1 means HIGH, 0 means LOW
uint16_t input_mask_{0x00};
};
/// Helper class to expose a PCA9554 pin as an internal input GPIO pin.
class PCA9554GPIOPin : public GPIOPin {
public:
PCA9554GPIOPin(PCA9554Component *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:
PCA9554Component *parent_;
};
} // namespace pca9554
} // namespace esphome