Anyone successfully used Pimoroni Badger with ESPHOME?

Has anyone managed to get ESPHOME to work successfully with a Pimoroni Badger 2040W? And able to give me some pointers?

I’ve got some basic code working with the Pi Pico but I haven’t found a combination to make the display work yet.

# Display is 296 x 128 pixels

substitutions:
  board: "rpipicow"
  name: "pitest"
  friendly_name: "Pi Test"
  default_state: "RESTORE_DEFAULT_OFF"
  ssid: "Pi Test Fallback"
  clk_pin:   GPIO18
  mosi_pin:  GPIO19
  miso_pin:  GPIO16 # Not required? see https://github.com/esphome/issues/issues/1462
  cs_pin:    GPIO17
  dc_pin:    GPIO20
  busy_pin:  GPIO26
  reset_pin: GPIO21
  model: "2.90inv2" #2.90in 2.90inv2 2.90inv2-r2 2.90in-b 2.90in-bV3
  screen_refresh: "30" # This per screen update NOT a timer!
  #full_update_every: "30"
  update_interval: 10s
  button_a: GPIO12
  button_b: GPIO13
  button_c: GPIO14
  button_down: GPIO11
  button_up: GPIO15
  badger_led: GPIO22
  pico_led: GPIO32 # ???Report of Pico LED being tied to WiFi???

esphome:
  name: ${name}
  friendly_name: ${friendly_name}

rp2040:
  board: ${board}
  framework:
    # Required until https://github.com/platformio/platform-raspberrypi/pull/36 is merged
    platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git

logger:

packages:
  api: !include ./common/api.yaml
  ota: !include ./common/ota.yaml
  wifi: !include ./common/wifi.yaml
  time: !include ./common/time.yaml
  common: !include ./common/globals.yaml

text_sensor:
  - platform: homeassistant
    name: "House state From Home Assistant"
    entity_id: sensor.house_state
    id: ha_house_state
    
spi:
  clk_pin: ${clk_pin}
  mosi_pin: ${mosi_pin}
  miso_pin: ${miso_pin}

color:
  - id: color_bg
    red: 0%
    green: 0%
    blue: 0%
    white: 0%
  - id: color_text
    red: 0%
    green: 0%
    blue: 0%
    white: 100%

display:
  - platform: waveshare_epaper
    id: badger_w
    cs_pin:
      number: ${cs_pin}
      inverted: true
    dc_pin: ${dc_pin}
    busy_pin:
      number: ${busy_pin}
      inverted: true
    reset_pin:
      number: ${reset_pin}
      inverted: true
    rotation: 270
    model: ${model}
    update_interval: ${update_interval}
#    full_update_every: ${screen_refresh}
    lambda: |-
      it.fill(COLOR_ON);      
      char str[17];
      time_t currTime = id(homeassistant_time).now().timestamp;
      strftime(str, sizeof(str), "%H:%M", localtime(&currTime));
      it.printf(20, 50, id(comic_sans), COLOR_OFF, "Time: %s", str);

font:
  - file: 'fonts/Comic Sans.ttf'
    id: comic_sans
    size: 8

binary_sensor:
  - platform: status
    name: "Status"
    id: device_status

  - platform: gpio
    pin:
      number: ${button_a}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button a"
    on_press:
      then:
      - output.turn_on: badger_led
      - component.update: badger_w
      - delay: 0.5s
    on_release:
      then:
      - output.turn_off: badger_led
  - platform: gpio
    pin:
      number: ${button_b}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button b"  
    on_press:
      then:
      - component.update: badger_w
  - platform: gpio
    pin:
      number: ${button_c}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button c"  
    on_press:
      then:
      - component.update: badger_w
  - platform: gpio
    pin:
      number: ${button_up}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button up" 
    on_press:
      then:
      - component.update: badger_w
  - platform: gpio
    pin:
      number: ${button_down}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button down"
    on_press:
      then:
      - component.update: badger_w

output:
  - platform: rp2040_pwm
    pin: ${badger_led}
    id: badger_led
  - platform: gpio
    pin: ${pico_led}
    id: pico_led

light:
  - platform: monochromatic
    name: "Badger LED"
    output: badger_led
  - platform: binary
    name: "Pico LED"
    id: picow_led
    output: pico_led

sensor:
  - platform: internal_temperature
    name: "Internal Temperature"
    update_interval: 300s
    id: processor_internal_temperature

button:
  - platform: shutdown
    name: "Shutdown"
  - platform: restart
    name: "Restart"

This is my current code, it’s been through a few changes but it’s where I am now. I’ve tried different display versions and pin inversions (from looking at the circuit diagram).

