Add backlight handling for lcd_pcf8574 (#573)

* Add backlight handling for lcd_pcf8574

Switch the backlight on or off by calling id(mydisplay).backlight()
or id(mydisplay).no_backlight() in lamda functions (assuming mydisplay
is the custom id for the LCD).

* Use abstract method


Co-authored-by: Attila Darazs <attila@darazs.com>
Co-authored-by: Otto Winter <otto@otto-winter.com>
This commit is contained in:
Attila Darazs 2019-06-03 19:36:00 +02:00 committed by Otto Winter
parent ebe64e24f1
commit 30a542e763
8 changed files with 45 additions and 16 deletions

View file

@ -1,12 +1,11 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import display from esphome.components import display
from esphome.const import CONF_DIMENSIONS, CONF_LAMBDA from esphome.const import CONF_DIMENSIONS
from esphome.core import coroutine from esphome.core import coroutine
lcd_base_ns = cg.esphome_ns.namespace('lcd_base') lcd_base_ns = cg.esphome_ns.namespace('lcd_base')
LCDDisplay = lcd_base_ns.class_('LCDDisplay', cg.PollingComponent) LCDDisplay = lcd_base_ns.class_('LCDDisplay', cg.PollingComponent)
LCDDisplayRef = LCDDisplay.operator('ref')
def validate_lcd_dimensions(value): def validate_lcd_dimensions(value):
@ -28,8 +27,3 @@ def setup_lcd_display(var, config):
yield cg.register_component(var, config) yield cg.register_component(var, config)
yield display.register_display(var, config) yield display.register_display(var, config)
cg.add(var.set_dimensions(config[CONF_DIMENSIONS][0], config[CONF_DIMENSIONS][1])) cg.add(var.set_dimensions(config[CONF_DIMENSIONS][0], config[CONF_DIMENSIONS][1]))
if CONF_LAMBDA in config:
lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], [(LCDDisplayRef, 'it')],
return_type=cg.void)
cg.add(var.set_writer(lambda_))

View file

@ -107,7 +107,7 @@ void LCDDisplay::update() {
for (uint8_t i = 0; i < this->rows_ * this->columns_; i++) for (uint8_t i = 0; i < this->rows_ * this->columns_; i++)
this->buffer_[i] = ' '; this->buffer_[i] = ' ';
this->writer_(*this); this->call_writer();
this->display(); this->display();
} }
void LCDDisplay::command_(uint8_t value) { this->send(value, false); } void LCDDisplay::command_(uint8_t value) { this->send(value, false); }

View file

