New boards Wishlist

NM-TV-154/NMiner 'Yellow Cube' display

BSwitchblade88Suggested this wish Β·

I have successfully got some basic outputs via pure ESPhome on a handful of pages including a couple of dynamic updating values and a history graph (stored on device, which loses history on reset).

I'd love to be able to add cards/pages via Tessera for card consistency across devices, however given there is no touchscreen and only a single capacitive button it might be a little out of scope. The resolution is also a bit smaller than a CYD, though not unworkably so.

Using the button to tab across pages is all that I'd expect, though there's obviously capacity for double-tap and long-press inputs if that was beneficial. Given the 'Override YAML' option already present in Tessera then that would be an easy onramp for mapping the button input.

Hardware testing

We often do not have this board ourselves. Community testing helps establish what actually works. A successful report is evidence for the maintainer to review, not an automatic compatibility claim.

Board details & configuration
Model
NM-TV-154
Chip, RAM and flash
ESP32-D0; unknown RAM and flash
Display and touch
240x240 ST7789V with PWM backlight. No touchscreen; single capactitive button
Already tried
Supplied YAML is functional with ESPhome 2026.10 Supplies 4 pages including live updating values from Home Assistant and a graph card.
Configuration status
partial
View shared configuration
esphome:
  name: nmtv
  friendly_name: NMTV Yellow Cube 

esp32:
  variant: esp32
  framework:
    type: esp-idf
    advanced: 
      minimum_chip_revision: "3.1"

logger:
    level: DEBUG
api:
  encryption:
    key: !secret_api_key

ota:
  - platform: esphome

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

web_server:
  port: 80
  version: 3

# LCD power enable
switch:
  - platform: gpio
    pin:
      number: GPIO21
      inverted: true
    id: lcd_power
    restore_mode: ALWAYS_ON

output:
  - platform: ledc
    pin: GPIO19
    inverted: true
    id: backlight_pwm

light:
  - platform: monochromatic
    output: backlight_pwm
    name: "Display Backlight"
    restore_mode: ALWAYS_ON   

spi:
  clk_pin: GPIO14
  mosi_pin: GPIO13



sensor:
  # --- Page 1: Inputs (kWh) ---
  - platform: homeassistant
    id: grid_daily_energy
    entity_id: sensor.meross_smart_energy_monitor_grid_combined_today_energy
    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

  - platform: homeassistant
    id: solar1_energy
    entity_id: sensor.ecoflow_solar_1_integral
    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

  - platform: homeassistant
    id: solar2_energy
    entity_id: sensor.ecoflow_solar_2_integral
    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

  # --- Page 2: Ecoflow (kWh) ---
  - platform: homeassistant
    id: ecoflow_power_in
    entity_id: sensor.ecoflow_combined_power_in_integral
    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

  - platform: homeassistant
    id: ecoflow_power_out
    entity_id: sensor.ecoflow_combined_power_out_integral
    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

  # --- Page 3: Current Usage (converted W -> kW) ---
  - platform: homeassistant
    id: grid_power
    entity_id: sensor.meross_smart_energy_monitor_grid_combined_power
    unit_of_measurement: "kW"
    device_class: power
    state_class: measurement
    filters:
      - multiply: 0.001

  - platform: homeassistant
    id: ev_charger_power
    entity_id: sensor.ev_charger_ble_proxy_ev_charge_wattage
    unit_of_measurement: "kW"
    device_class: power
    state_class: measurement
    filters:
      - multiply: 0.001

  - platform: homeassistant
    id: ef_output_power
    entity_id: sensor.ef_r350308_ac_output_power
    unit_of_measurement: "kW"
    device_class: power
    state_class: measurement
    filters:
      - multiply: 0.001
        
  - platform: homeassistant
    id: ef_battery
    entity_id: sensor.ef_r350308_main_battery_level
    unit_of_measurement: "%"
    device_class: battery
    state_class: measurement

  - platform: homeassistant
    id: jk_battery
    entity_id: sensor.sunroom_jk_bms_c6_state_of_charge
    unit_of_measurement: "%"
    device_class: battery
    state_class: measurement


        
color:
  - id: ha_cyan
    red: 1%
    green: 66%
    blue: 96%
  - id: color_white
    red: 100%
    green: 100%
    blue: 100%
  - id: color_amber
    red: 100%
    green: 60%
    blue: 0%

font:
  - file: "gfonts://Roboto"
    id: font_title
    size: 28
  - file: "gfonts://Roboto"
    id: font_label
    size: 20
  - file: "gfonts://Roboto"
    id: font_value
    size: 26

