Installing ESPhome on GEEKMAGIC Smart Weather Clock (smalltv/pro)

#1 - good choice :wink: we have a #1 and a #3 :wink:

Anyone here had luck with the S3 version (marked ESP32-S3-WROOM)? I’ve tried the config below, and the backlight is working, but are otherwise probably not using correct GPIOs (?):

esphome:
  name: minitv
  friendly_name: MiniTV

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino

# ...

font:
  - file: "gfonts://Roboto"
    id: roboto_20
    size: 20

spi:
  clk_pin: GPIO12
  mosi_pin: GPIO11

output:
  - platform: ledc
    pin: GPIO14
    inverted: true
    id: backlightdim

light:
  - platform: monochromatic
    output: backlightdim
    name: "Backlight"
    restore_mode: RESTORE_DEFAULT_ON

time:
  - platform: homeassistant
    id: home_time
    timezone: Europe/Amsterdam

#display:
#  - platform: st7789v
#    model: Custom
#    width: 128
#    height: 128
#    offset_width: 1
#    offset_height: 2
#    dc_pin: GPIO2
#    reset_pin: GPIO4
#    id: disp
#    rotation: 180
#    lambda: |-
#      it.strftime(0, 0, id(roboto_20), TextAlign::TOP_LEFT, "%H:%M", id(home_time).now());
#      it.line(0, 50, 127, 50);

display:
  - platform: ili9xxx
    model: st7789v
    dc_pin: GPIO2 # 7?
    reset_pin: GPIO4 # 6?
    invert_colors: false
    show_test_card: true
    dimensions:
      height: 240
      width: 240
    lambda: |-
      it.strftime(0, 0, id(roboto_20), TextAlign::TOP_LEFT, "%H:%M", id(home_time).now());
      it.line(0, 50, 127, 50);

Hi AndrƩ,
when I try to use your code, it got this error message - what am I doing wrong?

Make sure that your ā€œdisplay:ā€ settings are correct.

SvenRhein, your lvgl: section is missing a widget with an id of ā€œboot_screenā€. If you don’t have that section, you can safely remove that ā€œon_bootā€ section from your esphome: section.

1 Like

My Geekmagic s3 is in. Been reading for a hour now, no idea on how to put EspHome on it.

There is no binary on GitHub - GeekMagicClock/GeekMagic-S3: GeekMagic S3 project for fun. for the s3 version, and no explianation on how to build it.

Please help! I can flash it with Web - ESPHome but I cannot find the bin file for it…

Hi guys.
I got my GeekMagic SmallTV PRO :slight_smile:
Thanks to this post I was able to start my implementation, but at the moment I’m having issues with the component ā€œonline_imageā€.
The idea is to load a screenshot of my doorbell and show it on the SmallTv.

I’m facing problems with the heap fragmentation, online_image can’t get a big enough memory chunk to load the image.

Does anyone knows if the PRO version has PSRAM and how to enable it?

Would the S3 version be better for this?

I will leave here my current implementation that might be a good starting point for someone :slight_smile:

esphome:
  name: esphome-web-8af3ac
  friendly_name: SmallTV Pro
  min_version: 2024.11.0
  name_add_mac_suffix: false
  platformio_options:
    build_flags: "-DBOARD_HAS_PSRAM"
#    board_build.arduino.memory_type: qio_opi
  on_boot:
    - delay: 5s
    - lvgl.widget.hide: boot_screen
    
psram:

esp32:
  board: esp32dev
  framework:
    type: arduino
    
    

# Enable logging
logger:
  level: debug

# enable web server
web_server:
  version: 3

# Enable Home Assistant API
api:
  encryption:
    key: "8/lX1IaTM5wyJf1dcot5gXjO2dZAcEhtWfRiZMohHhU="

ota:
  - platform: esphome

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  on_connect:
    - component.update: my_online_image

# Define a PWM output on the ESP32
output:
  - platform: ledc
    pin: GPIO25
    inverted: True
    id: backlight_pwm

# Define a monochromatic, dimmable light for the backlight
light:
  - platform: monochromatic
    output: backlight_pwm
    name: "Display Backlight"
    id: back_light
    restore_mode: ALWAYS_ON


esp32_touch:
  # setup_mode: true


image:
  - file: https://esphome.io/_static/favicon-512x512.png
    id: boot_logo
    resize: 200x200
    type: RGB565
    transparency: alpha_channel

  - file: http://192.168.1.112:8123/local/doorbell/snapshot_small.jpg
    type: rgb565
    id: doorbel_snapshot
    resize: 240x240