As it stands I do not any screen updates at all, the display remains as the Pimoroni examples. All the Pico inputs and outputs work as expected.

I get this error but I cannot find a solution despite reading a number of post referencing the error.

[10:14:00][E][waveshare_epaper:159]: Timeout while displaying image!
[10:14:00][W][component:237]: Component display took a long time for an operation (1015 ms).
[10:14:00][W][component:238]: Components should block for at most 30 ms.

Dude, this is awesome. Sorry I am finding it years later.

Did you ever get this working?

Sorry I never did get this to work, that is I could not control the display, the pi worked a treat I could use the buttons and control the LEDs. Admittedly I’ve not spent a great deal of time since I posted this to do any more investigation.

Why not use one of the dozens and dozens of different esp32 w/display thats already supported and ready to go?

I have the Badger and looking for an interesting way to use it with Home Assistant, rather than the included Badger software.

Ya, I get that but sometimes its just not worth the hassle making something work that isnt supported and for the bargain basement price of 20-25$ you can buy an alternative that is supported out of the box. Something valued at hundreds of dollars, I would get that and try to make it work but, thats just me and my opinion after many years working with this stuff and learned many lessons from wasting time with dead ends…

Have you searched Github to see if anyone has already made a custom component for that display? Theres lots of good stuff on there. If there isnt, id recommend just putting it in storage and starting with a supported display but, you do you.

I might come back to this at some point, but until then I’m going to stick to the Badger software. This was always “I wonder if?” project.

I know absolutely nothing about the Badger software but if you can use something like mqtt with it then you could communicate with it and control it from HA or any esphome device. It would be a bunch of extra work but, totally doable and not to difficult.

I forgot sbout the new LVGL component and it works with just about any display.

https://esphome.io/components/lvgl/

Good news! I did some digging and after mashing up the code from above, with some more from a github issue and adding a dash of random experimentation I have the Badger 2040W working with ESPHome (screen included!). The trick is to use the ‘gdew029t5’ display type!

The display code looks like this:

spi:
  clk_pin: ${clk_pin}
  mosi_pin: ${mosi_pin}
  miso_pin: ${miso_pin}

display:
  - platform: waveshare_epaper
    cs_pin: ${cs_pin}
    dc_pin: ${dc_pin}
    busy_pin: ${busy_pin}
    reset_pin: ${reset_pin}
    model: gdew029t5
    rotation: 270
    update_interval: 5s
    lambda: |-
      it.line(0, 0, 100, 50);
      it.rectangle(5, 20, 30, 42);
      it.filled_rectangle(40, 40, 30, 42);
      it.circle(20, 40, 10);
      it.filled_circle(20, 75, 10);
      it.filled_ring(75, 75, 30, 20);
      it.filled_gauge(75, 75, 30, 20, 80);
      it.triangle(25, 5, 100, 5, 80, 25);
      it.filled_triangle(115, 5, 95, 25, 125, 70);
      it.filled_regular_polygon(170, 45, 20, EDGES_HEXAGON);
      it.regular_polygon(170, 45, 40, EDGES_OCTAGON, VARIATION_FLAT_TOP);

and the full code with everything I have working so far looks like this:

substitutions:
  clk_pin:   GPIO18
  mosi_pin:  GPIO19
  miso_pin:  GPIO16
  cs_pin:    GPIO17
  dc_pin:    GPIO20
  busy_pin:  GPIO26
  reset_pin: GPIO21
  button_a: GPIO12
  button_b: GPIO13
  button_c: GPIO14
  button_down: GPIO11
  button_up: GPIO15
  badger_led: GPIO22
  pico_led: GPIO32

esphome:
  name: badger-rp2040
  friendly_name: Badger RP2040

rp2040:
  board: rpipicow

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "ufkAYb7WCVvqHYe20deUknnTb8SSFUb2mSQ1X6y4Lng="

ota:
  - platform: esphome
    password: "9ec6880a365c267827789d294a5b9209"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password


text_sensor:
  - platform: homeassistant
    name: "House state From Home Assistant"
    entity_id: sensor.house_state
    id: ha_house_state
    
spi:
  clk_pin: ${clk_pin}
  mosi_pin: ${mosi_pin}
  miso_pin: ${miso_pin}