graph:
  - id: battery_graph
    duration: 12h
    width: 220
    height: 130
    x_grid: 2h
    y_grid: 20
    min_value: 0
    max_value: 100
    border: true
    traces:
      - sensor: ef_battery
        line_type: SOLID
        line_thickness: 4
        color: ha_cyan
      - sensor: jk_battery
        line_type: SOLID
        line_thickness: 4
        color: color_amber

    
display:
  - platform: mipi_spi
    id: my_display
    model: ST7789V
    cs_pin: GPIO15
    dc_pin: GPIO2
    dimensions: 240x240
    invert_colors: true      
    update_interval: 5s
    pages:
      - id: page_inputs
        lambda: |-
          it.fill(Color::BLACK);
          it.print(120, 8, id(font_title), id(ha_cyan), TextAlign::TOP_CENTER, "Inputs");

          it.print(10, 65, id(font_label), id(color_white), TextAlign::TOP_LEFT, "Grid");
          it.printf(230, 60, id(font_value), id(color_white), TextAlign::TOP_RIGHT, "%.2f kWh", id(grid_daily_energy).state);

          it.print(10, 125, id(font_label), id(color_white), TextAlign::TOP_LEFT, "Solar 1");
          it.printf(230, 120, id(font_value), id(color_white), TextAlign::TOP_RIGHT, "%.2f kWh", id(solar1_energy).state);

          it.print(10, 185, id(font_label), id(color_white), TextAlign::TOP_LEFT, "Solar 2");
          it.printf(230, 180, id(font_value), id(color_white), TextAlign::TOP_RIGHT, "%.2f kWh", id(solar2_energy).state);

      - id: page_ecoflow
        lambda: |-
          it.fill(Color::BLACK);
          it.print(120, 8, id(font_title), id(ha_cyan), TextAlign::TOP_CENTER, "Ecoflow");

          it.print(10, 90, id(font_label), id(color_white), TextAlign::TOP_LEFT, "Power In");
          it.printf(230, 85, id(font_value), id(color_white), TextAlign::TOP_RIGHT, "%.2f kWh", id(ecoflow_power_in).state);

          it.print(10, 150, id(font_label), id(color_white), TextAlign::TOP_LEFT, "Power Out");
          it.printf(230, 145, id(font_value), id(color_white), TextAlign::TOP_RIGHT, "%.2f kWh", id(ecoflow_power_out).state);

      - id: page_current
        lambda: |-
          it.fill(Color::BLACK);
          it.print(120, 8, id(font_title), id(ha_cyan), TextAlign::TOP_CENTER, "Current Usage");

          it.print(10, 65, id(font_label), id(color_white), TextAlign::TOP_LEFT, "Grid");
          it.printf(230, 60, id(font_value), id(color_white), TextAlign::TOP_RIGHT, "%.2f kW", id(grid_power).state);

          it.print(10, 125, id(font_label), id(color_white), TextAlign::TOP_LEFT, "EV Charger");
          it.printf(230, 120, id(font_value), id(color_white), TextAlign::TOP_RIGHT, "%.2f kW", id(ev_charger_power).state);

          it.print(10, 185, id(font_label), id(color_white), TextAlign::TOP_LEFT, "Ecoflow Out");
          it.printf(230, 180, id(font_value), id(color_white), TextAlign::TOP_RIGHT, "%.2f kW", id(ef_output_power).state);
      - id: page_battery
        lambda: |-
          it.fill(Color::BLACK);
          it.print(120, 8, id(font_title), id(ha_cyan), TextAlign::TOP_CENTER, "Battery (12h)");

          it.graph(10, 45, id(battery_graph));

          // Legend + current values
          it.filled_rectangle(15, 195, 10, 10, id(ha_cyan));
          it.printf(30, 192, id(font_label), id(color_white), TextAlign::TOP_LEFT, "EF %.0f%%", id(ef_battery).state);

          it.filled_rectangle(130, 195, 10, 10, id(color_amber));
          it.printf(145, 192, id(font_label), id(color_white), TextAlign::TOP_LEFT, "JK %.0f%%", id(jk_battery).state);
          
      
esp32_touch:
  setup_mode: false

binary_sensor:
  - platform: esp32_touch
    name: "Touch Button"
    pin: GPIO32
    threshold: 1500
    on_press:
      - display.page.show_next: my_display
      - component.update: my_display

1 owner has volunteered to test.

Sign in to volunteer

Discussion 0

Add a comment

Start the conversation

Share an example, ask a question or explain how you would use this.

Add your thoughts, a screenshot or a useful link.

Markdown & basic HTML
Paste or drop images Β· URLs on their own line become previews0 / 10,000
Create your account to join in

We need a verified email address to reach you about your contribution. Your address stays private.

Continue with GitHub

Your draft stays in this tab. Return here after verification.