http_request:
  id: httpRequest
  verify_ssl: false

online_image:
  - id: my_online_image
    url: "http://192.168.1.112:8123/local/doorbell/snapshot.jpg"
    format: JPEG
    type: BINARY
    #resize: 200x200
    on_download_finished:
      - logger.log: "------IMAGE DOWNLOADED----"
      - lvgl.image.update:
          id: doorbell_img
          src: my_online_image

# Button for testing the image loading
button:
  - platform: template
    name: "TEST BUTTON"
    id: my_button1
    icon: "mdi:emoticon-outline"
    on_press:
      - logger.log: "TEST Button pressed"
      - component.update: my_online_image


font:
  - file: "fonts/Roboto.ttf"
    id: roboto_24
    size: 24
  - file: "fonts/materialdesignicons-webfont.ttf"
    id: icons_40
    size: 40
    bpp: 4
    glyphs: [
      "\U000F10C3", #Termometer 
      "\U000F058E", #water-percent 
      "\U000F059D"#Wind 
      ]



binary_sensor:
  - platform: status
    name: Status sensor
  - platform: esp32_touch
    name: "Touch Button"
    pin: GPIO32
    threshold: 1250
    id: touch_button
    filters:
      - delayed_on: 50ms
    on_multi_click:
      - timing:
          - ON for at most 0.5s
          - OFF for at most 0.5s
          - ON for at most 0.5s
        then:
          # Double tap - go to previous page
          - logger.log: "Double tap detected - going to previous page"
          - lvgl.page.previous:
      - timing:
          - ON for at most 0.5s
        then:
          - if:
              condition: lvgl.is_paused
              then:
                - logger.log: "LVGL resuming"
                - lvgl.resume:
                - lvgl.widget.redraw:
                - light.turn_on: back_light
          # Single tap - go to next page
          - logger.log: "Single tap detected - going to next page"
          - lvgl.page.next:

spi:
  clk_pin: GPIO18
  mosi_pin: GPIO23
  interface: hardware
  id: spihwd

display:
  - platform: ili9xxx
    id: lcd_display
    model: st7789v
    spi_id: spihwd
    data_rate: 40MHz
    dc_pin: GPIO02
    reset_pin: GPIO04
    spi_mode: MODE3
    dimensions:
      width: 240
      height: 240
      offset_height: 0
      offset_width: 0
    invert_colors: true
    auto_clear_enabled: false
    update_interval: never

number:
  - platform: template
    name: LVGL Screen timeout
    optimistic: true
    id: display_timeout
    unit_of_measurement: "s"
    initial_value: 45
    restore_value: true
    min_value: 10
    max_value: 180
    step: 5
    mode: box

