mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 09:01:49 +00:00 
			
		
		
		
	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:
		
				
					committed by
					
						
						Otto Winter
					
				
			
			
				
	
			
			
			
						parent
						
							ebe64e24f1
						
					
				
				
					commit
					30a542e763
				
			@@ -1,12 +1,11 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.components import display
 | 
			
		||||
from esphome.const import CONF_DIMENSIONS, CONF_LAMBDA
 | 
			
		||||
from esphome.const import CONF_DIMENSIONS
 | 
			
		||||
from esphome.core import coroutine
 | 
			
		||||
 | 
			
		||||
lcd_base_ns = cg.esphome_ns.namespace('lcd_base')
 | 
			
		||||
LCDDisplay = lcd_base_ns.class_('LCDDisplay', cg.PollingComponent)
 | 
			
		||||
LCDDisplayRef = LCDDisplay.operator('ref')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def validate_lcd_dimensions(value):
 | 
			
		||||
@@ -28,8 +27,3 @@ def setup_lcd_display(var, config):
 | 
			
		||||
    yield cg.register_component(var, config)
 | 
			
		||||
    yield display.register_display(var, config)
 | 
			
		||||
    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_))
 | 
			
		||||
 
 | 
			
		||||
@@ -107,7 +107,7 @@ void LCDDisplay::update() {
 | 
			
		||||
  for (uint8_t i = 0; i < this->rows_ * this->columns_; i++)
 | 
			
		||||
    this->buffer_[i] = ' ';
 | 
			
		||||
 | 
			
		||||
  this->writer_(*this);
 | 
			
		||||
  this->call_writer();
 | 
			
		||||
  this->display();
 | 
			
		||||
}
 | 
			
		||||
void LCDDisplay::command_(uint8_t value) { this->send(value, false); }
 | 
			
		||||
 
 | 
			
		||||
@@ -12,11 +12,8 @@ namespace lcd_base {
 | 
			
		||||
 | 
			
		||||
class LCDDisplay;
 | 
			
		||||
 | 
			
		||||
using lcd_writer_t = std::function<void(LCDDisplay &)>;
 | 
			
		||||
 | 
			
		||||
class LCDDisplay : public PollingComponent {
 | 
			
		||||
 public:
 | 
			
		||||
  void set_writer(lcd_writer_t &&writer) { this->writer_ = std::move(writer); }
 | 
			
		||||
  void set_dimensions(uint8_t columns, uint8_t rows) {
 | 
			
		||||
    this->columns_ = columns;
 | 
			
		||||
    this->rows_ = rows;
 | 
			
		||||
@@ -54,11 +51,11 @@ class LCDDisplay : public PollingComponent {
 | 
			
		||||
  virtual void send(uint8_t value, bool rs) = 0;
 | 
			
		||||
 | 
			
		||||
  void command_(uint8_t value);
 | 
			
		||||
  virtual void call_writer() = 0;
 | 
			
		||||
 | 
			
		||||
  uint8_t columns_;
 | 
			
		||||
  uint8_t rows_;
 | 
			
		||||
  uint8_t *buffer_{nullptr};
 | 
			
		||||
  lcd_writer_t writer_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace lcd_base
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,8 @@ import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome import pins
 | 
			
		||||
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']
 | 
			
		||||
 | 
			
		||||
@@ -42,3 +43,9 @@ def to_code(config):
 | 
			
		||||
    if CONF_RW_PIN in config:
 | 
			
		||||
        rw = yield cg.gpio_pin_expression(config[CONF_RW_PIN])
 | 
			
		||||
        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_))
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ namespace lcd_gpio {
 | 
			
		||||
 | 
			
		||||
class GPIOLCDDisplay : public lcd_base::LCDDisplay {
 | 
			
		||||
 public:
 | 
			
		||||
  void set_writer(std::function<void(GPIOLCDDisplay &)> &&writer) { this->writer_ = std::move(writer); }
 | 
			
		||||
  void setup() override;
 | 
			
		||||
  void set_data_pins(GPIOPin *d0, GPIOPin *d1, GPIOPin *d2, GPIOPin *d3) {
 | 
			
		||||
    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 send(uint8_t value, bool rs) override;
 | 
			
		||||
 | 
			
		||||
  void call_writer() override { this->writer_(*this); }
 | 
			
		||||
 | 
			
		||||
  GPIOPin *rs_pin_{nullptr};
 | 
			
		||||
  GPIOPin *rw_pin_{nullptr};
 | 
			
		||||
  GPIOPin *enable_pin_{nullptr};
 | 
			
		||||
  GPIOPin *data_pins_[8]{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
 | 
			
		||||
  std::function<void(GPIOLCDDisplay &)> writer_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace lcd_gpio
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.components import lcd_base, i2c
 | 
			
		||||
from esphome.const import CONF_ID
 | 
			
		||||
from esphome.const import CONF_ID, CONF_LAMBDA
 | 
			
		||||
 | 
			
		||||
DEPENDENCIES = ['i2c']
 | 
			
		||||
AUTO_LOAD = ['lcd_base']
 | 
			
		||||
@@ -18,3 +18,9 @@ def to_code(config):
 | 
			
		||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
			
		||||
    yield lcd_base.setup_lcd_display(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_))
 | 
			
		||||
 
 | 
			
		||||
@@ -6,9 +6,13 @@ namespace 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() {
 | 
			
		||||
  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();
 | 
			
		||||
    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
 | 
			
		||||
    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);
 | 
			
		||||
  // Pulse ENABLE
 | 
			
		||||
  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 << 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 esphome
 | 
			
		||||
 
 | 
			
		||||
@@ -9,13 +9,22 @@ namespace lcd_pcf8574 {
 | 
			
		||||
 | 
			
		||||
class PCF8574LCDDisplay : public lcd_base::LCDDisplay, public i2c::I2CDevice {
 | 
			
		||||
 public:
 | 
			
		||||
  void set_writer(std::function<void(PCF8574LCDDisplay &)> &&writer) { this->writer_ = std::move(writer); }
 | 
			
		||||
  void setup() override;
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
  void backlight();
 | 
			
		||||
  void no_backlight();
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  bool is_four_bit_mode() override { return true; }
 | 
			
		||||
  void write_n_bits(uint8_t value, uint8_t n) 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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user