Changing fonts on an ESPHome with SSD1306 display from a HA drop down

I’ve got an ESP8266 with light and motion sensing set up. It sits under my TV and I thought it would be a nice extra to add an OLED display I had sitting around and use it as a clock.

I have the code working for the clock, and a custom font.

While trying to find the “right” font (best balance of readability and pretty), I decided to try and make the font selectable in real time, instead of having to compile a new binary every time I wanted to try out a change. I figured I could create a drop down in home assistant that triggered the change on the ESP.

I cannot quite figure it out, so I’m hoping there’s a superstar here that can help me debug because I’m chasing my tail. ChatGPT is leading me in (wrong) circles, and I’m not good enough at coding to work it out from the docs.


In home assistant’s configuration.yaml, I created a drop down:

# ESPHome Clock Font Selector
    name: Font Select
      - 7 segment
      - Anon
      - Arial
      - Consulate
      - Courier Prime
      - LM Mono
      - Noto Mono
      - Sicret
      - Cursed Timer

Then in the ESP device’s code editor, I have:

  name: esphome-web-ddf566

  board: esp01_1m

# Enable logging

  sda: 4
  scl: 5
  scan: true
  id: bus_a
  - platform: bh1750
    name: "Living Room Illuminance"
    address: 0x23
    update_interval: 60s  
  - platform: gpio
    pin: 13
    name: "Living Room PIR"
    device_class: motion  

  - platform: binary
    name: "PIR state"
    output: ESP_LED

  - id: ESP_LED
    platform: gpio
    pin: 2
    inverted: true

  - platform: homeassistant
    id: esptime

  !include fonts/fonts.yaml

  - platform: template
    name: "Font Select"
    id: font_select
    optimistic: true # This means it will assume state changes were successful without feedback from Home Assistant
    options: # These options must match exactly with your input_select options in Home Assistant
      - 7 Segment
      - Anon
      - Arial
      - Consulate
      - Courier Prime
      - LM Mono
      - Noto Mono
      - Sicret
      - Cursed Timer

  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    address: 0x3C
    # Print time in HH:MM format using the selected font
    lambda: |-
      if (id(font_select).state == "7 Segment") {
        it.strftime(63, 31, font1, TextAlign::CENTER, "%H:%M", id(esptime).now());
      } else if (id(font_select).state == "Anon") {
        it.strftime(63, 31, font2, TextAlign::CENTER, "%H:%M", id(esptime).now());
      } else if (id(font_select).state == "Arial") {
        it.strftime(63, 31, font3, TextAlign::CENTER, "%H:%M", id(esptime).now());
      } else if (id(font_select).state == "Consulate") {
        it.strftime(63, 31, font4, TextAlign::CENTER, "%H:%M", id(esptime).now());
      } else if (id(font_select).state == "Courier Prime") {
        it.strftime(63, 31, font5, TextAlign::CENTER, "%H:%M", id(esptime).now());
      } else if (id(font_select).state == "LM Mono") {
        it.strftime(63, 31, font6, TextAlign::CENTER, "%H:%M", id(esptime).now());
      } else if (id(font_select).state == "Noto Mono") {
        it.strftime(63, 31, font7, TextAlign::CENTER, "%H:%M", id(esptime).now());
      } else if (id(font_select).state == "Sicret") {
        it.strftime(63, 31, font8, TextAlign::CENTER, "%H:%M", id(esptime).now());
      } else if (id(font_select).state == "Cursed Timer") {
        it.strftime(63, 31, font9, TextAlign::CENTER, "%H:%M", id(esptime).now());

# it.strftime(63, 31, font1, TextAlign::CENTER, "%H:%M", id(esptime).now());

# Enable Home Assistant API
    service: set_font # This service allows you to set the font from Home Assistant using an automation or script
      option: string # The option is a string that matches one of your font options
      - # This action sets the template select option to match your input_select option
          id: font_select 
          option: !lambda 'return option;'


  ssid: !secret wifi_ssid
  password: !secret wifi_password
  output_power : 10.0
  power_save_mode: light

  # Enable fallback hotspot (captive portal) in case wifi connection fails
    ssid: "Esphome-Web-Ddf566"
    password: "hDZSUn5GGBND"


The information about the fonts is included with the !include fonts/fonts.yaml, and the content of the file is:

  - file: 'fonts/7seg.ttf'
    id: font1
    size: 40

  - file: 'fonts/anon.ttf'
    id: font2
    size: 40

  - file: 'fonts/arial.ttf'
    id: font3
    size: 40

  - file: 'fonts/consulate.ttf'
    id: font4
    size: 40

  - file: 'fonts/courierprime.ttf'
    id: font5
    size: 40
  - file: 'fonts/lmmono.ttf'
    id: font6
    size: 40
  - file: 'fonts/notomono.ttf'
    id: font7
    size: 40
  - file: 'fonts/sicret.ttf'
    id: font8
    size: 40

  - file: 'fonts/timer.ttf'
    id: font9
    size: 40

I’m confident the include for the fonts shouldn’t be the issue as it worked fine when I was hard coding the font style in the it.strftime statement.

when I try to validate the ESP code, I get the following error:

INFO Reading configuration /config/esphome/esphome-web-ddf566.yaml...
INFO Detected timezone 'Europe/London'
Failed config

api: [source /config/esphome/esphome-web-ddf566.yaml:93]
    service: set_font
      option: string
        Unable to find action with the name ''. 
          id: font_select
          option: !lambda |-
            return option;

What am I doing wrong here? TIA!

Should be select.set:

Thanks Daryl. This resolves the validation error and allows the code to compile, but changes to the dropdown do not result in changes on my ESPhome device’s display.

From the documentation, I think select.set: is doing the opposite of what I want, and updates the selected option in the HA dropdown with a value from the ESPhome code execution. Or am I misunderstanding something?

I was missing something. Something really obvious and I feel dumb now.

This code creates an input select FOR THE ESPHOME DEVICE NODE. I was trying to make changes using a HA input select. When I go to the ESPhome node, there’s a font select entity. Changes there result in changes on the node.

So, thanks Daryl for helping me fix the code, and thanks to my smooth brain for taking a while to realise why it wasn’t changing…

1 Like