lvgl:
  buffer_size: 25%
  on_idle:
    timeout: !lambda "return (id(display_timeout).state * 1000);"
    then:
      - logger.log: "LVGL is idle"
      - light.turn_off: back_light
      - lvgl.pause:
  theme:
    label:
      text_font: roboto_24 # set all your labels to use your custom defined font
    button:
      bg_color: 0x2F8CD8
      bg_grad_color: 0x005782
      bg_grad_dir: VER
      bg_opa: COVER
      border_color: 0x0077b3
      border_width: 1
      text_color: 0xFFFFFF
      pressed: # set some button colors to be different in pressed state
        bg_color: 0x006699
        bg_grad_color: 0x00334d
      checked: # set some button colors to be different in checked state
        bg_color: 0x1d5f96
        bg_grad_color: 0x03324A
        text_color: 0xfff300
    buttonmatrix:
      bg_opa: TRANSP
      border_color: 0x0077b3
      border_width: 0
      text_color: 0xFFFFFF
      pad_all: 0
      items: # set all your buttonmatrix buttons to use your custom defined styles and font
        bg_color: 0x2F8CD8
        bg_grad_color: 0x005782
        bg_grad_dir: VER
        bg_opa: COVER
        border_color: 0x0077b3
        border_width: 1
        text_color: 0xFFFFFF
        text_font: roboto_24
        pressed:
          bg_color: 0x006699
          bg_grad_color: 0x00334d
        checked:
          bg_color: 0x1d5f96
          bg_grad_color: 0x03324A
          text_color: 0x005580
    switch:
      bg_color: 0xC0C0C0
      bg_grad_color: 0xb0b0b0
      bg_grad_dir: VER
      bg_opa: COVER
      checked:
        bg_color: 0x1d5f96
        bg_grad_color: 0x03324A
        bg_grad_dir: VER
        bg_opa: COVER
      knob:
        bg_color: 0xFFFFFF
        bg_grad_color: 0xC0C0C0
        bg_grad_dir: VER
        bg_opa: COVER
    slider:
      border_width: 1
      border_opa: 15%
      bg_color: 0xcccaca
      bg_opa: 15%
      indicator:
        bg_color: 0x1d5f96
        bg_grad_color: 0x03324A
        bg_grad_dir: VER
        bg_opa: COVER
      knob:
        bg_color: 0x2F8CD8
        bg_grad_color: 0x005782
        bg_grad_dir: VER
        bg_opa: COVER
        border_color: 0x0077b3
        border_width: 1
        text_color: 0xFFFFFF
  style_definitions:
    - id: header_footer
      bg_color: 0x2F8CD8
      bg_grad_color: 0x005782
      bg_grad_dir: VER
      bg_opa: COVER
      border_opa: TRANSP
      radius: 0
      pad_all: 0
      pad_row: 0
      pad_column: 0
      border_color: 0x0077b3
      text_color: 0xFFFFFF
      width: 100%
      height: 30
  top_layer:
    widgets:
      - obj:
          id: boot_screen
          x: 0
          y: 0
          width: 100%
          height: 100%
          bg_color: 0xffffff
          bg_opa: COVER
          radius: 0
          pad_all: 0
          border_width: 0
          widgets:
            - image:
                align: CENTER
                src: boot_logo
                y: -40
            - spinner:
                align: CENTER
                y: 75
                height: 50
                width: 50
                spin_time: 1s
                arc_length: 60deg
                arc_width: 8
                indicator:
                  arc_color: 0x18bcf2
                  arc_width: 8
          on_press:
            - lvgl.widget.hide: boot_screen
  pages:
    # Page 1: Solar and Home Battery
    - id: solar_page
      widgets:
        - obj:
            align: TOP_MID
            styles: header_footer
            widgets:
              - label:
                  text: "Solar"
                  align: CENTER
                  text_align: CENTER
                  text_color: 0xFFFFFF
        #solar power
        - obj:
            height: 180
            width: 180
            align: CENTER
            bg_color: 0xFFFFFF
            border_width: 0
            pad_all: 4
            widgets:
              - meter:
                  height: 100%
                  width: 100%
                  border_width: 0
                  bg_opa: TRANSP
                  align: CENTER
                  scales:
                    - range_from: 0
                      range_to: 3200
                      angle_range: 180 # sets the total angle to 180 = starts mid left and ends mid right
                      ticks:
                        count: 0
                      indicators:
                        - line:
                            id: val_needle_solar
                            width: 4
                            r_mod: 12 # sets line length by this much difference from the scale default radius
                            value: -2
                        - arc: # first half of the scale background
                            color: 0xF5F542
                            opa: 50%
                            r_mod: 10 # radius difference from the scale default radius
                            width: 20
                            start_value: 0
                            end_value: 3200
              - obj: # to cover the middle part of meter indicator line
                  height: 120
                  width: 120
                  radius: 60
                  align: CENTER
                  border_width: 0
                  bg_color: 0xFFFFFF
                  pad_all: 0
              - label: # gauge numeric indicator
                  id: val_text_solar
                  text_font: montserrat_30
                  align: CENTER
                  y: -5
                  text: "0"
              - label: # lower range indicator
                  text_font: montserrat_18
                  align: CENTER
                  y: 8
                  x: -90
                  text: "-10"
              - label: # higher range indicator
                  text_font: montserrat_18
                  align: CENTER
                  y: 8
                  x: 90
                  text: "3.2k"
     
        # Home Battery    
        - label:
            id: battery_label
            text: "0%"
            x: 20
            y: 160
            width: 200
            text_align: CENTER
        - bar:
            id: battery_bar
            x: 20
            y: 190
            width: 200
            height: 20
            min_value: 0
            max_value: 100
            value: 0


    # Page 2: weather_page
    - id: weather_page
      widgets:
        - obj:
            align: TOP_MID
            styles: header_footer
            widgets:
              - label:
                  text: "Weather"
                  align: CENTER
                  text_align: CENTER
                  text_color: 0xFFFFFF
            # Temperature
        - obj:
            x: 0
            y: 60
            width: 240  # Full screen width
            height: 50
            border_width: 0
            bg_opa: 0  # Transparent background
            widgets:
              - label:
                  id: temp_outside_icon
                  text_font: icons_40
                  text: "\U000F10C3"
                  align: left_mid
                  x: 10  # Left margin
              - label:
                  id: temp_outside_label
                  text: "0.0°C"
                  text_font: montserrat_40
                  align: left_mid
                  x: 60  # Position to the right of the icon
        
        # Humidity row
        - obj:
            x: 0
            y: 120  # Below temperature row
            width: 240  # Full screen width
            height: 50
            border_width: 0
            bg_opa: 0  # Transparent background
            widgets:
              - label:
                  id: humidity_icon
                  text_font: icons_40
                  text: "\U000F058E"  # Water percent icon
                  align: left_mid
                  x: 10  # Left margin
              - label:
                  id: humidity_outside_label
                  text: "0%"
                  text_font: montserrat_40
                  align: left_mid
                  x: 60  # Position to the right of the icon
   




    # Page 3: Doorbel
    - id: doorbel_page
      widgets:
        - obj:
            align: TOP_MID
            styles: header_footer
            widgets:
              - label:
                  text: "Doorbel"
                  align: CENTER
                  text_align: CENTER
                  text_color: 0xFFFFFF
            # Temperature
        - obj:
            x: 0
            y: 0
            width: 240  # Full screen width
            height: 240
            border_width: 0
            bg_opa: 0  # Transparent background
            widgets:
              - image:
                  id: doorbell_img
                  align: CENTER
                  src: my_online_image
                  #src: doorbel_snapshot
                  
       