display:
  - platform: waveshare_epaper
    cs_pin: ${cs_pin}
    dc_pin: ${dc_pin}
    busy_pin: ${busy_pin}
    reset_pin: ${reset_pin}
    model: gdew029t5
    rotation: 270
    update_interval: 5s
    lambda: |-
      it.line(0, 0, 100, 50);
      it.rectangle(5, 20, 30, 42);
      it.filled_rectangle(40, 40, 30, 42);
      it.circle(20, 40, 10);
      it.filled_circle(20, 75, 10);
      it.filled_ring(75, 75, 30, 20);
      it.filled_gauge(75, 75, 30, 20, 80);
      it.triangle(25, 5, 100, 5, 80, 25);
      it.filled_triangle(115, 5, 95, 25, 125, 70);
      it.filled_regular_polygon(170, 45, 20, EDGES_HEXAGON);
      it.regular_polygon(170, 45, 40, EDGES_OCTAGON, VARIATION_FLAT_TOP);
  



binary_sensor:
  - platform: status
    name: "Status"
    id: device_status

  - platform: gpio
    pin:
      number: ${button_a}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button a"
    on_press:
      then:
      - output.turn_on: badger_led
    on_release:
      then:
      - output.turn_off: badger_led
  - platform: gpio
    pin:
      number: ${button_b}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button b"  

  - platform: gpio
    pin:
      number: ${button_c}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button c"  

  - platform: gpio
    pin:
      number: ${button_up}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button up" 

  - platform: gpio
    pin:
      number: ${button_down}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button down"


output:
  - platform: rp2040_pwm
    pin: ${badger_led}
    id: badger_led
  - platform: gpio
    pin: ${pico_led}
    id: pico_led

light:
  - platform: monochromatic
    name: "Badger LED"
    output: badger_led
  - platform: binary
    name: "Pico LED"
    id: picow_led
    output: pico_led

sensor:
  - platform: internal_temperature
    name: "Internal Temperature"
    update_interval: 60s
    id: processor_internal_temperature

button:
  - platform: shutdown
    name: "Shutdown"
  - platform: restart
    name: "Restart"

If anyone wants to see it in action, here’s my Badger controlling lights in my office while also displaying stocks, 3d printer progress, time and temperature!

Excellent work, thank you!

I’ve got the display renderer test card up and running, now time to tinker and see if this can actually be useful to my household. Exciting times.

P.S. Would you care to share some of the code for actions in your video demonstration?

1 Like

The buttons are just automations on the HomeAssistant side.

Thanks, I’ve been tinkering around button presses and screen updates. That all seems to make sense, just need to get some nice looking fonts!!!

Also started to have a quick look at LVGL to see how that looks, but struggling to get started with a display, more reading required.

Still not sure what the use case is going to be yet, [very simple] media controller maybe?

This is the full YAML file. Obviously it refers to entities in my own HA install but should give you enough to get started!


substitutions:
  clk_pin:   GPIO18
  mosi_pin:  GPIO19
  miso_pin:  GPIO16
  cs_pin:    GPIO17
  dc_pin:    GPIO20
  busy_pin:  GPIO26
  reset_pin: GPIO21
  button_a: GPIO12
  button_b: GPIO13
  button_c: GPIO14
  button_down: GPIO11
  button_up: GPIO15
  badger_led: GPIO22
  pico_led: GPIO32
  i2c_sda: GPIO4
  i2c_scl: GPIO5

esphome:
  name: badger-rp2040
  friendly_name: Badger RP2040
  on_boot:
    then:
    # read the RTC time once when the system boots
    - pcf85063.read_time
    - component.update: badger_w           

rp2040:
  board: rpipicow

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "XXX"

ota:
  - platform: esphome
    password: "XXX"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

time:
  - platform: pcf85063
    id: pcf85063_time
    update_interval: never
  - platform: homeassistant
    on_time_sync:
      then:
        pcf85063.write_time:

font:
  - file:
      type: gfonts
      family: 'Kanit'
      weight: 600
    id: font_small
    size: 16
  - file:
      type: gfonts
      family: 'Kanit'
      weight: 600
    id: font_medium
    size: 28
  - file:
      type: gfonts
      family: 'Kanit'
      weight: 600
    id: font_large
    size: 42

color:

  - id: BLACK
    red: 0%
    green: 0%
    blue: 0%
    white: 0%

  - id: WHITE
    red: 100%
    green: 100%
    blue: 100%
    white: 100%

i2c:
  sda: ${i2c_sda}
  scl: ${i2c_scl}
  scan: true
  id: bus_a

spi:
  clk_pin: ${clk_pin}
  mosi_pin: ${mosi_pin}
  miso_pin: ${miso_pin}

# WIDTH 296
# HEIGHT 128

