mirror of
https://github.com/randybb/esphome-configs.git
synced 2026-01-02 19:47:29 +01:00
have fun
This commit is contained in:
57
components/pca9554_2/__init__.py
Normal file
57
components/pca9554_2/__init__.py
Normal 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])
|
||||
96
components/pca9554_2/pca9554.cpp
Normal file
96
components/pca9554_2/pca9554.cpp
Normal 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
|
||||
61
components/pca9554_2/pca9554.h
Normal file
61
components/pca9554_2/pca9554.h
Normal 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
|
||||
Reference in New Issue
Block a user