sensor:
  # DC Power
  - platform: homeassistant
    id: total_dc_power
    unit_of_measurement: "Watt"    
    entity_id: sensor.pv1_power
    on_value:
      - lvgl.indicator.update:
          id: val_needle_solar
          value: !lambda return x;
      - lvgl.label.update:
          id: val_text_solar
          text:
            format: "%.0f"
            args: [ 'x' ]



  # Home Battery
  - platform: homeassistant
    id: evcc_battery_soc
    entity_id: sensor.battery_state_of_charge
    unit_of_measurement: "%"
    on_value:
      - lvgl.label.update:
          id: battery_label
          text: !lambda |-
            return ("Battery: " + to_string(static_cast<int>(x)) + "%").c_str();
      - lvgl.bar.update:
          id: battery_bar
          value: !lambda |-
            return x;

  # Temp Outside
  - platform: homeassistant
    id: temp_outside
    entity_id: sensor.gw1100a_outdoor_temperature
    unit_of_measurement: "C"
    on_value:
      - lvgl.label.update:
          id: temp_outside_label
          text: !lambda |-
            char buffer[16];
            sprintf(buffer, "%.1f°C", x);  // One decimal place
            return buffer;

  # Hum Outside
  - platform: homeassistant
    id: hum_outside
    entity_id: sensor.gw1100a_humidity
    unit_of_measurement: "%"
    on_value:
      - lvgl.label.update:
          id: humidity_outside_label
          text: !lambda |-
            char buffer[16];
            sprintf(buffer, "%.1f°", x);  // One decimal place
            return buffer;



1 Like

Wow. I’m really happy with what I achieved through your help here and using ChatGPT. I created something that improves my quality of life.

Since my daily commute by train is rather unreliable, I need to check the departure times every morning. But I don’t want to use my phone for that while I’m already in a hurry.

So I set up the SmallTV Pro to display the next four trains, their estimated time of departure and their delay. For convenience I also made a second page showing the trains in the other direction.

It works like charm:

Feel free to ask if you want to know any details.

3 Likes

Just want to say thanks to everyone! With your shared stuff I mixed up my first output on a geekmagic pro! Its a very basic output and it just shows 3 sensors.

  1. Current available solarpower (unused)
  2. Current power from landline
  3. Home Battery in %

Also you can tap on the touch area and the backlight will cycle through different brightness states.

I had some struggle to get esp home running in the first place, because web esphome was not able to connect, although it showed the device online. Finally I was able to flash a base image (legacy bin file) through the web interface of the stock firmware, which I quickly generated in homeassistant esphome. Now I can update wireless through homeassistant.

In case someone want to reuse my current progress, here is the code. I will now try to make it look nicer and make more use of the touch interface.