display:
  - platform: waveshare_epaper
    cs_pin: ${cs_pin}
    id: badger_w
    dc_pin: ${dc_pin}
    busy_pin: ${busy_pin}
    reset_pin: ${reset_pin}
    model: gdew029t5
    rotation: 270
    update_interval: 60s
    full_update_every: 10
    lambda: |-
      // SET COLORS
      const auto WHITE   = Color(0,   0,   0,   0);
      const auto BLACK   = Color(255, 255, 255, 0);       

      std::string my_custom_text = id(custom_text).state.c_str();
      if(my_custom_text.length() > 0) {
        // DISPLAY NOTIFICATIONS
        it.printf(10, 10, id(font_large), id(BLACK), "%s", id(custom_text).state.c_str());
      } else {

        // TOP BAR
          it.filled_rectangle(0, 0, 296, 38, BLACK);
          it.printf(it.get_width()-65, -3, id(font_medium), id(WHITE), "%.1f", id(office_temp).state);
          it.printf(10, -3, id(font_medium), id(WHITE), "%s", id(current_time).state.c_str());

        // BOTTOM NAV
          it.filled_rectangle(0, it.get_height()-24, 96, 24, BLACK);
          it.filled_rectangle(98, it.get_height()-24, 100, 24, BLACK);
          it.filled_rectangle(200, it.get_height()-24, 96, 24, BLACK);
          it.print(23, it.get_height()-24, id(font_small), id(WHITE), "LAMP");
          it.print(126, it.get_height()-24, id(font_small), id(WHITE), "STRIP");
          it.print(236, it.get_height()-24, id(font_small), id(WHITE), "MK4");

        // MIDDLE ZONE
          
          it.printf(10, 45, id(font_small), id(BLACK), "BKNG");
          it.printf(10, 60, id(font_medium), id(BLACK), "%.0f", id(bkng).state);

          // 3D PRINTER STATUS
          if (id(mk4_progress).state > 0) {
            it.printf(230, 80, id(font_small), id(BLACK), "%.0f%%", id(mk4_progress).state);
            it.filled_gauge(245, 90, 40, 30, id(mk4_progress).state);
          } else {
            it.graph(100, 45, id(single_temperature_graph));
          }
      }    






graph:
  # Show bare-minimum auto-ranged graph
  - id: single_temperature_graph
    sensor: office_temp
    duration: 1h
    width: 176
    height: 51
    border: True

binary_sensor:
  - platform: status
    name: "Status"
    id: device_status

  - platform: gpio
    pin:
      number: ${button_a}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button a"
    id: "button_a"


  - platform: gpio
    pin:
      number: ${button_b}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button b"
    id: "button_b"      



  - platform: gpio
    pin:
      number: ${button_c}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button c"
    id: "button_c"      


  - platform: gpio
    pin:
      number: ${button_up}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button up"
    id: "button_up"
    on_press: 
      then:
        # - display.page.show_next: badger_w
        - component.update: badger_w

  - platform: gpio
    pin:
      number: ${button_down}
      inverted: false
      mode:
        input: true
        pulldown: true
    name: "Button down"
    id: "button_down"
    on_press: 
      then:
        # - display.page.show_previous: badger_w  
        - component.update: badger_w

output:
  - platform: rp2040_pwm
    pin: ${badger_led}
    id: badger_led
  - platform: gpio
    pin: ${pico_led}
    id: pico_led

light:
  - platform: monochromatic
    name: "Badger LED"
    output: badger_led
  - platform: binary
    name: "Pico LED"
    id: picow_led
    output: pico_led

sensor:
  - platform: internal_temperature
    name: "Internal Temperature"
    update_interval: 60s
    id: processor_internal_temperature
  - platform: homeassistant
    name: "Office Temp"
    id: "office_temp"
    entity_id: sensor.everything_presence_one_8d0bb8_temperature
  - platform: homeassistant
    name: "BKNG"
    id: "bkng"
    entity_id: sensor.bkng
  - platform: homeassistant
    name: "Mk4 Progress"
    id: "mk4_progress"
    entity_id: sensor.prusamk4_progress



text_sensor:
  - platform: template
    name: "Current Time"
    id: current_time
    update_interval: 30s
    lambda: return id(pcf85063_time).now().strftime("%H:%M");

button:
  - platform: shutdown
    name: "Shutdown"
  - platform: restart
    name: "Restart"

text:
  - platform: template
    name: "Custom Text"
    id: custom_text
    optimistic: true
    min_length: 0
    max_length: 100
    initial_value: ''
    mode: text
    on_value:
    - component.update: badger_w   

More than enough, thank you. I have various sensors displaying, just tinkering around with pages, layouts and fonts, hence my looking at LVGL, but so far LVGL has not brought me any display.

Away for a week visiting new grandchildren and I’ll get back to this when I get home. Didn’t think I could get away with bringing the Badger with me!!!

1 Like

I think I’m just about ready to call this project finished!