WeAct 2.9" epaper module working

Not officially supported but it works:
Code:

spi:
  
  mosi_pin: GPIO15  # aka SDA
  clk_pin: GPIO02  #aka SCL

display:
  - platform: waveshare_epaper
    model: 2.90inV2
    cs_pin: GPIO16
    dc_pin: GPIO17
    reset_pin: GPIO05
    busy_pin: GPIO18
    rotation: 270
    full_update_every: 60
    update_interval: 2s
    lambda: |-    
      it.print(0, 0, id(font1), "Hello World!");    
      it.strftime(0, 64, id(font1), "%H:%M:%S", id(esptime).now());

4 Likes

Which board does it work with?
In my case this configuration does not work with en ESP-C3 board and Esphome.

The same screen work fine with the same ESP-C3 board running Arduino code.

I was using a NodeMCU ESP32 V1.1

Code:

esp32:
  board: esp32dev
  framework:
    type: arduino

Did you use the same i/o pins? On your board, you may need to use other i/o pins.

I managed to get it to work after several tries with ESPHome config and Arduino demo file :

**ESP32-C3 pinout:

  • DC=1,
  • RST=2,
  • BUSY=3,
  • SCL(SCK)=4,
  • SDA(MOSI)=6,
  • SS=7

*ESPHome test

# Setup SPI

spi:
  clk_pin: 4
  mosi_pin: 6

# Configuration for the display
display:
  - platform: waveshare_epaper
    model: 2.90inV2
    cs_pin: 7
    dc_pin: 1
    busy_pin: 3
    reset_pin: 2
    rotation: 270°
    id: my_display
    lambda: |-
      it.printf(125, 6, id(font1), TextAlign::TOP_CENTER, "%s", "Hello World!");
      it.strftime(125, 116, id(font1), TextAlign::BOTTOM_CENTER, "%Y-%m-%d %H:%M", id(time_homeassistant).now());

Arduino demo

// base class GxEPD2_GFX can be used to pass references or pointers to the display instance as parameter, uses ~1.2k more code

// enable or disable GxEPD2_GFX base class

#define ENABLE_GxEPD2_GFX 0

#include <GxEPD2_BW.h>

#include <GxEPD2_3C.h>

#include <Fonts/FreeMonoBold9pt7b.h>

// ESP32-C3 SS=7,SCL(SCK)=4,SDA(MOSI)=6,BUSY=3,RST=2,DC=1

// 2.13'' EPD Module

GxEPD2_BW<GxEPD2_213_BN, GxEPD2_213_BN::HEIGHT> display(GxEPD2_213_BN(/*CS=5*/ SS, /*DC=*/ 1, /*RST=*/ 2, /*BUSY=*/ 3)); // DEPG0213BN 122x250, SSD1680

//GxEPD2_3C<GxEPD2_213_Z98c, GxEPD2_213_Z98c::HEIGHT> display(GxEPD2_213_Z98c(/*CS=5*/ SS, /*DC=*/ 1, /*RST=*/ 2, /*BUSY=*/ 3)); // GDEY0213Z98 122x250, SSD1680

// 2.9'' EPD Module

//GxEPD2_BW<GxEPD2_290_BS, GxEPD2_290_BS::HEIGHT> display(GxEPD2_290_BS(/*CS=5*/ SS, /*DC=*/ 1, /*RST=*/ 2, /*BUSY=*/ 3)); // DEPG0290BS 128x296, SSD1680

//GxEPD2_3C<GxEPD2_290_C90c, GxEPD2_290_C90c::HEIGHT> display(GxEPD2_290_C90c(/*CS=5*/ SS, /*DC=*/ 1, /*RST=*/ 2, /*BUSY=*/ 3)); // GDEM029C90 128x296, SSD1680

void setup()

{

  pinMode(8, OUTPUT);

  digitalWrite(8, HIGH);

   

  display.init(115200,true,50,false);

  helloWorld();

  helloFullScreenPartialMode();

  delay(1000);

  if (display.epd2.hasFastPartialUpdate)

  {

    showPartialUpdate();

    delay(1000);

  }

  display.hibernate();

}

const char HelloWorld[] = "Hello World!";

const char HelloWeACtStudio[] = "WeAct Studio";

void helloWorld()

{

  display.setRotation(1);

  display.setFont(&FreeMonoBold9pt7b);

  display.setTextColor(GxEPD_BLACK);

  int16_t tbx, tby; uint16_t tbw, tbh;

  display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh);

  // center the bounding box by transposition of the origin:

  uint16_t x = ((display.width() - tbw) / 2) - tbx;

  uint16_t y = ((display.height() - tbh) / 2) - tby;

  display.setFullWindow();

  display.firstPage();

  do

  {

    display.fillScreen(GxEPD_WHITE);

    display.setCursor(x, y-tbh);

    display.print(HelloWorld);

    display.setTextColor(display.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK);

    display.getTextBounds(HelloWeACtStudio, 0, 0, &tbx, &tby, &tbw, &tbh);

    x = ((display.width() - tbw) / 2) - tbx;

    display.setCursor(x, y+tbh);

    display.print(HelloWeACtStudio);

  }

  while (display.nextPage());

}