esphome:
  name: geektv
  friendly_name: GeekTV
  min_version: 2024.11.0
  name_add_mac_suffix: false
  on_boot:
    then:
      - light.turn_on:
          id: back_light
          brightness: 1.0
  #  - delay: 5s

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:
  baud_rate: 0

# enable web server
web_server:
  version: 3

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

ota:
  - platform: esphome
    password: ""

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Geektv Fallback Hotspot"
    password: ""

captive_portal:


debug:
  update_interval: 5s

text_sensor:
  - platform: debug
    device:
      name: "Device Info"
    reset_reason:
      name: "Reset Reason"



# Define a PWM output on the ESP32
output:
  - platform: ledc
    pin: GPIO25
    inverted: True
    id: backlight_pwm

# Define a monochromatic, dimmable light for the backlight
light:
  - platform: monochromatic
    output: backlight_pwm
    name: "Display Backlight"
    id: back_light
    restore_mode: ALWAYS_ON
    on_turn_on:
      - light.turn_on:
          id: back_light
          brightness: 1.0  # Set initial brightness to 100% on power up

esp32_touch:
  # setup_mode: true

binary_sensor:
  - platform: esp32_touch
    name: "Touch Button"
    pin: GPIO32
    threshold: 1250
    id: gp32
    filters:
      # Small filter, to debounce the spurious events.
      - delayed_on: 10ms
      - delayed_off: 10ms
    on_click:
    - min_length: 10ms
      max_length: 500ms
      # Short touch to cycle through brightnesses
      then:
        - lambda: |-
            int current_brightness = id(back_light).current_values.get_brightness() * 100;
            current_brightness += 18;
            if (current_brightness > 100) {
              current_brightness = 5;
            }
            // Store the brightness value for later use
            id(current_brightness_variable).publish_state(current_brightness);
        - light.turn_on:
            id: back_light
            brightness: !lambda 'return id(current_brightness_variable).state / 100.0;'
        - logger.log: 
            level: info
            format: "Touch ON"
    - min_length: 500ms
      max_length: 2000ms
      then:
        - logger.log: "Long Touch"

spi:
  clk_pin: GPIO18
  mosi_pin: GPIO23
  interface: hardware
  id: spihwd

display:
  - platform: ili9xxx
    id: lcd_display
    model: st7789v
    spi_id: spihwd
    data_rate: 40MHz
    dc_pin: GPIO02
    reset_pin: GPIO04
    spi_mode: MODE3
    dimensions:
      width: 240
      height: 240
      offset_height: 0
      offset_width: 0
    invert_colors: true
    auto_clear_enabled: false
    update_interval: never

lvgl:

  log_level: INFO
  color_depth: 16
  bg_color: 0
  border_width: 0
  outline_width: 0
  #shadow_width: 0
  #text_font: unscii_16
  #align: center
  style_definitions:
    - id: font_style
      text_color: 0xFFFFFF
      bg_color: 0
      bg_opa: TRANSP
    - id: details_style
      text_font: MONTSERRAT_16
      text_color: 0xFFFFFF
      bg_color: 0
      bg_opa: TRANSP

  buffer_size: 25%
  widgets:
    - label:
        id: powerverschenkt_label
        text: "?"
        x: 35 
        y: 20
        #width: 100
        #text_align: CENTER
        styles: font_style
        text_font: MONTSERRAT_30 # override font size
        text_color: 0x00ff00

    - label:
        id: netzstrom_label
        text: "?"
        x: 35 
        y: 60
        #width: 100
        #text_align: CENTER
        styles: font_style
        text_font: MONTSERRAT_30 # override font size
        text_color: 0xff0000
 
    - label:
        id: battery_label
        text: "?"
        x: 35
        y: 100
        #width: 100
        text_color: 0xffffff
        #text_align: CENTER
        styles: font_style
        text_font: MONTSERRAT_30 # override font size
        
    - bar:
        id: battery_bar
        x: 120
        y: 120
        width: 90
        height: 6
        min_value: 0
        max_value: 100
        value: 0

    - image:
        src: icon_lightning
        #align: center
        image_recolor: 0x00ff00
        image_recolor_opa: 100% 
        y: 20
        x: 0

    - image:
        src: icon_transmission_tower
        #align: center
        image_recolor: 0xff0000
        image_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
        y: 60
        x: 0

    - image:
        src: battery_icon
        #align: center
        image_recolor: 0xffffff
        image_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
        y: 100
        x: 0

    - image:
        src: icon_home_assistant
        align: bottom_mid
        image_recolor: 0x838383
        image_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
        y: -10
        #x: 0

