esphome / feature-requests

ESPHome Feature Request Tracker
https://esphome.io/
406 stars 26 forks source link

Support for displays with ST7789 #901

Open r-vit opened 3 years ago

r-vit commented 3 years ago

Describe the problem you have/What new integration you would like

I would like to be able to use displays that are based on the ST7789 Please describe your use case for this integration and alternatives you've tried:

Additional context

There's an Arduino and Platformio library that supports this type of displays: https://github.com/Bodmer/TFT_eSPI

napieraj commented 3 years ago

does the https://esphome.io/components/display/st7789v.html component not work for this model? does the V denote some major change?

r-vit commented 3 years ago

It looks like this component supports displays with a specific screen size (135x240) I tried to use it with mine (240x240), but it can't use the entire screen area

I tried to adapt the source code for the bigger displays, but realized that the component creates a screen buffer in RAM, so in my case it needs 240x240x3 bytes of RAM (if I'm not mistaken) and fails.

So, I had to just skip ESPHome entirely and use TFT_eSPI directly - that library works well.

bonochromatic commented 3 years ago

I've got three of these 240x240 ST7789's sitting at home and I'd love for them to be supported in ESPHome. I'm not really talented enough yet to know how to use Adafruit's drivers or TFT_eSPI within ESPHome, so I'm kind of at an impasse. I can design my builds to only utilize the 135 pixels that the ST7789v drivers afford, but that leaves almost half the screen's real estate sadly unutilized.

https://www.adafruit.com/product/3787 is the type of display I'm on about. Any hope for these little dudes?

haukurhafsteins commented 3 years ago

The following code from st7789v.cpp is used when setting up the display data. It looks like this causes the display to be offset and limited to 135x240 pixels as @r-vit mentioned.

void ST7789V::write_display_data() { uint16_t x1 = 52; // _offsetx uint16_t x2 = 186; // _offsetx uint16_t y1 = 40; // _offsety int16_t y2 = 279; // _offsety

Also the display size is hardcoded:

`int ST7789V::get_height_internal() { return 240; // 320; }

int ST7789V::get_width_internal() { return 135; // 240; }`

The attached image confirms this. A filled rectangle is drawn at 0.0 with width/height 100/100. St7789v-Display-Offset

As the st7789v.cpp is generated, I have not been able to change these code sections to confirm this.

haplm commented 3 years ago

@r-vit - Is it possible to use TFT_eSPI library with ESPHome? If it is, would you be so kind and give me (us) some hint how to do that? I also have one of these sitting idle in my drawer, and I'd like to utilise it... Thanks!

r-vit commented 3 years ago

@r-vit - Is it possible to use TFT_eSPI library with ESPHome? If it is, would you be so kind and give me (us) some hint how to do that? I also have one of these sitting idle in my drawer, and I'd like to utilise it... Thanks!

Unfortunately I wasn't able to make it work with ESPHome, so I just had to write an Arduino sketch using TFT_eSPI library and other libraries I needed to access wi-fi and mqtt server. In the end it was pretty easy, though it didn't integrate neatly into Home Assistant. But since I was able to use it to display some data from my HA, I considered that was enough for me.

haplm commented 3 years ago

I see, thank you. I guess I'll wait, maybe the ESPHome guys will decide to upgrade/enable the driver...

haukurhafsteins commented 3 years ago

I am using TFT_eSPI with ESPHome. NOTE: C++ knowledge is necessay to be able to use this solution.

You need to do the following:

According to documentation you do the following in the yaml file to create a custom component;

custom_component:

The problem is that the variable my_custom is local and not accessable elsewhere in the yaml. To fix that you create a golbal variable in your custom component *.h file that can be used instead.

Here is an example:

I call my custome compoent file display_controller.h (NOTE: this is a rough example) `

include

include

include "esphome.h"

class DisplayController : public Component { public: void setup() override { tft.init(); PrintOnScreen(); } void loop() override { update(); } void PrintOnScreen() { tft.fillRect(0, 0, 240, 40, TFT_BLACK); tft.setTextColor(TFT_BLACK, TFT_WHITE); tft.setCursor(8, 4); tft.println("Hello World..."); } private: TFT_eSPI tft = TFT_eSPI(); } ` // The globla diplay controller variable DisplayController *displayController;

Inside yaml you have the following: esphome: ... includes:

Now you use the displayController variable inside your lambdas to access functions to display things.

One more thing, inside the TFT_eSPI library you modify the User_Setup.h according to the display you use.

haplm commented 3 years ago

Thanks, @haukurhafsteins , this is very helpful. I guess I can manage.

markjsmith commented 3 years ago

I'd like to see a 240x 240 screen added too, its used on the Lanbon L8 touch screen wall switch, which looks terrific. I don't think i'm techy enough to follow this, but will give it a try.

davet2001 commented 2 years ago

I did some work on a related topic which probably helps here.

I was using an ili9341 which has a 16 bit 320x240 display. There is not enough ram in the esp32 to buffer all these pixels.

So instead the buffer is 8bit, which looks pretty bad. If the display driver you are using only has 16bit or 24bit mode coded, then above a certain resolution it won't compile for esp32 due to insufficient ram.

In this PR https://github.com/esphome/esphome/pull/2490 and the part2 which follows it, I enabled an 8bit pallet mode which keeps the buffer small but the colors good.

I think that could be used in a more generic way on other screens including the one requested here.

jboucher250 commented 2 years ago

@haukurhafsteins Can you elaborate on your last sentence please? I understand that I need User_Setup.h and have my copy of it all ready after proving it worked in my tests in Arduino IDE, but I have not sure how/where to put User_Setup.h in the right place/time to work with ESPHome. Thanks

haukurhafsteins commented 2 years ago

@jboucher250 If you have your copy of theTFT_eSPI library, the User_Setup.h should be located in the root folder. The following image shows a test project (xxx) where I use TFT_eSPI and it´s location in the project (using Microsoft Code editor). image

jboucher250 commented 2 years ago

@haukurhafsteins Thanks, I think I am still missing something. Here is a little more info about what I have. I am using ESPHome via Home Assistant and am not sure how I would point it to a local copy of the TFT_eSPI code. When I add the TFT_eSPI library as shown here, it pulls it from the web:

image

For visual, here is a pic of my Home Assistant config folder where you can see my custom component as well as a local copy of TFT_eSPI ready to go with my User_Setup.h within: image

How do I tell ESPHome to use that folder rather than TFT_eSPI from the web?

jboucher250 commented 2 years ago

I got it, thanks. Just needed to use file:///. Now I will be able to move it to a more appropriate location image

POWA-SE commented 2 years ago

Any news regarding this feature request?

djtoast commented 2 years ago

Id also like to revive this. Any chance this module would be added to esphome especially the 240x240

nagyrobi commented 1 year ago

Done in https://github.com/esphome/esphome/pull/3651

landonr commented 1 year ago

I think this is necessary for the tdisplay s3? I'm not sure how to set up the tft_espi https://github.com/Xinyuan-LilyGO/T-Display-S3

landonr commented 1 year ago

got it working for lilygo tdisplay s3 here. It flickers for me so I'm not super happy with it https://github.com/landonr/lilygo-tdisplays3-esphome

tcdsantos commented 1 year ago

I am using TFT_eSPI with ESPHome. NOTE: C++ knowledge is necessay to be able to use this solution.

You need to do the following:

  • Create a custom component that has a variable that is the tft display.
  • In your custom component you implement as many global function as you need to display someting.
  • In your yaml file you link in the TFT_eSPI under "libraries:" and implement the custom component under the "custom_component:" settings.
  • You access the custom component by using lambda in various places in your yaml file.

According to documentation you do the following in the yaml file to create a custom component;

custom_component:

  • lambda: |- auto my_custom = new MyCustomComponent(); return {my_custom};

The problem is that the variable my_custom is local and not accessable elsewhere in the yaml. To fix that you create a golbal variable in your custom component *.h file that can be used instead.

Here is an example:

I call my custome compoent file display_controller.h (NOTE: this is a rough example) ` #include #include #include "esphome.h"

class DisplayController : public Component { public: void setup() override { tft.init(); PrintOnScreen(); } void loop() override { update(); } void PrintOnScreen() { tft.fillRect(0, 0, 240, 40, TFT_BLACK); tft.setTextColor(TFT_BLACK, TFT_WHITE); tft.setCursor(8, 4); tft.println("Hello World..."); } private: TFT_eSPI tft = TFT_eSPI(); } ` // The globla diplay controller variable DisplayController *displayController;

Inside yaml you have the following: esphome: ... includes: - display_controller.h libraries: - TFT_eSPI ... custom_component:

  • lambda: |- displayController = new DisplayController(); App.register_component(displayController); return {displayController};

Now you use the displayController variable inside your lambdas to access functions to display things.

One more thing, inside the TFT_eSPI library you modify the User_Setup.h according to the display you use.

Hello @haukurhafsteins! This is a great solution!

I am trying to integrate TFT_eSPI library with ESPHome and I adopted your solution. I already have the Hello World string being displayed on screen.

However, I am stoped with two questions that maybe you (or someone else) could help me: 1) What is the propose of your update() function that is called inside the loop() function in display_controler.h file? 2) In my yaml file, how can I call a method from the displayController when a sensor state changes? I am not used to play with lambdas... I tried to understand how they work but I can only find examples of lambdas for filters and for the "display" component. If I have this simple binary sensor detailed below, how can I call displayController->my_custom_method() to print this sensor state on screen everytime it changes?

binary_sensor:
  - platform: gpio
    pin: 
      number: 19
      mode:
        input: true
        pullup: true
    name: "Aquarium Maximum Water Level 1"
    id: maximum_water_level_1

Can you help me?

Thank you very much!

landonr commented 1 year ago

this repo was updated today to work with the tdisplay s3 st7789 as a standard display https://github.com/landonr/lilygo-tdisplays3-esphome

kbx81 commented 1 year ago

Is there still an issue with the existing st7789 component in ESPHome? It now supports any resolution the ST7789 controller can handle. If it's still an issue, what exactly is the problem?

landonr commented 1 year ago

TDisplay S3 uses a patched version of the TFT_eSPI library. I'll test with the latest esphome to see if anything changed