From 75275c4e934746f33f81f6cc4aea251d04e88783 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Sat, 2 Nov 2019 20:31:39 +0100 Subject: [PATCH] Remove PCF8574 input_pullup mode and cleanup (#828) Fixes https://github.com/esphome/issues/issues/755 Closes https://github.com/esphome/esphome/pull/822 Fixes https://github.com/esphome/issues/issues/667 Closes https://github.com/esphome/esphome/pull/808 Co-Authored-By: Amish Vishwakarma Co-Authored-By: S-Przybylski --- esphome/components/pcf8574/__init__.py | 13 ++++-- esphome/components/pcf8574/pcf8574.cpp | 59 ++++++++++++-------------- esphome/components/pcf8574/pcf8574.h | 8 ++-- 3 files changed, 43 insertions(+), 37 deletions(-) diff --git a/esphome/components/pcf8574/__init__.py b/esphome/components/pcf8574/__init__.py index ad74ac70a9..daf367c089 100644 --- a/esphome/components/pcf8574/__init__.py +++ b/esphome/components/pcf8574/__init__.py @@ -11,7 +11,6 @@ pcf8574_ns = cg.esphome_ns.namespace('pcf8574') PCF8574GPIOMode = pcf8574_ns.enum('PCF8574GPIOMode') PCF8674_GPIO_MODES = { 'INPUT': PCF8574GPIOMode.PCF8574_INPUT, - 'INPUT_PULLUP': PCF8574GPIOMode.PCF8574_INPUT_PULLUP, 'OUTPUT': PCF8574GPIOMode.PCF8574_OUTPUT, } @@ -33,16 +32,24 @@ def to_code(config): cg.add(var.set_pcf8575(config[CONF_PCF8575])) +def validate_pcf8574_gpio_mode(value): + value = cv.string(value) + if value.upper() == 'INPUT_PULLUP': + raise cv.Invalid("INPUT_PULLUP mode has been removed in 1.14 and been combined into " + "INPUT mode (they were the same thing). Please use INPUT instead.") + return cv.enum(PCF8674_GPIO_MODES, upper=True)(value) + + PCF8574_OUTPUT_PIN_SCHEMA = cv.Schema({ cv.Required(CONF_PCF8574): cv.use_id(PCF8574Component), cv.Required(CONF_NUMBER): cv.int_, - cv.Optional(CONF_MODE, default="OUTPUT"): cv.enum(PCF8674_GPIO_MODES, upper=True), + cv.Optional(CONF_MODE, default="OUTPUT"): validate_pcf8574_gpio_mode, cv.Optional(CONF_INVERTED, default=False): cv.boolean, }) PCF8574_INPUT_PIN_SCHEMA = cv.Schema({ cv.Required(CONF_PCF8574): cv.use_id(PCF8574Component), cv.Required(CONF_NUMBER): cv.int_, - cv.Optional(CONF_MODE, default="INPUT"): cv.enum(PCF8674_GPIO_MODES, upper=True), + cv.Optional(CONF_MODE, default="INPUT"): validate_pcf8574_gpio_mode, cv.Optional(CONF_INVERTED, default=False): cv.boolean, }) diff --git a/esphome/components/pcf8574/pcf8574.cpp b/esphome/components/pcf8574/pcf8574.cpp index 50922e2f48..6cadf565de 100644 --- a/esphome/components/pcf8574/pcf8574.cpp +++ b/esphome/components/pcf8574/pcf8574.cpp @@ -31,9 +31,9 @@ bool PCF8574Component::digital_read(uint8_t pin) { } void PCF8574Component::digital_write(uint8_t pin, bool value) { if (value) { - this->port_mask_ |= (1 << pin); + this->output_mask_ |= (1 << pin); } else { - this->port_mask_ &= ~(1 << pin); + this->output_mask_ &= ~(1 << pin); } this->write_gpio_(); @@ -41,16 +41,14 @@ void PCF8574Component::digital_write(uint8_t pin, bool value) { void PCF8574Component::pin_mode(uint8_t pin, uint8_t mode) { switch (mode) { case PCF8574_INPUT: - this->ddr_mask_ &= ~(1 << pin); - this->port_mask_ &= ~(1 << pin); - break; - case PCF8574_INPUT_PULLUP: - this->ddr_mask_ &= ~(1 << pin); - this->port_mask_ |= (1 << pin); + // Clear mode mask bit + this->mode_mask_ &= ~(1 << pin); + // Write GPIO to enable input mode + this->write_gpio_(); break; case PCF8574_OUTPUT: - this->ddr_mask_ |= (1 << pin); - this->port_mask_ &= ~(1 << pin); + // Set mode mask bit + this->mode_mask_ |= 1 << pin; break; default: break; @@ -59,21 +57,20 @@ void PCF8574Component::pin_mode(uint8_t pin, uint8_t mode) { bool PCF8574Component::read_gpio_() { if (this->is_failed()) return false; - + bool success; + uint8_t data[2]; if (this->pcf8575_) { - if (!this->parent_->raw_receive_16(this->address_, &this->input_mask_, 1)) { - this->status_set_warning(); - return false; - } + success = this->read_bytes_raw(data, 2); + this->input_mask_ = (uint16_t(data[1]) << 8) | (uint16_t(data[0]) << 0); } else { - uint8_t data; - if (!this->parent_->raw_receive(this->address_, &data, 1)) { - this->status_set_warning(); - return false; - } - this->input_mask_ = data; + success = this->read_bytes_raw(data, 1); + this->input_mask_ = data[0]; } + if (!success) { + this->status_set_warning(); + return false; + } this->status_clear_warning(); return true; } @@ -81,20 +78,20 @@ bool PCF8574Component::write_gpio_() { if (this->is_failed()) return false; - uint16_t value = (this->input_mask_ & ~this->ddr_mask_) | this->port_mask_; + 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_; - this->parent_->raw_begin_transmission(this->address_); - uint8_t data = value & 0xFF; - this->parent_->raw_write(this->address_, &data, 1); - - if (this->pcf8575_) { - data = (value >> 8) & 0xFF; - this->parent_->raw_write(this->address_, &data, 1); - } - if (!this->parent_->raw_end_transmission(this->address_)) { + uint8_t data[2]; + data[0] = value; + data[1] = value >> 8; + if (!this->write_bytes_raw(data, this->pcf8575_ ? 2 : 1)) { this->status_set_warning(); return false; } + this->status_clear_warning(); return true; } diff --git a/esphome/components/pcf8574/pcf8574.h b/esphome/components/pcf8574/pcf8574.h index 390031c391..925fa30899 100644 --- a/esphome/components/pcf8574/pcf8574.h +++ b/esphome/components/pcf8574/pcf8574.h @@ -10,7 +10,6 @@ namespace pcf8574 { /// Modes for PCF8574 pins enum PCF8574GPIOMode : uint8_t { PCF8574_INPUT = INPUT, - PCF8574_INPUT_PULLUP = INPUT_PULLUP, PCF8574_OUTPUT = OUTPUT, }; @@ -38,9 +37,12 @@ class PCF8574Component : public Component, public i2c::I2CDevice { bool write_gpio_(); - uint16_t ddr_mask_{0x00}; + /// Mask for the pin mode - 1 means output, 0 means input + 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}; - uint16_t port_mask_{0x00}; bool pcf8575_; ///< TRUE->16-channel PCF8575, FALSE->8-channel PCF8574 };