image:
  - file: mdi:battery-minus-variant
    id: battery_icon_minus
    resize: 35x35
    type: binary
  - file: mdi:battery
    id: battery_icon
    resize: 35x35
    type: binary
  - file: mdi:battery-plus-variant
    id: battery_icon_plus
    resize: 35x35
    type: binary
  - file: mdi:sun-wireless-outline
    id: icon_solar
    resize: 35x35
    type: binary
  - file: mdi:transmission-tower
    id: icon_transmission_tower
    resize: 35x35
    type: binary
  - file: mdi:lightning-bolt-circle
    id: icon_lightning
    resize: 35x35
    type: binary
  - file: mdi:home-assistant
    id: icon_home_assistant
    resize: 35x35
    type: binary

sensor:
  # DC Power
  - platform: homeassistant # or your actual sensor platform
    id: total_powerverschenkt
    unit_of_measurement: "Watt"    
    entity_id: sensor.zuruck_zum_netz_watt
    on_value:
      - lvgl.label.update:
          id: powerverschenkt_label
          text: !lambda |-
            return ("" + to_string(static_cast<int>(x)) + "W").c_str();

  # Forecast
  - platform: homeassistant # or your actual sensor platform
    id: total_netzstrom
    unit_of_measurement: "Watt" 
    entity_id: sensor.strom_vom_netz_watt
    on_value:
      - lvgl.label.update:
          id: netzstrom_label
          text: !lambda |-
            return ("" + to_string(static_cast<int>(x)) + "W").c_str();

  # Home Battery
  - platform: homeassistant
    id: battery_kepworth
    entity_id: sensor.kepworth_lifepo4_battery_soc
    unit_of_measurement: "%"
    on_value:
      - lvgl.label.update:
          id: battery_label
          text: !lambda |-
            return ("" + to_string(static_cast<int>(x)) + "%").c_str();
      - lvgl.bar.update:
          id: battery_bar
          value: !lambda |-
            return x;

  #- platform: uptime
  #  name: Uptime Sensor
  #  id: time_since_boot
  #  update_interval: 3s
  #  internal: True

  - platform: template
    id: current_brightness_variable
    name: "Current Brightness"
    unit_of_measurement: "%"
    accuracy_decimals: 0
    state_class: "measurement"


Update: Now cycle through brightness with touch button.

4 Likes

I like it - looks like a popular use case, showing PV data for the home.
I ordered 2 more now for 2 other rooms.

Ideas for improving mine is - showing also wether/which car is charging, time based brightness adjustment (night mode) + use the touch button for a 2nd weather page

with your help and your good examples I have one geekmagic clock up and running - I created a second one with a different api key… the clock is working but it does not update its data… anybody an idea? I copied the code from my working one - added this code to the second clock with a changed new api key…

a got it… I had forgotten to add the device in home assistant as an esphome device :slight_smile:

now both of them works like a charm

3 Likes

So… the Geekmagik-S3 LCD works with this yaml:

substitutions:
  name: "geekmagic-s3"
  friendly_name: "geekmagic s3 tv"
  comment: "Geekmagic S3 Crypto Miner Thingy"

esphome:
  name: $name
  comment: $comment
  platformio_options:
    board_build.arduino.memory_type: qio_opi
    board_build.flash_mode: dio
    board_upload.maximum_ram_size: 524288

esp32:
  board: esp32-s3-devkitc-1
  variant: esp32s3
  flash_size: 16MB
  partitions: 16MB.csv
  framework:
    type: esp-idf
    
psram:
  mode: octal
  speed: 80MHz

packages:
  wifi_ota_api: !include common/wifi_ota_api.yaml

captive_portal:

debug:
  update_interval: 5s

text_sensor:
  - platform: debug
    device:
      name: "Device Info"
    reset_reason:
      name: "Reset Reason"


esp32_touch:
  #setup_mode: True
  measurement_duration: 0.25ms

binary_sensor:
  - platform: esp32_touch
    name: "Touch Sensor"
    id: touch_pad
    pin: GPIO9
    threshold: 120000
