support for the sx1509 i2c device (#651)

* added ANALOG_OUTPUT as first functionality

* added gpio

* seperated the code for different functions

* fixed code

* Revert "fixed code"

This reverts commit 0c6eacb225.

* add timings for breathe and blink

* made the sx1509_float_output am output component

* add keypad

* implementation for sx1509 keypad

* keypad code cleanup and first device tests

* debounce

* keypad working now.

* update for timings.
does not compile yet

* added all options for breathe and blink
fixed var namings

* blink and breath still not ok

* fixed ms for timings

* sync with repo

* fixed issue with gpio pin output

* code cleanup

* lint

* more lint

* remove log from header

* Update esphome/components/sx1509/__init__.py

Co-Authored-By: Otto Winter <otto@otto-winter.com>

* review

* feedback

* fixed review issues
did some extended testing with mqtt spy

* code cleanup (comments)

* fixed row col swap for binarysensor_keypad

* flake and lint

* travis

* travis

* travis

* Update esphome/components/sx1509/sx1509.cpp

Co-Authored-By: Otto Winter <otto@otto-winter.com>

* review

* separated platforms

* code cleanup

* travis relative paths in python

* remove blink/breathe
code cleanup

* cpp lint

* feedback

* travis

* lint line to long

* check keypad settings to be valid

* clang

* keypad config

* text

* Remove wrong .gitignore from .gitignore

* Remove .pio folder from .gitignore (merge)

* Formatting

* Formatting

* Add i2c log in dump_config

* Remove unused variables

* Disable static for header files

We don't need internal linkage

* Use consistent member default argument style

* Run clang-format


Co-authored-by: null <m.vanturnhout@exxellence.nl>
Co-authored-by: Otto Winter <otto@otto-winter.com>
This commit is contained in:
Michiel van Turnhout 2019-10-14 05:27:50 -04:00 committed by Otto Winter
parent be91cfb261
commit 5f2808ec2f
11 changed files with 701 additions and 0 deletions

View file

@ -0,0 +1,77 @@
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_KEYPAD = 'keypad'
CONF_KEY_ROWS = 'key_rows'
CONF_KEY_COLUMNS = 'key_columns'
CONF_SLEEP_TIME = 'sleep_time'
CONF_SCAN_TIME = 'scan_time'
CONF_DEBOUNCE_TIME = 'debounce_time'
DEPENDENCIES = ['i2c']
MULTI_CONF = True
sx1509_ns = cg.esphome_ns.namespace('sx1509')
SX1509GPIOMode = sx1509_ns.enum('SX1509GPIOMode')
SX1509_GPIO_MODES = {
'INPUT': SX1509GPIOMode.SX1509_INPUT,
'INPUT_PULLUP': SX1509GPIOMode.SX1509_INPUT_PULLUP,
'OUTPUT': SX1509GPIOMode.SX1509_OUTPUT
}
SX1509Component = sx1509_ns.class_('SX1509Component', cg.Component, i2c.I2CDevice)
SX1509GPIOPin = sx1509_ns.class_('SX1509GPIOPin', cg.GPIOPin)
KEYPAD_SCHEMA = cv.Schema({
cv.Required(CONF_KEY_ROWS): cv.int_range(min=1, max=8),
cv.Required(CONF_KEY_COLUMNS): cv.int_range(min=1, max=8),
cv.Optional(CONF_SLEEP_TIME): cv.int_range(min=128, max=8192),
cv.Optional(CONF_SCAN_TIME): cv.int_range(min=1, max=128),
cv.Optional(CONF_DEBOUNCE_TIME): cv.int_range(min=1, max=64),
})
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(SX1509Component),
cv.Optional(CONF_KEYPAD): cv.Schema(KEYPAD_SCHEMA),
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x3E))
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
if CONF_KEYPAD in config:
keypad = config[CONF_KEYPAD]
cg.add(var.set_rows_cols(keypad[CONF_KEY_ROWS], keypad[CONF_KEY_COLUMNS]))
if CONF_SLEEP_TIME in keypad and CONF_SCAN_TIME in keypad and CONF_DEBOUNCE_TIME in keypad:
cg.add(var.set_sleep_time(keypad[CONF_SLEEP_TIME]))
cg.add(var.set_scan_time(keypad[CONF_SCAN_TIME]))
cg.add(var.set_debounce_time(keypad[CONF_DEBOUNCE_TIME]))
CONF_SX1509 = 'sx1509'
CONF_SX1509_ID = 'sx1509_id'
SX1509_OUTPUT_PIN_SCHEMA = cv.Schema({
cv.Required(CONF_SX1509): cv.use_id(SX1509Component),
cv.Required(CONF_NUMBER): cv.int_,
cv.Optional(CONF_MODE, default="OUTPUT"): cv.enum(SX1509_GPIO_MODES, upper=True),
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
})
SX1509_INPUT_PIN_SCHEMA = cv.Schema({
cv.Required(CONF_SX1509): cv.use_id(SX1509Component),
cv.Required(CONF_NUMBER): cv.int_,
cv.Optional(CONF_MODE, default="INPUT"): cv.enum(SX1509_GPIO_MODES, upper=True),
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
})
@pins.PIN_SCHEMA_REGISTRY.register(CONF_SX1509,
(SX1509_OUTPUT_PIN_SCHEMA, SX1509_INPUT_PIN_SCHEMA))
def sx1509_pin_to_code(config):
parent = yield cg.get_variable(config[CONF_SX1509])
yield SX1509GPIOPin.new(parent, config[CONF_NUMBER], config[CONF_MODE],
config[CONF_INVERTED])