void helloFullScreenPartialMode()

{

  //Serial.println("helloFullScreenPartialMode");

  const char fullscreen[] = "full screen update";

  const char fpm[] = "fast partial mode";

  const char spm[] = "slow partial mode";

  const char npm[] = "no partial mode";

  display.setPartialWindow(0, 0, display.width(), display.height());

  display.setRotation(1);

  display.setFont(&FreeMonoBold9pt7b);

  if (display.epd2.WIDTH < 104) display.setFont(0);

  display.setTextColor(GxEPD_BLACK);

  const char* updatemode;

  if (display.epd2.hasFastPartialUpdate)

  {

    updatemode = fpm;

  }

  else if (display.epd2.hasPartialUpdate)

  {

    updatemode = spm;

  }

  else

  {

    updatemode = npm;

  }

  // do this outside of the loop

  int16_t tbx, tby; uint16_t tbw, tbh;

  // center update text

  display.getTextBounds(fullscreen, 0, 0, &tbx, &tby, &tbw, &tbh);

  uint16_t utx = ((display.width() - tbw) / 2) - tbx;

  uint16_t uty = ((display.height() / 4) - tbh / 2) - tby;

  // center update mode

  display.getTextBounds(updatemode, 0, 0, &tbx, &tby, &tbw, &tbh);

  uint16_t umx = ((display.width() - tbw) / 2) - tbx;

  uint16_t umy = ((display.height() * 3 / 4) - tbh / 2) - tby;

  // center HelloWorld

  display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh);

  uint16_t hwx = ((display.width() - tbw) / 2) - tbx;

  uint16_t hwy = ((display.height() - tbh) / 2) - tby;

  display.firstPage();

  do

  {

    display.fillScreen(GxEPD_WHITE);

    display.setCursor(hwx, hwy);

    display.print(HelloWorld);

    display.setCursor(utx, uty);

    display.print(fullscreen);

    display.setCursor(umx, umy);

    display.print(updatemode);

  }

  while (display.nextPage());

  //Serial.println("helloFullScreenPartialMode done");

}

void showPartialUpdate()

{

  // some useful background

  helloWorld();

  // use asymmetric values for test

  uint16_t box_x = 10;

  uint16_t box_y = 15;

  uint16_t box_w = 70;

  uint16_t box_h = 20;

  uint16_t cursor_y = box_y + box_h - 6;

  if (display.epd2.WIDTH < 104) cursor_y = box_y + 6;

  float value = 13.95;

  uint16_t incr = display.epd2.hasFastPartialUpdate ? 1 : 3;

  display.setFont(&FreeMonoBold9pt7b);

  if (display.epd2.WIDTH < 104) display.setFont(0);

  display.setTextColor(GxEPD_BLACK);

  // show where the update box is

  for (uint16_t r = 0; r < 4; r++)

  {

    display.setRotation(r);

    display.setPartialWindow(box_x, box_y, box_w, box_h);

    display.firstPage();

    do

    {

      display.fillRect(box_x, box_y, box_w, box_h, GxEPD_BLACK);

      //display.fillScreen(GxEPD_BLACK);

    }

    while (display.nextPage());

    delay(2000);

    display.firstPage();

    do

    {

      display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE);

    }

    while (display.nextPage());

    delay(1000);

  }

  //return;

  // show updates in the update box

  for (uint16_t r = 0; r < 4; r++)

  {

    display.setRotation(r);

    display.setPartialWindow(box_x, box_y, box_w, box_h);

    for (uint16_t i = 1; i <= 10; i += incr)

    {

      display.firstPage();

      do

      {

        display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE);

        display.setCursor(box_x, cursor_y);

        display.print(value * i, 2);

      }

      while (display.nextPage());

      delay(500);

    }

    delay(1000);

    display.firstPage();

    do

    {

      display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE);

    }

    while (display.nextPage());

    delay(1000);

  }

}

void loop() {

  // put your main code here, to run repeatedly:

  digitalWrite(8, HIGH);

  delay(1000);

  digitalWrite(8, LOW);

  delay(1000);  

}
1 Like

Hello,
I’m trying to get a GDEY0213Z98 (2.13" b/w/r) work with esphome (not supported yet)
I was able to make it work with GxEPD2 library and arduino ide.

Did you find a way to mix both ? arduino and esphome ?