##    filters:
##      # Small filter, to debounce the spurious events.
##      - delayed_on: 10ms
##      - delayed_off: 10ms
    on_click:
    - min_length: 10ms
      max_length: 500ms
      # Short touch to cycle through brightnesses
      then:
        - lambda: |-
            int current_brightness = id(back_light).current_values.get_brightness() * 100;
            current_brightness += 18;
            if (current_brightness > 100) {
              current_brightness = 5;
            }
            // Store the brightness value for later use
            id(current_brightness_variable).publish_state(current_brightness);
        - light.turn_on:
            id: back_light
            brightness: !lambda 'return id(current_brightness_variable).state / 100.0;'
        - logger.log: 
            level: info
            format: "Touch ON"
    - min_length: 500ms
      max_length: 2000ms
      then:
        - logger.log: "Long Touch"

spi:
  - id: spihw
    clk_pin: GPIO12
    mosi_pin: GPIO11

output:
  - platform: ledc
    pin: GPIO14
    inverted: true
    id: backlight_output

light:
  - platform: monochromatic
    output: backlight_output
    name: LCD Backlight
    id: back_light
    restore_mode: ALWAYS_ON
    #default_transition_length: 0s

display:
  - platform: ili9xxx
    id: lcd_display
    model: st7789v #gc9a01a
    spi_id: spihw
    #data_rate: 80MHz
    #cs_pin: GPIO1
    dc_pin: GPIO7
    reset_pin: GPIO6
    spi_mode: MODE3
    invert_colors: true
    dimensions:
      width: 240
      height: 240
    update_interval: never
    auto_clear_enabled: false

lvgl:

  log_level: INFO
  color_depth: 16
  bg_color: 0
  border_width: 0
  outline_width: 0
  #shadow_width: 0
  #text_font: unscii_16
  #align: center
  style_definitions:
    - id: font_style
      text_color: 0xFFFFFF
      bg_color: 0
      bg_opa: TRANSP
    - id: details_style
      text_font: MONTSERRAT_16
      text_color: 0xFFFFFF
      bg_color: 0
      bg_opa: TRANSP

  buffer_size: 25%
  widgets:
    - label:
        id: powerverschenkt_label
        text: "?"
        x: 35 
        y: 20
        #width: 100
        #text_align: CENTER
        styles: font_style
        text_font: MONTSERRAT_30 # override font size
        text_color: 0x00ff00

    - label:
        id: netzstrom_label
        text: "?"
        x: 35 
        y: 60
        #width: 100
        #text_align: CENTER
        styles: font_style
        text_font: MONTSERRAT_30 # override font size
        text_color: 0xff0000
 
    - label:
        id: battery_label
        text: "?"
        x: 35
        y: 100
        #width: 100
        text_color: 0xffffff
        #text_align: CENTER
        styles: font_style
        text_font: MONTSERRAT_30 # override font size
        
    - bar:
        id: battery_bar
        x: 120
        y: 120
        width: 90
        height: 6
        min_value: 0
        max_value: 100
        value: 0

    - image:
        src: icon_lightning
        #align: center
        image_recolor: 0x00ff00
        image_recolor_opa: 100% 
        y: 20
        x: 0

    - image:
        src: icon_transmission_tower
        #align: center
        image_recolor: 0xff0000
        image_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
        y: 60
        x: 0

    - image:
        src: battery_icon
        #align: center
        image_recolor: 0xffffff
        image_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
        y: 100
        x: 0

    - image:
        src: icon_home_assistant
        align: bottom_mid
        image_recolor: 0x838383
        image_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
        y: -10
        #x: 0

image:
  - file: mdi:battery-minus-variant
    id: battery_icon_minus
    resize: 35x35
    type: binary
  - file: mdi:battery
    id: battery_icon
    resize: 35x35
    type: binary
  - file: mdi:battery-plus-variant
    id: battery_icon_plus
    resize: 35x35
    type: binary
  - file: mdi:sun-wireless-outline
    id: icon_solar
    resize: 35x35
    type: binary
  - file: mdi:transmission-tower
    id: icon_transmission_tower
    resize: 35x35
    type: binary
  - file: mdi:lightning-bolt-circle
    id: icon_lightning
    resize: 35x35
    type: binary
  - file: mdi:home-assistant
    id: icon_home_assistant
    resize: 35x35
    type: binary

sensor:
  # get raw value from esp32_touch