@ -12,11 +12,8 @@ namespace lcd_base {
class LCDDisplay; class LCDDisplay;
using lcd_writer_t = std::function<void(LCDDisplay &)>;
class LCDDisplay : public PollingComponent { class LCDDisplay : public PollingComponent {
public: public:
void set_writer(lcd_writer_t &&writer) { this->writer_ = std::move(writer); }
void set_dimensions(uint8_t columns, uint8_t rows) { void set_dimensions(uint8_t columns, uint8_t rows) {
this->columns_ = columns; this->columns_ = columns;
this->rows_ = rows; this->rows_ = rows;
@ -54,11 +51,11 @@ class LCDDisplay : public PollingComponent {
virtual void send(uint8_t value, bool rs) = 0; virtual void send(uint8_t value, bool rs) = 0;
void command_(uint8_t value); void command_(uint8_t value);
virtual void call_writer() = 0;
uint8_t columns_; uint8_t columns_;
uint8_t rows_; uint8_t rows_;
uint8_t *buffer_{nullptr}; uint8_t *buffer_{nullptr};
lcd_writer_t writer_;
}; };
} // namespace lcd_base } // namespace lcd_base

View file

@ -2,7 +2,8 @@ import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome import pins from esphome import pins
from esphome.components import lcd_base from esphome.components import lcd_base
from esphome.const import CONF_DATA_PINS, CONF_ENABLE_PIN, CONF_RS_PIN, CONF_RW_PIN, CONF_ID from esphome.const import CONF_DATA_PINS, CONF_ENABLE_PIN, CONF_RS_PIN, CONF_RW_PIN, CONF_ID, \
CONF_LAMBDA
AUTO_LOAD = ['lcd_base'] AUTO_LOAD = ['lcd_base']
@ -42,3 +43,9 @@ def to_code(config):
if CONF_RW_PIN in config: if CONF_RW_PIN in config:
rw = yield cg.gpio_pin_expression(config[CONF_RW_PIN]) rw = yield cg.gpio_pin_expression(config[CONF_RW_PIN])
cg.add(var.set_rw_pin(rw)) cg.add(var.set_rw_pin(rw))
if CONF_LAMBDA in config:
lambda_ = yield cg.process_lambda(config[CONF_LAMBDA],
[(GPIOLCDDisplay.operator('ref'), 'it')],
return_type=cg.void)
cg.add(var.set_writer(lambda_))

View file

@ -8,6 +8,7 @@ namespace lcd_gpio {
class GPIOLCDDisplay : public lcd_base::LCDDisplay { class GPIOLCDDisplay : public lcd_base::LCDDisplay {
public: public:
void set_writer(std::function<void(GPIOLCDDisplay &)> &&writer) { this->writer_ = std::move(writer); }
void setup() override; void setup() override;
void set_data_pins(GPIOPin *d0, GPIOPin *d1, GPIOPin *d2, GPIOPin *d3) { void set_data_pins(GPIOPin *d0, GPIOPin *d1, GPIOPin *d2, GPIOPin *d3) {
this->data_pins_[0] = d0; this->data_pins_[0] = d0;
@ -36,10 +37,13 @@ class GPIOLCDDisplay : public lcd_base::LCDDisplay {
void write_n_bits(uint8_t value, uint8_t n) override; void write_n_bits(uint8_t value, uint8_t n) override;
void send(uint8_t value, bool rs) override; void send(uint8_t value, bool rs) override;
void call_writer() override { this->writer_(*this); }
GPIOPin *rs_pin_{nullptr}; GPIOPin *rs_pin_{nullptr};
GPIOPin *rw_pin_{nullptr}; GPIOPin *rw_pin_{nullptr};
GPIOPin *enable_pin_{nullptr}; GPIOPin *enable_pin_{nullptr};
GPIOPin *data_pins_[8]{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; GPIOPin *data_pins_[8]{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
std::function<void(GPIOLCDDisplay &)> writer_;
}; };
} // namespace lcd_gpio } // namespace lcd_gpio

View file

@ -1,7 +1,7 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import lcd_base, i2c from esphome.components import lcd_base, i2c
from esphome.const import CONF_ID from esphome.const import CONF_ID, CONF_LAMBDA
DEPENDENCIES = ['i2c'] DEPENDENCIES = ['i2c']
AUTO_LOAD = ['lcd_base'] AUTO_LOAD = ['lcd_base']
@ -18,3 +18,9 @@ def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
yield lcd_base.setup_lcd_display(var, config) yield lcd_base.setup_lcd_display(var, config)
yield i2c.register_i2c_device(var, config) yield i2c.register_i2c_device(var, config)
if CONF_LAMBDA in config:
lambda_ = yield cg.process_lambda(config[CONF_LAMBDA],
[(PCF8574LCDDisplay.operator('ref'), 'it')],
return_type=cg.void)
cg.add(var.set_writer(lambda_))

View file

@ -6,9 +6,13 @@ namespace lcd_pcf8574 {
static const char *TAG = "lcd_pcf8574"; static const char *TAG = "lcd_pcf8574";
static const uint8_t LCD_DISPLAY_BACKLIGHT_ON = 0x08;
static const uint8_t LCD_DISPLAY_BACKLIGHT_OFF = 0x00;
void PCF8574LCDDisplay::setup() { void PCF8574LCDDisplay::setup() {
ESP_LOGCONFIG(TAG, "Setting up PCF8574 LCD Display..."); ESP_LOGCONFIG(TAG, "Setting up PCF8574 LCD Display...");
if (!this->write_bytes(0x08, nullptr, 0)) { this->backlight_value_ = LCD_DISPLAY_BACKLIGHT_ON;
if (!this->write_bytes(this->backlight_value_, nullptr, 0)) {
this->mark_failed(); this->mark_failed();
return; return;
} }
@ -29,7 +33,7 @@ void PCF8574LCDDisplay::write_n_bits(uint8_t value, uint8_t n) {
// Ugly fix: in the super setup() with n == 4 value needs to be shifted left // Ugly fix: in the super setup() with n == 4 value needs to be shifted left
value <<= 4; value <<= 4;
} }
uint8_t data = value | 0x08; // Enable backlight uint8_t data = value | this->backlight_value_; // Set backlight state
this->write_bytes(data, nullptr, 0); this->write_bytes(data, nullptr, 0);
// Pulse ENABLE // Pulse ENABLE
this->write_bytes(data | 0x04, nullptr, 0); this->write_bytes(data | 0x04, nullptr, 0);
@ -41,6 +45,14 @@ void PCF8574LCDDisplay::send(uint8_t value, bool rs) {
this->write_n_bits((value & 0xF0) | rs, 0); this->write_n_bits((value & 0xF0) | rs, 0);
this->write_n_bits(((value << 4) & 0xF0) | rs, 0); this->write_n_bits(((value << 4) & 0xF0) | rs, 0);
} }
void PCF8574LCDDisplay::backlight() {
this->backlight_value_ = LCD_DISPLAY_BACKLIGHT_ON;
this->write_bytes(this->backlight_value_, nullptr, 0);
}
void PCF8574LCDDisplay::no_backlight() {
this->backlight_value_ = LCD_DISPLAY_BACKLIGHT_OFF;
this->write_bytes(this->backlight_value_, nullptr, 0);
}
} // namespace lcd_pcf8574 } // namespace lcd_pcf8574
} // namespace esphome } // namespace esphome

View file

@ -9,13 +9,22 @@ namespace lcd_pcf8574 {
class PCF8574LCDDisplay : public lcd_base::LCDDisplay, public i2c::I2CDevice { class PCF8574LCDDisplay : public lcd_base::LCDDisplay, public i2c::I2CDevice {
public: public:
void set_writer(std::function<void(PCF8574LCDDisplay &)> &&writer) { this->writer_ = std::move(writer); }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
void backlight();
void no_backlight();
protected: protected:
bool is_four_bit_mode() override { return true; } bool is_four_bit_mode() override { return true; }
void write_n_bits(uint8_t value, uint8_t n) override; void write_n_bits(uint8_t value, uint8_t n) override;
void send(uint8_t value, bool rs) override; void send(uint8_t value, bool rs) override;
void call_writer() override { this->writer_(*this); }
// Stores the current state of the backlight.
uint8_t backlight_value_;
std::function<void(PCF8574LCDDisplay &)> writer_;
}; };
} // namespace lcd_pcf8574 } // namespace lcd_pcf8574