Can I use this code also for the ESP8266? By just changing ESP32 to ESP8266?
Or will that not work?
Also can I provide mqtt username and password?
Because I do have that on my mqtt server.
Can I use this code also for the ESP8266? By just changing ESP32 to ESP8266?
Or will that not work?
Also can I provide mqtt username and password?
Because I do have that on my mqtt server.
Not exactly, but you can flash a ESP8266, many of us have done it, see my post here of the code I’m using:
Yes this is actually for Esp32 and will work only there. I have made a version for my other esp8266 based SmallTV as well, will post it later. It comes with a few quirks though and could use some optimisation in terms of display refresh.
Setting the user/pw should work like this:
# Example configuration entry
mqtt:
broker: <broker>
username: <user>
password: !secret mqtt_password
see MQTT Client Component - ESPHome - Smart Home Made Simple
st7789v driver has been deprecated for a while in favor of mipi_spi. This has been mentioned several times over the thread, but unfortunately it is too long to read and find the relevant post…
Just update your display section as follows, while keeping your pages/lambda code. You can also remove all external_components. Key there is the buffer_size, which is a new feature that no longe requires the whole picture to reside on ESP8266 RAM.
- id: my_display
platform: mipi_spi
model: ST7789V
spi_id: spihwd
dimensions:
height: 240
width: 240
offset_height: 0
offset_width: 0
buffer_size: 12.5%
invert_colors: true
dc_pin: GPIO00
reset_pin: GPIO02
color_depth: 16
update_interval: never
spi_mode: mode3
data_rate: 40000000
auto_clear_enabled: False
That did it, thanks!
This is the updated version of the yaml for the ESP8266 using the most adequate driver (Thanks to @lhartmann)
esphome:
name: smalltv
friendly_name: SmallTV
esp8266:
board: esp12e
# Enable logging
# logger:
# level: DEBUG
# WiFi configuration
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "SmallTV Fallback"
password: "secretPW"
captive_portal:
# OTA updates
ota:
- platform: esphome
password: !secret ota_password
# MQTT broker configuration (no user/password)
mqtt:
broker: <broker hostname>
port: 1883
on_json_message:
- topic: <topic>
then:
- lambda: |-
if (!x["items"].is<JsonArrayConst>()) return;
JsonArrayConst items = x["items"].as<JsonArrayConst>();
int count = items.size();
if (count > 10) count = 10;
id(item_count) = count;
for (int i = 0; i < count; i++) {
JsonObjectConst item = items[i].as<JsonObjectConst>();
std::string label = item["label"].as<std::string>();
std::string value = item["value"].as<std::string>();
std::string rgb = item["value_rgb"].as<std::string>();
id(item_labels)[i] = label;
id(item_values)[i] = value;
id(item_colors)[i] = rgb;
}
for (int i = count; i < 10; i++) {
id(item_labels)[i] = "";
id(item_values)[i] = "";
id(item_colors)[i] = "FFFFFF";
}
- component.update: my_display
# Global variables to store parsed data
globals:
- id: item_count
type: int
restore_value: no
initial_value: "0"
- id: item_labels
type: std::string[10]
restore_value: no
- id: item_values
type: std::string[10]
restore_value: no
- id: item_colors
type: std::string[10]
restore_value: no
# Fonts
font:
- file: "gfonts://Roboto"
id: font_header
size: 16
- file: "gfonts://Roboto"
id: font_label
size: 14
- file: "gfonts://Roboto"
id: font_value
size: 16
color:
- id: color_bg
hex: "0A0A1A"
- id: color_header_bg
hex: "1A1A2E"
- id: color_header_text
hex: "00BFFF"
- id: color_row_bg
hex: "16213E"
- id: color_row_border
hex: "0F3460"
- id: color_label_text
hex: "A0A0C0"
- id: color_default_value
hex: "00FF88"
output:
- platform: esp8266_pwm
pin: GPIO05
frequency: 20 Hz
id: pwm_output
light:
- platform: monochromatic
output: pwm_output
name: "Backlight"
spi:
clk_pin: GPIO14
mosi_pin: GPIO13
interface: hardware
id: spihwd
display:
- id: my_display
platform: mipi_spi
model: ST7789V
spi_id: spihwd
dimensions:
height: 240
width: 240
offset_height: 0
offset_width: 0
buffer_size: 12.5%
invert_colors: true
dc_pin: GPIO00
reset_pin: GPIO02
color_depth: 16
update_interval: never
spi_mode: mode3
data_rate: 40000000
auto_clear_enabled: False
lambda: |-
// it.filled_rectangle(0, 0, 240, 240, Color(255, 0, 0));
// it.printf(120, 120, id(font_label), Color(255, 255, 255), TextAlign::CENTER, "HELLO");
auto hex_to_color = [](const std::string &hex) -> Color {
uint32_t rgb = 0x00FF88;
if (hex.length() == 6) {
rgb = strtoul(hex.c_str(), nullptr, 16);
}
uint8_t r = (rgb >> 16) & 0xFF;
uint8_t g = (rgb >> 8) & 0xFF;
uint8_t b = rgb & 0xFF;
return Color(r, g, b);
};
int w = 240;
int y = 0;
int header_h = 25;
int row_h = 34;
// Background
it.filled_rectangle(0, 0, w, 240, id(color_bg));
// Header bar
it.filled_rectangle(0, 0, w, header_h, id(color_header_bg));
it.printf(w / 2, header_h / 2, id(font_header), id(color_header_text), TextAlign::CENTER, "AS20");
y = header_h;
int count = id(item_count);
if (count > 6) count = 6;
if (count == 0) {
it.printf(w / 2, y + 20, id(font_label), id(color_label_text), TextAlign::CENTER, "Waiting for data...");
}
for (int i = 0; i < count; i++) {
int row_y = y + i * row_h;
// Row background
it.filled_rectangle(0, row_y, w, row_h, id(color_row_bg));
// Bottom border
it.horizontal_line(0, row_y + row_h - 1, w, id(color_row_border));
// Label on left
it.printf(6, row_y + row_h / 2, id(font_label), id(color_label_text), TextAlign::CENTER_LEFT, "%s", id(item_labels)[i].c_str());
// Value on right with dynamic color
Color val_color = hex_to_color(id(item_colors)[i]);
it.printf(w - 5, row_y + row_h / 2, id(font_value), val_color, TextAlign::CENTER_RIGHT, "%s", id(item_values)[i].c_str());
}
As I understand, the base version (with ESP8266) doesn’t come with a button, only the screen, but the pro version (with ESP32) has a button (or maybe some capacitive sensor, whatever). Is this correct?
Also, if someone knows the answer to these, would be awesome:
Does the base version have free pins so I could add in my own button to it?
What about the pro version?
Can the pro version’s button be used via ESPHome/Home Assistant just fine?
Would anyone know how to modify this so that the sunset would be displayed in 12 hour instead of 24 hour time? Or can you point me to a better place to ask?
# Text sensor for time
time:
- platform: sntp
id: sntp_time
servers:
- 0.pool.ntp.org
- 1.pool.ntp.org
sun:
latitude: !secret home_latitude
longitude: !secret home_longitude
id: sun_position
text_sensor:
- platform: sun
name: "Sunrise"
type: sunrise
id: sun_sunrise
- platform: sun
name: "Sunset"
type: sunset
id: sun_sunset
display:
- platform: mipi_spi
model: st7789v
spi_id: spihwd
dimensions:
height: 240
width: 240
offset_height: 0
offset_width: 0
invert_colors: true
dc_pin: GPIO00
reset_pin: GPIO02
#backlight_pin: GPIO25
color_depth: 8
#update_interval: never
update_interval: 10s
id: disp
spi_mode: mode3
lambda: |-
// Display time and temperature
const auto RED = Color(255, 0, 0);
const auto GREEN = Color(0, 255, 0);
const auto BLUE = Color(0, 0, 255);
const auto WHITE = Color(255, 255, 255);
// Draw time (centered)
it.strftime(120, 20, id(font1), WHITE, TextAlign::CENTER, "%H:%M", id(sntp_time).now());
it.strftime(120, 60, id(font1), GREEN, TextAlign::CENTER, "%l:%M %p", id(sntp_time).now());
it.strftime(120, 100, id(font2), RED, TextAlign::CENTER, "%a", id(sntp_time).now());
it.strftime(120, 130, id(font2), RED, TextAlign::CENTER, "%Y/%m/%d", id(sntp_time).now());
it.printf(0, 160, id(font3), BLUE, TextAlign::LEFT, "Next Rise: %s", id(sun_sunrise).state.c_str());
it.printf(0, 185, id(font3), BLUE, TextAlign::LEFT, "Next Set: %s", id(sun_sunset).state.c_str());
# Fonts (add to your ESPHome project)
font:
- file: "gfonts://Roboto"
id: font1
size: 48
- file: "gfonts://Roboto"
id: font2
size: 33
- file: "gfonts://Roboto"
id: font3
size: 25
Yeah, I use it to turn pages (tap) and perform actions (hold).
esp32_touch:
# setup_mode: true
binary_sensor:
- platform: esp32_touch
name: "Touch Pad"
disabled_by_default: True
internal: True
pin: GPIO32
threshold: 1500
id: my_touch_pad
on_state:
then:
- component.update: lcd_display
on_release:
then:
- script.execute: "config_page_timeout"
on_click:
- min_length: 10ms
max_length: 500ms
then:
- if:
condition:
- lambda: 'return id(back_light).current_values.get_brightness() < .5;'
then:
- script.execute: adjust_brightness_with_timeout
- if:
condition:
- lambda: 'return id(back_light).current_values.get_brightness() >= .5;'
then:
- logger.log: "Displaying next page..."
- display.page.show_next: lcd_display
- component.update: lcd_display
on_press:
then:
- delay: 1s
- if:
condition:
- for:
condition:
- binary_sensor.is_on: my_touch_pad
time: 1s
then:
- if:
condition:
- display.is_displaying_page: page_curtain
then:
- logger.log: "Toggling curtains..."
- homeassistant.action:
action: cover.toggle
data:
entity_id: cover.curtains
Hey! Just came here to say thanks for this topic. You folks are GOAT!
I had one of these on my junk drawer for ages. Now i have a screen that shows some network stuff.
I even wrote an article about it. It contains my working setup and some more data related to this.
Let me know what you think: I just wanted a desk clock I accidentally built a Home Assistant dashboard - DEV Community
Thanks for that wright up!
It is a very nice summary with many details I was unaware of. A very thorough and welcome addition to the knowledge being gained here
I do not know if anyone would be interested in this but I think the GeekMagic display is cool a bit big, looking like an old school TV set. I’ve been looking for a 3D printable case for it but have not found one. So I decided to create my own. It’s as basic as it get. I can upload the file if someone wants it. What’s the best place to upload in your opinion?
Printables.com, thingiverse.com or similar. These sites are specialized for printed things.
I have the same model. I have succesfully integrated it to ESPhome, but I cannot get the display working. What is your display config in the yaml?
I’m new to this (I’ve only experimented with a Lilygo S3) and in my enthusiasm, I ordered the Pro instead of the S3 version. So to be able to flash it with a basic ESPHome firmware, I need to connect GND with GPIO0 and then connect the device with the USB-cable to my pc? (Sorry, I’m afraid of damaging my pc
) Do I need an USB-UART adapter for this or is there any other way to do this?
If you are new, I’d recommend starting with a simple modern ESPHome config like mine here
, and then adding some LVGL.
You can solder headers to the GPIOs if you want to enable modern partition features like boot loader rollback, but if you are new, try just uploading the firmware to the stock Web UI in Legacy format (which you can get in ESPHome Device Builder! That worked for me when I got mine late last year!
Ah thanks, I will take a look this week!
I got the display up and running after a few false starts with my YAML. Works great now!
Hello !
To anyone having an (apprently cheaper) GeekMagic Smart Weather clock with ESP8266 (and no touch sensitive button), using a FTDI adapter I was able to have it work fine using this code :
# ============================================================
# ESPHome base configuration for GeekMagic SmallTV
# (ESP-12F / ESP8266 + ST7789V 240x240 display, no CS pin)
#
# Tested with ESPHome 2026.5.0
#
# Hardware specifications:
# - MCU : ESP-12F (ESP8266MOD)
# - Display : ST7789V 240x240, SPI, no CS pin (tied to GND)
# - GPIO14 : SPI CLK
# - GPIO13 : SPI MOSI
# - GPIO00 : DC (Data/Command)
# - GPIO02 : RST (Display Reset)
# - GPIO05 : Backlight (PWM, inverted)
#
# Key settings required to work:
# - spi_mode: mode3 (mandatory without CS pin)
# - color_depth: 8bit (mandatory on ESP8266, limited RAM)
# - buffer_size: 12% (minimum accepted, prevents RAM crashes)
# - invert_colors: true (correct colors on this model)
# ============================================================
esphome:
name: geekmagic-smalltv
esp8266:
board: esp12e
wifi:
min_auth_mode: WPA2
networks:
- ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "GeekMagic-Fallback"
password: "fallback123"
logger:
api:
encryption:
key: !secret api_key
ota:
- platform: esphome
password: !secret ota_password
captive_portal:
# --- Backlight ---
spi:
clk_pin: GPIO14
mosi_pin: GPIO13
output:
- platform: esp8266_pwm
pin: GPIO05
frequency: 1000 Hz
id: pwm_backlight
inverted: true
light:
- platform: monochromatic
output: pwm_backlight
name: "Backlight"
id: retroeclairage
restore_mode: ALWAYS_ON
default_transition_length: 1s
# --- Display ---
display:
- platform: mipi_spi
model: ST7789V
dc_pin: GPIO00
reset_pin: GPIO02
dimensions:
width: 240
height: 240
color_depth: 8bit
spi_mode: mode3
invert_colors: true
buffer_size: 12%
update_interval: never
id: disp
lambda: |-
it.fill(Color(0, 0, 0)); // Black background
On top of that, I was able to have it display a clock, and the status of 2 entities.
I also set up a timeout to turn backlight off 90 seconds after the last movement (to prevent pixel burn-in)
About your comment on turning off backlight to prevent burn in, turning off the backlight doesn't actually help (meaningfully). The backlight just makes the image visible. The image is still displayed the whole time, whether the backlight is on or off. Read this from the ESPHome LVGL cookbook on LCD burn-in prevention:
But sure, I guess turning off the backlight also helps for the lifetime of the backlight itself, but I have no idea if that's something one should be worried about anyway.
I also think your 90 seconds timeout sounds extremely conservative, but if it doesn't bother you and you're aiming for an extremely long lifetime of the LCD, fair enough.