##  - platform: template
##    name: "Raw touch value"
##    lambda: |-
##        return id(touch_pad).get_value();
##    update_interval: 3s

  # DC Power
  - platform: homeassistant # or your actual sensor platform
    id: total_powerverschenkt
    unit_of_measurement: "Watt"    
    entity_id: sensor.power_export
    on_value:
      - lvgl.label.update:
          id: powerverschenkt_label
          text: !lambda |-
            return ("" + to_string(static_cast<int>(x)) + "W").c_str();

  # Forecast
  - platform: homeassistant # or your actual sensor platform
    id: total_netzstrom
    unit_of_measurement: "Watt" 
    entity_id: sensor.power_import
    on_value:
      - lvgl.label.update:
          id: netzstrom_label
          text: !lambda |-
            return ("" + to_string(static_cast<int>(x)) + "W").c_str();

  # Home Battery
  - platform: homeassistant
    id: battery_kepworth
    entity_id: sensor.batteries_state_of_capacity
    unit_of_measurement: "%"
    on_value:
      - lvgl.label.update:
          id: battery_label
          text: !lambda |-
            return ("" + to_string(static_cast<int>(x)) + "%").c_str();
      - lvgl.bar.update:
          id: battery_bar
          value: !lambda |-
            return x;

  - platform: template
    id: current_brightness_variable
    name: "Current Brightness"
    unit_of_measurement: "%"
    accuracy_decimals: 0
    state_class: "measurement"

But I’m having a absolut horrible time and very little knowledge on how to get the touch sensor to work! I know its the right pin but I’m getting absolutely nothing from it! and it worked with the original code…
Can anyone share some insight on how to troubleshoot this??

edit: partitions: 16MB.csv is from original code and probably default…

edit2: got it!-) ā€œmeasurement_duration: 0.25msā€ did the trick

1 Like

Hello, I have a smalltv ultra (esp8266) and wanted to use it to show data from a photovoltaic inverter (sofar inverter connected via modbus over tcp). On the homeassistant panel everything is displaying live nicely, but the smalltv i can’t get it to do that, i don’t know yaml/esp well, i was using gpt chat. what can be fixed here?

Blockquote
display:

  • platform: st7789v
    model: ā€œCustomā€
    spi_id: spihwd
    height: 240
    width: 240
    offset_height: 0
    offset_width: 0
    dc_pin: GPIO00
    reset_pin: GPIO02
    eightbitcolor: True
    update_interval: 20s
    id: disp
    spi_mode: mode3
    lambda: |-
    it.fill(Color::BLACK);

    // Wiersz 1: MOC
    it.printf(10, 10, id(font_large), Color::WHITE, ā€œMOC:ā€);
    it.printf(110, 10, id(font_large), Color(255, 0, 0), ā€œ%.2f kWā€, id(moc_chwilowa).state);

    // Wiersz 2: DZIŚ
    it.printf(10, 55, id(font_large), Color::WHITE, ā€œDzis:ā€);
    it.printf(100, 55, id(font_large), Color(0, 255, 0), ā€œ%.2f kWhā€, id(prod_dzienna).state);

    // Wiersz 3: OGƓLNIE
    it.printf(60, 105, id(font_large), Color::WHITE, ā€œOgolnie:ā€);
    it.printf(60, 145, id(font_large), Color(0, 255, 255), ā€œ%.0f kWhā€, id(produkcja_total).state);

    // Wiersz 4: TEMPERATURA
    it.printf(15, 190, id(font_large), Color::WHITE, ā€œTemp:ā€);
    it.printf(125, 190, id(font_large), Color(255, 255, 0), ā€œ%.0f°Cā€, id(temperatura_falownika).state);

sensor:

  • platform: homeassistant
    id: moc_chwilowa
    entity_id: sensor.falownik_moc_chwilowa

  • platform: homeassistant
    id: prod_dzienna
    entity_id: sensor.falownik_produkcja

  • platform: homeassistant
    id: produkcja_total
    entity_id: sensor.produkcja_calkowita

  • platform: homeassistant
    id: temperatura_falownika
    entity_id: sensor.temperatura_falownika

font:

  • file: ā€œgfonts://Robotoā€
    id: font_large
    size: 36

  • file: ā€œgfonts://Robotoā€
    id: font_small
    size: 16

Did you also add the esphome node to home assistant via integrations? Because if you miss that step it can’t retrieve values from the sensors and would give the same result you’re seeing.

What do the esphome logs say? Do they properly show the returned values from home assistant? If so, then your lamda is wrong. If not, you are either not properly importing the sensors from HA, OR you may not be handling the data type properly (usually that results in compiling errors)

Thanks :smiley: its working now :smiley:

Is there any chance to make the screen more responsive? I set 10sec update interval. Now the value shows for 6 seconds, then the screen goes off for 3 seconds, and a new one appears with the updated value. The original soft showed the data very dynamically.