I’ve recently purchased a 20x4 LCD display backed with a PCF8574 board (only only two data PINs in addition to the power). Initially it wouldn’t work with a NodeMCU v3 (no power indication) but after switching to a ESP32 I’ve got it working, but the display was way too bright…
Looking around ESPHome and Home Assistant no one seems to have wanted anything more than the ability to turn the backlight on or off, but elsewhere I found reference to being able to control the backlight with a PWM PIN
Step 1 was to remove the jumper from the pins labelled LED and then connect a jumper cable from the top PIN to D12 on the ESP32 Module (nothing needs to be connected to the bottom PIN, I just placed the jumper there for safe keeping).
Step 2 was to create a new Input Number Helper in Home Assistant with a range of 0 to 100 and set it to a sensible default - I chose 50%
Step 3 was to update the ESPHome config by adding a new output
block as follows
- platform: ledc
pin: GPIO12
id: backlight
and also a new Text Sensor
(where entity_id
matches that of the numeric_input you created earlier (e.g. input_number.mortara_backlight_level
), and the id
matches that defined in the output
block (e.g. backlight
))
text_sensor:
- platform: homeassistant
id: display_backlight
entity_id: input_number.mortara_backlight_level
internal: true
on_value:
then:
- output.turn_on: backlight
- output.set_level:
id: backlight
level: !lambda |-
return atoi(id(display_backlight).state.c_str()) / 100.0;
The on_value
block is a script that runs when the value is changed (including on boot), and it takes the value of the input_number and converts this to a percentage.
If you are already using the existing backlight()
no_backlight()
functions to turn the backlight off these are respected (e.g. if you change the input helper to 100% while your backlight binary sensor has the display turned off, it will remain off.
My full ESP Home config is as follows, it’s based on the ESPHome documentation but I found that the display address was different (look at the logs) and the wiring diagram I used had different PIN numbers.
On the display itself, the first line is generated by ESPHome, but the other three lines are set to the output of Input Helpers in Home Assistant.
esphome:
name: mortara
platform: ESP32
board: nodemcu-32s
wifi:
ssid: "MySSID"
password: "MyWiFiPassword"
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Mortara Fallback Hotspot"
password: "MyFallbackPassword"
captive_portal:
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
sensor:
- platform: wifi_signal
name: "Mortara - WiFi Signal Sensor"
update_interval: 60s
- platform: uptime
name: "Mortara - Uptime Sensor"
text_sensor:
- platform: version
name: "Mortara - ESPHome Version"
- platform: homeassistant
id: display_line_2
entity_id: input_text.mortara_line_2
internal: true
- platform: homeassistant
id: display_line_3
entity_id: input_text.mortara_line_3
internal: true
- platform: homeassistant
id: display_line_4
entity_id: input_text.mortara_line_4
internal: true
- platform: homeassistant
id: display_backlight
entity_id: input_number.mortara_backlight_level
internal: true
on_value:
then:
- output.turn_on: backlight
- output.set_level:
id: backlight
level: !lambda |-
return atoi(id(display_backlight).state.c_str()) / 100.0;
binary_sensor:
- platform: homeassistant
id: backlight_on
entity_id: input_boolean.mortara_backlight_on
internal: true
output:
- platform: ledc
pin: GPIO12
id: backlight
i2c:
sda: GPIO21
scl: GPIO22
scan: True
time:
- platform: homeassistant
id: my_time
timezone: "Europe/London"
display:
- platform: lcd_pcf8574
dimensions: 20x4
address: 0x27
id: mortara_lcd
lambda: |-
if(id(backlight_on).state) {
id(mortara_lcd).backlight();
fflush(stdout);
it.strftime(0,0," %H:%M %d-%b-%Y", id(my_time).now());
it.printf(0, 1, "%s", id(display_line_2).state.c_str());
it.printf(0, 2, "%s", id(display_line_3).state.c_str());
it.printf(0, 3, "%s", id(display_line_4).state.c_str());
} else {
id(mortara_lcd).no_backlight();
}