View file

@ -0,0 +1,28 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import binary_sensor
from esphome.const import CONF_ID
from .. import SX1509Component, sx1509_ns, CONF_SX1509_ID
CONF_ROW = 'row'
CONF_COLUMN = 'col'
DEPENDENCIES = ['sx1509']
SX1509BinarySensor = sx1509_ns.class_('SX1509BinarySensor', binary_sensor.BinarySensor)
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(SX1509BinarySensor),
cv.GenerateID(CONF_SX1509_ID): cv.use_id(SX1509Component),
cv.Required(CONF_ROW): cv.int_range(min=0, max=4),
cv.Required(CONF_COLUMN): cv.int_range(min=0, max=4),
})
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield binary_sensor.register_binary_sensor(var, config)
hub = yield cg.get_variable(config[CONF_SX1509_ID])
cg.add(var.set_row_col(config[CONF_ROW], config[CONF_COLUMN]))
cg.add(hub.register_keypad_binary_sensor(var))

View file

@ -0,0 +1,19 @@
#pragma once
#include "esphome/components/sx1509/sx1509.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
namespace esphome {
namespace sx1509 {
class SX1509BinarySensor : public sx1509::SX1509Processor, public binary_sensor::BinarySensor {
public:
void set_row_col(uint8_t row, uint8_t col) { this->key_ = (1 << (col + 8)) | (1 << row); }
void process(uint16_t data) override { this->publish_state(static_cast<bool>(data == key_)); }
protected:
uint16_t key_{0};
};
} // namespace sx1509
} // namespace esphome

View file

@ -0,0 +1,25 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import output
from esphome.const import CONF_PIN, CONF_ID
from .. import SX1509Component, sx1509_ns, CONF_SX1509_ID
DEPENDENCIES = ['sx1509']
SX1509FloatOutputChannel = sx1509_ns.class_('SX1509FloatOutputChannel',
output.FloatOutput, cg.Component)
CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend({
cv.Required(CONF_ID): cv.declare_id(SX1509FloatOutputChannel),
cv.GenerateID(CONF_SX1509_ID): cv.use_id(SX1509Component),
cv.Required(CONF_PIN): cv.int_range(min=0, max=15),
}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
parent = yield cg.get_variable(config[CONF_SX1509_ID])
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield output.register_output(var, config)
cg.add(var.set_pin(config[CONF_PIN]))
cg.add(var.set_parent(parent))

View file

@ -0,0 +1,30 @@
#include "sx1509_float_output.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace sx1509 {
static const char *TAG = "sx1509_float_channel";
void SX1509FloatOutputChannel::write_state(float state) {
const uint16_t max_duty = 255;
const float duty_rounded = roundf(state * max_duty);
auto duty = static_cast<uint16_t>(duty_rounded);
this->parent_->set_pin_value(this->pin_, duty);
}
void SX1509FloatOutputChannel::setup() {
ESP_LOGD(TAG, "setup pin %d", this->pin_);
this->parent_->pin_mode(this->pin_, SX1509_ANALOG_OUTPUT);
this->turn_off();
}
void SX1509FloatOutputChannel::dump_config() {
ESP_LOGCONFIG(TAG, "SX1509 PWM:");
ESP_LOGCONFIG(TAG, " sx1509 pin: %d", this->pin_);
LOG_FLOAT_OUTPUT(this);
}
} // namespace sx1509
} // namespace esphome

View file

@ -0,0 +1,27 @@
#pragma once
#include "esphome/components/sx1509/sx1509.h"
#include "esphome/components/output/float_output.h"
namespace esphome {
namespace sx1509 {
class SX1509Component;
class SX1509FloatOutputChannel : public output::FloatOutput, public Component {
public:
void set_parent(SX1509Component *parent) { this->parent_ = parent; }
void set_pin(uint8_t pin) { pin_ = pin; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::HARDWARE; }
protected:
void write_state(float state) override;
SX1509Component *parent_;
uint8_t pin_;
};
} // namespace sx1509
} // namespace esphome

View file

@ -0,0 +1,253 @@
#include "sx1509.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace sx1509 {
static const char *TAG = "sx1509";
void SX1509Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up SX1509Component...");
ESP_LOGV(TAG, " Resetting devices...");
if (!this->write_byte(REG_RESET, 0x12)) {
this->mark_failed();
return;
}
this->write_byte(REG_RESET, 0x34);
uint16_t data;
this->read_byte_16(REG_INTERRUPT_MASK_A, &data);
if (data == 0xFF00) {
clock_(INTERNAL_CLOCK_2MHZ);
} else {
this->mark_failed();
return;
}
delayMicroseconds(500);
if (this->has_keypad_)
this->setup_keypad_();
}
void SX1509Component::dump_config() {
ESP_LOGCONFIG(TAG, "SX1509:");
if (this->is_failed()) {
ESP_LOGE(TAG, "Setting up SX1509 failed!");
}
LOG_I2C_DEVICE(this);
}
void SX1509Component::loop() {
if (this->has_keypad_) {
uint16_t key_data = this->read_key_data();
for (auto *binary_sensor : this->keypad_binary_sensors_)
binary_sensor->process(key_data);
}
}
bool SX1509Component::digital_read(uint8_t pin) {
if (this->ddr_mask_ & (1 << pin)) {
uint16_t temp_reg_data;
this->read_byte_16(REG_DATA_B, &temp_reg_data);
if (temp_reg_data & (1 << pin))
return true;
}
return false;
}
void SX1509Component::digital_write(uint8_t pin, bool bit_value) {
if ((~this->ddr_mask_) & (1 << pin)) {
// If the pin is an output, write high/low
uint16_t temp_reg_data = 0;
this->read_byte_16(REG_DATA_B, &temp_reg_data);
if (bit_value)
temp_reg_data |= (1 << pin);
else
temp_reg_data &= ~(1 << pin);
this->write_byte_16(REG_DATA_B, temp_reg_data);
} else {
// Otherwise the pin is an input, pull-up/down
uint16_t temp_pullup;
this->read_byte_16(REG_PULL_UP_B, &temp_pullup);
uint16_t temp_pull_down;
this->read_byte_16(REG_PULL_DOWN_B, &temp_pull_down);
if (bit_value) {
// if HIGH, do pull-up, disable pull-down
temp_pullup |= (1 << pin);
temp_pull_down &= ~(1 << pin);
this->write_byte_16(REG_PULL_UP_B, temp_pullup);
this->write_byte_16(REG_PULL_DOWN_B, temp_pull_down);
} else {
// If LOW do pull-down, disable pull-up
temp_pull_down |= (1 << pin);
temp_pullup &= ~(1 << pin);
this->write_byte_16(REG_PULL_UP_B, temp_pullup);
this->write_byte_16(REG_PULL_DOWN_B, temp_pull_down);
}
}
}
void SX1509Component::pin_mode(uint8_t pin, uint8_t mode) {
this->read_byte_16(REG_DIR_B, &this->ddr_mask_);
if ((mode == SX1509_OUTPUT) || (mode == SX1509_ANALOG_OUTPUT))
this->ddr_mask_ &= ~(1 << pin);
else
this->ddr_mask_ |= (1 << pin);
this->write_byte_16(REG_DIR_B, this->ddr_mask_);
if (mode == INPUT_PULLUP)
digital_write(pin, HIGH);
if (mode == SX1509_ANALOG_OUTPUT) {
setup_led_driver_(pin);
}
}
void SX1509Component::setup_led_driver_(uint8_t pin) {
uint16_t temp_word;
uint8_t temp_byte;
this->read_byte_16(REG_INPUT_DISABLE_B, &temp_word);
temp_word |= (1 << pin);
this->write_byte_16(REG_INPUT_DISABLE_B, temp_word);
this->read_byte_16(REG_PULL_UP_B, &temp_word);
temp_word &= ~(1 << pin);
this->write_byte_16(REG_PULL_UP_B, temp_word);
this->ddr_mask_ &= ~(1 << pin); // 0=output
this->write_byte_16(REG_DIR_B, this->ddr_mask_);
this->read_byte(REG_CLOCK, &temp_byte);
temp_byte |= (1 << 6); // Internal 2MHz oscillator part 1 (set bit 6)
temp_byte &= ~(1 << 5); // Internal 2MHz oscillator part 2 (clear bit 5)
this->write_byte(REG_CLOCK, temp_byte);
this->read_byte(REG_MISC, &temp_byte);
temp_byte &= ~(1 << 7); // set linear mode bank B
temp_byte &= ~(1 << 3); // set linear mode bank A
temp_byte |= 0x70; // Frequency of the LED Driver clock ClkX of all IOs:
this->write_byte(REG_MISC, temp_byte);
this->read_byte_16(REG_LED_DRIVER_ENABLE_B, &temp_word);
temp_word |= (1 << pin);
this->write_byte_16(REG_LED_DRIVER_ENABLE_B, temp_word);
this->read_byte_16(REG_DATA_B, &temp_word);
temp_word &= ~(1 << pin);
this->write_byte_16(REG_DATA_B, temp_word);
}
void SX1509Component::clock_(byte osc_source, byte osc_pin_function, byte osc_freq_out, byte osc_divider) {
osc_source = (osc_source & 0b11) << 5; // 2-bit value, bits 6:5
osc_pin_function = (osc_pin_function & 1) << 4; // 1-bit value bit 4
osc_freq_out = (osc_freq_out & 0b1111); // 4-bit value, bits 3:0
byte reg_clock = osc_source | osc_pin_function | osc_freq_out;
this->write_byte(REG_CLOCK, reg_clock);
osc_divider = constrain(osc_divider, 1, 7);
this->clk_x_ = 2000000;
osc_divider = (osc_divider & 0b111) << 4; // 3-bit value, bits 6:4
uint8_t reg_misc;
this->read_byte(REG_MISC, &reg_misc);
reg_misc &= ~(0b111 << 4);
reg_misc |= osc_divider;
this->write_byte(REG_MISC, reg_misc);
}
void SX1509Component::setup_keypad_() {
uint8_t temp_byte;
// setup row/col pins for INPUT OUTPUT
this->read_byte_16(REG_DIR_B, &this->ddr_mask_);
for (int i = 0; i < this->rows_; i++)
this->ddr_mask_ &= ~(1 << i);
for (int i = 8; i < (this->cols_ * 2); i++)
this->ddr_mask_ |= (1 << i);
this->write_byte_16(REG_DIR_B, this->ddr_mask_);
this->read_byte(REG_OPEN_DRAIN_A, &temp_byte);
for (int i = 0; i < this->rows_; i++)
temp_byte |= (1 << i);
this->write_byte(REG_OPEN_DRAIN_A, temp_byte);
this->read_byte(REG_PULL_UP_B, &temp_byte);
for (int i = 0; i < this->cols_; i++)
temp_byte |= (1 << i);
this->write_byte(REG_PULL_UP_B, temp_byte);
if (debounce_time_ >= scan_time_) {
debounce_time_ = scan_time_ >> 1; // Force debounce_time to be less than scan_time
}
set_debounce_keypad_(debounce_time_, rows_, cols_);
uint8_t scan_time_bits = 0;
for (uint8_t i = 7; i > 0; i--) {
if (scan_time_ & (1 << i)) {
scan_time_bits = i;
break;
}
}
scan_time_bits &= 0b111; // Scan time is bits 2:0
temp_byte = sleep_time_ | scan_time_bits;
this->write_byte(REG_KEY_CONFIG_1, temp_byte);
rows_ = (rows_ - 1) & 0b111; // 0 = off, 0b001 = 2 rows, 0b111 = 8 rows, etc.
cols_ = (cols_ - 1) & 0b111; // 0b000 = 1 column, ob111 = 8 columns, etc.
this->write_byte(REG_KEY_CONFIG_2, (rows_ << 3) | cols_);
}
uint16_t SX1509Component::read_key_data() {
uint16_t key_data;
this->read_byte_16(REG_KEY_DATA_1, &key_data);
return (0xFFFF ^ key_data);
}
void SX1509Component::set_debounce_config_(uint8_t config_value) {
// First make sure clock is configured
uint8_t temp_byte;
this->read_byte(REG_MISC, &temp_byte);
temp_byte |= (1 << 4); // Just default to no divider if not set
this->write_byte(REG_MISC, temp_byte);
this->read_byte(REG_CLOCK, &temp_byte);
temp_byte |= (1 << 6); // default to internal osc.
this->write_byte(REG_CLOCK, temp_byte);
config_value &= 0b111; // 3-bit value
this->write_byte(REG_DEBOUNCE_CONFIG, config_value);
}
void SX1509Component::set_debounce_time_(uint8_t time) {
uint8_t config_value = 0;
for (int i = 7; i >= 0; i--) {
if (time & (1 << i)) {
config_value = i + 1;
break;
}
}
config_value = constrain(config_value, 0, 7);
set_debounce_config_(config_value);
}
void SX1509Component::set_debounce_enable_(uint8_t pin) {
uint16_t debounce_enable;
this->read_byte_16(REG_DEBOUNCE_ENABLE_B, &debounce_enable);
debounce_enable |= (1 << pin);
this->write_byte_16(REG_DEBOUNCE_ENABLE_B, debounce_enable);
}
void SX1509Component::set_debounce_pin_(uint8_t pin) { set_debounce_enable_(pin); }
void SX1509Component::set_debounce_keypad_(uint8_t time, uint8_t num_rows, uint8_t num_cols) {
set_debounce_time_(time);
for (uint16_t i = 0; i < num_rows; i++)
set_debounce_pin_(i);
for (uint16_t i = 0; i < (8 + num_cols); i++)
set_debounce_pin_(i);
}
} // namespace sx1509
} // namespace esphome

View file

@ -0,0 +1,89 @@
#pragma once
#include "esphome/components/i2c/i2c.h"
#include "esphome/core/component.h"
#include "sx1509_gpio_pin.h"
#include "sx1509_registers.h"
namespace esphome {
namespace sx1509 {
// These are used for clock config:
const uint8_t INTERNAL_CLOCK_2MHZ = 2;
const uint8_t EXTERNAL_CLOCK = 1;
const uint8_t SOFTWARE_RESET = 0;
const uint8_t HARDWARE_RESET = 1;
const uint8_t ANALOG_OUTPUT = 0x03; // To set a pin mode for PWM output
// PinModes for SX1509 pins
enum SX1509GPIOMode : uint8_t {
SX1509_INPUT = INPUT, // 0x00
SX1509_INPUT_PULLUP = INPUT_PULLUP, // 0x02
SX1509_ANALOG_OUTPUT = ANALOG_OUTPUT, // 0x03
SX1509_OUTPUT = OUTPUT, // 0x01
};
const uint8_t REG_I_ON[16] = {REG_I_ON_0, REG_I_ON_1, REG_I_ON_2, REG_I_ON_3, REG_I_ON_4, REG_I_ON_5,
REG_I_ON_6, REG_I_ON_7, REG_I_ON_8, REG_I_ON_9, REG_I_ON_10, REG_I_ON_11,
REG_I_ON_12, REG_I_ON_13, REG_I_ON_14, REG_I_ON_15};
// for all components that implement the process(uint16_t data )
class SX1509Processor {
public:
virtual void process(uint16_t data){};
};
class SX1509Component : public Component, public i2c::I2CDevice {
public:
SX1509Component() = default;
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::HARDWARE; }
void loop() override;
bool digital_read(uint8_t pin);
uint16_t read_key_data();
void set_pin_value(uint8_t pin, uint8_t i_on) { this->write_byte(REG_I_ON[pin], i_on); };
void pin_mode(uint8_t pin, uint8_t mode);
void digital_write(uint8_t pin, bool bit_value);
u_long get_clock() { return this->clk_x_; };
void set_rows_cols(uint8_t rows, uint8_t cols) {
this->rows_ = rows;
this->cols_ = cols;
this->has_keypad_ = true;
};
void set_sleep_time(uint16_t sleep_time) { this->sleep_time_ = sleep_time; };
void set_scan_time(uint8_t scan_time) { this->scan_time_ = scan_time; };
void set_debounce_time(uint8_t debounce_time = 1) { this->debounce_time_ = debounce_time; };
void register_keypad_binary_sensor(SX1509Processor *binary_sensor) {
this->keypad_binary_sensors_.push_back(binary_sensor);
};
protected:
u_long clk_x_ = 2000000;
uint8_t frequency_ = 0;
uint16_t ddr_mask_ = 0x00;
uint16_t input_mask_ = 0x00;
uint16_t port_mask_ = 0x00;
bool has_keypad_ = false;
uint8_t rows_ = 0;
uint8_t cols_ = 0;
uint16_t sleep_time_ = 128;
uint8_t scan_time_ = 1;
uint8_t debounce_time_ = 1;
std::vector<SX1509Processor *> keypad_binary_sensors_;
void setup_keypad_();
void set_debounce_config_(uint8_t config_value);
void set_debounce_time_(uint8_t time);
void set_debounce_pin_(uint8_t pin);
void set_debounce_enable_(uint8_t pin);
void set_debounce_keypad_(uint8_t time, uint8_t num_rows, uint8_t num_cols);
void setup_led_driver_(uint8_t pin);
void clock_(uint8_t osc_source = 2, uint8_t osc_pin_function = 1, uint8_t osc_freq_out = 0, uint8_t osc_divider = 0);
};
} // namespace sx1509
} // namespace esphome

View file

@ -0,0 +1,20 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include "sx1509_gpio_pin.h"
namespace esphome {
namespace sx1509 {
static const char *TAG = "sx1509_gpio_pin";
void SX1509GPIOPin::setup() {
ESP_LOGD(TAG, "setup pin %d", this->pin_);
this->parent_->pin_mode(this->pin_, this->mode_);
}
void SX1509GPIOPin::pin_mode(uint8_t mode) { this->parent_->pin_mode(this->pin_, mode); }
bool SX1509GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
void SX1509GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
} // namespace sx1509
} // namespace esphome

View file

@ -0,0 +1,24 @@
#pragma once
#include "sx1509.h"
namespace esphome {
namespace sx1509 {
class SX1509Component;
class SX1509GPIOPin : public GPIOPin {
public:
SX1509GPIOPin(SX1509Component *parent, uint8_t pin, uint8_t mode, bool inverted = false)
: GPIOPin(pin, mode, inverted), parent_(parent){};
void setup() override;
void pin_mode(uint8_t mode) override;
bool digital_read() override;
void digital_write(bool value) override;
protected:
SX1509Component *parent_;
};
} // namespace sx1509
} // namespace esphome

View file

@ -0,0 +1,109 @@
/******************************************************************************
sx1509_registers.h
Register definitions for SX1509.
Jim Lindblom @ SparkFun Electronics
Original Creation Date: September 21, 2015
https://github.com/sparkfun/SparkFun_SX1509_Arduino_Library
Here you'll find the Arduino code used to interface with the SX1509 I2C
16 I/O expander. There are functions to take advantage of everything the
SX1509 provides - input/output setting, writing pins high/low, reading
the input value of pins, LED driver utilities (blink, breath, pwm), and
keypad engine utilites.
Development environment specifics:
IDE: Arduino 1.6.5
Hardware Platform: Arduino Uno
SX1509 Breakout Version: v2.0
This code is beerware; if you see me (or any other SparkFun employee) at the
local, and you've found our code helpful, please buy us a round!
Distributed as-is; no warranty is given.
******************************************************************************/
#pragma once
namespace esphome {
namespace sx1509 {
const uint8_t REG_INPUT_DISABLE_B =
0x00; // RegInputDisableB Input buffer disable register _ I/O[15_8] (Bank B) 0000 0000
const uint8_t REG_INPUT_DISABLE_A =
0x01; // RegInputDisableA Input buffer disable register _ I/O[7_0] (Bank A) 0000 0000
const uint8_t REG_LONG_SLEW_B =
0x02; // RegLongSlewB Output buffer long slew register _ I/O[15_8] (Bank B) 0000 0000
const uint8_t REG_LONG_SLEW_A = 0x03; // RegLongSlewA Output buffer long slew register _ I/O[7_0] (Bank A) 0000 0000
const uint8_t REG_LOW_DRIVE_B =
0x04; // RegLowDriveB Output buffer low drive register _ I/O[15_8] (Bank B) 0000 0000
const uint8_t REG_LOW_DRIVE_A = 0x05; // RegLowDriveA Output buffer low drive register _ I/O[7_0] (Bank A) 0000 0000
const uint8_t REG_PULL_UP_B = 0x06; // RegPullUpB Pull_up register _ I/O[15_8] (Bank B) 0000 0000
const uint8_t REG_PULL_UP_A = 0x07; // RegPullUpA Pull_up register _ I/O[7_0] (Bank A) 0000 0000
const uint8_t REG_PULL_DOWN_B = 0x08; // RegPullDownB Pull_down register _ I/O[15_8] (Bank B) 0000 0000
const uint8_t REG_PULL_DOWN_A = 0x09; // RegPullDownA Pull_down register _ I/O[7_0] (Bank A) 0000 0000
const uint8_t REG_OPEN_DRAIN_B = 0x0A; // RegOpenDrainB Open drain register _ I/O[15_8] (Bank B) 0000 0000
const uint8_t REG_OPEN_DRAIN_A = 0x0B; // RegOpenDrainA Open drain register _ I/O[7_0] (Bank A) 0000 0000
const uint8_t REG_POLARITY_B = 0x0C; // RegPolarityB Polarity register _ I/O[15_8] (Bank B) 0000 0000
const uint8_t REG_POLARITY_A = 0x0D; // RegPolarityA Polarity register _ I/O[7_0] (Bank A) 0000 0000
const uint8_t REG_DIR_B = 0x0E; // RegDirB Direction register _ I/O[15_8] (Bank B) 1111 1111
const uint8_t REG_DIR_A = 0x0F; // RegDirA Direction register _ I/O[7_0] (Bank A) 1111 1111
const uint8_t REG_DATA_B = 0x10; // RegDataB Data register _ I/O[15_8] (Bank B) 1111 1111*
const uint8_t REG_DATA_A = 0x11; // RegDataA Data register _ I/O[7_0] (Bank A) 1111 1111*
const uint8_t REG_INTERRUPT_MASK_B =
0x12; // RegInterruptMaskB Interrupt mask register _ I/O[15_8] (Bank B) 1111 1111
const uint8_t REG_INTERRUPT_MASK_A =
0x13; // RegInterruptMaskA Interrupt mask register _ I/O[7_0] (Bank A) 1111 1111
const uint8_t REG_SENSE_HIGH_B = 0x14; // RegSenseHighB Sense register for I/O[15:12] 0000 0000
const uint8_t REG_SENSE_LOW_B = 0x15; // RegSenseLowB Sense register for I/O[11:8] 0000 0000
const uint8_t REG_SENSE_HIGH_A = 0x16; // RegSenseHighA Sense register for I/O[7:4] 0000 0000
const uint8_t REG_SENSE_LOW_A = 0x17; // RegSenseLowA Sense register for I/O[3:0] 0000 0000
const uint8_t REG_INTERRUPT_SOURCE_B =
0x18; // RegInterruptSourceB Interrupt source register _ I/O[15_8] (Bank B) 0000 0000
const uint8_t REG_INTERRUPT_SOURCE_A =
0x19; // RegInterruptSourceA Interrupt source register _ I/O[7_0] (Bank A) 0000 0000
const uint8_t REG_EVENT_STATUS_B = 0x1A; // RegEventStatusB Event status register _ I/O[15_8] (Bank B) 0000 0000
const uint8_t REG_EVENT_STATUS_A = 0x1B; // RegEventStatusA Event status register _ I/O[7_0] (Bank A) 0000 0000
const uint8_t REG_LEVEL_SHIFTER_1 = 0x1C; // RegLevelShifter1 Level shifter register 0000 0000
const uint8_t REG_LEVEL_SHIFTER_2 = 0x1D; // RegLevelShifter2 Level shifter register 0000 0000
const uint8_t REG_CLOCK = 0x1E; // RegClock Clock management register 0000 0000
const uint8_t REG_MISC = 0x1F; // RegMisc Miscellaneous device settings register 0000 0000
const uint8_t REG_LED_DRIVER_ENABLE_B =
0x20; // RegLEDDriverEnableB LED driver enable register _ I/O[15_8] (Bank B) 0000 0000
const uint8_t REG_LED_DRIVER_ENABLE_A =
0x21; // RegLEDDriverEnableA LED driver enable register _ I/O[7_0] (Bank A) 0000 0000
// Debounce and Keypad Engine
const uint8_t REG_DEBOUNCE_CONFIG = 0x22; // RegDebounceConfig Debounce configuration register 0000 0000
const uint8_t REG_DEBOUNCE_ENABLE_B =
0x23; // RegDebounceEnableB Debounce enable register _ I/O[15_8] (Bank B) 0000 0000
const uint8_t REG_DEBOUNCE_ENABLE_A =
0x24; // RegDebounceEnableA Debounce enable register _ I/O[7_0] (Bank A) 0000 0000
const uint8_t REG_KEY_CONFIG_1 = 0x25; // RegKeyConfig1 Key scan configuration register 0000 0000
const uint8_t REG_KEY_CONFIG_2 = 0x26; // RegKeyConfig2 Key scan configuration register 0000 0000
const uint8_t REG_KEY_DATA_1 = 0x27; // RegKeyData1 Key value (column) 1111 1111
const uint8_t REG_KEY_DATA_2 = 0x28; // RegKeyData2 Key value (row) 1111 1111
// LED Driver (PWM, blinking, breathing)
const uint8_t REG_I_ON_0 = 0x2A; // RegIOn0 ON intensity register for I/O[0] 1111 1111
const uint8_t REG_I_ON_1 = 0x2D; // RegIOn1 ON intensity register for I/O[1] 1111 1111
const uint8_t REG_I_ON_2 = 0x30; // RegIOn2 ON intensity register for I/O[2] 1111 1111
const uint8_t REG_I_ON_3 = 0x33; // RegIOn3 ON intensity register for I/O[3] 1111 1111
const uint8_t REG_I_ON_4 = 0x36; // RegIOn4 ON intensity register for I/O[4] 1111 1111
const uint8_t REG_I_ON_5 = 0x3B; // RegIOn5 ON intensity register for I/O[5] 1111 1111
const uint8_t REG_I_ON_6 = 0x40; // RegIOn6 ON intensity register for I/O[6] 1111 1111
const uint8_t REG_I_ON_7 = 0x45; // RegIOn7 ON intensity register for I/O[7] 1111 1111
const uint8_t REG_I_ON_8 = 0x4A; // RegIOn8 ON intensity register for I/O[8] 1111 1111
const uint8_t REG_I_ON_9 = 0x4D; // RegIOn9 ON intensity register for I/O[9] 1111 1111
const uint8_t REG_I_ON_10 = 0x50; // RegIOn10 ON intensity register for I/O[10] 1111 1111
const uint8_t REG_I_ON_11 = 0x53; // RegIOn11 ON intensity register for I/O[11] 1111 1111
const uint8_t REG_I_ON_12 = 0x56; // RegIOn12 ON intensity register for I/O[12] 1111 1111
const uint8_t REG_I_ON_13 = 0x5B; // RegIOn13 ON intensity register for I/O[13] 1111 1111
const uint8_t REG_I_ON_14 = 0x60; // RegIOn14 ON intensity register for I/O[14] 1111 1111
const uint8_t REG_I_ON_15 = 0x65; // RegIOn15 ON intensity register for I/O[15] 1111 1111
// Miscellaneous
const uint8_t REG_HIGH_INPUT_B = 0x69; // RegHighInputB High input enable register _ I/O[15_8] (Bank B) 0000 0000
const uint8_t REG_HIGH_INPUT_A = 0x6A; // RegHighInputA High input enable register _ I/O[7_0] (Bank A) 0000 0000
// Software Reset
const uint8_t REG_RESET = 0x7D; // RegReset Software reset register 0000 0000
const uint8_t REG_TEST_1 = 0x7E; // RegTest1 Test register 0000 0000
const uint8_t REG_TEST_2 = 0x7F; // RegTest2 Test register 0000 0000
} // namespace sx1509
} // namespace esphome