I noticed there’s a new device in the M5Stack series: M5Stack Tab5. It looks like a great solution for a wall-mounted control panel for HomeAssistant. Does anyone already have experience with it? Looking at the specs, would it be hard to make it work with ESPHome?
It would be a great device! Any news?
I think the most difficult thing is to get the two esp32s to talk to each other so that WIFI works.
They are working on it. Not everything is working yet as far as supported platforms but they have a board for espressif’s evaluation board. It talks to the C6 via SDIO.
It has the potential to be a tablet and voice assistant with LVGL. Someone got Quake running on a P4 demo board so it’s a huge upgrade.
Is there a beta version yet of ESPHome that will work on the M5Stack Tab5 ? I understand the challenge is creating code for both ESP32-P4 and ESP32-C6 (WiFi/BT) on the board.
Really appreciate you all working on this.
they have an example configuration on their devices page or on github. I compiled the example config they have on the page and it compiled and seems to be working!
WIP, will post the GitHub link once I clean up and tweak some things. The P4 is WAY faster then the S3, not sure if it’s the 32MB of PSRAM but super responsive with animation while being a pretty decent voice assistant. Not full duplex, only half duplex so stop word doesn’t work. I added a stop button in the screen and I can either tap the Darth Vader icon to start the voice assistant or hold it and let go to force it to stop listening (helpful with TV or music). Also had weird issues get the wake sound to work. The I2S bus keeps locking up so I gave up on that and moved on to LVGL
hello, i have some problems with i2c and touchscreen, can someone help me please? can you share your yaml please?
Here is my YAML and 2 images used, most are mdi icons. I’ve added some gradient colors and animations also but still learning. Also, I started out with the documented YAML on the ESPHome devices website which will get you up and running with the sample card LVGL.
thanks a lot, thanks for your time, i think i have a i2c problem
esphome and esphome-dev does not working for me
[C][component:173]: Setup template.number took 1ms
[18:59:37.774][D][number:033]: 'screen brightness': Sending state 8.000000
[18:59:37.774][D][light:089]: 'Display Backlight' Setting:
[18:59:37.775][D][light:095]: Color mode:
[18:59:37.775][D][light:102]: State: ON
[18:59:37.776][D][light:077]: Brightness: 3%
[18:59:37.776][D][light:140]: Transition length: 0.2s
[18:59:37.777][C][component:173]: Setup template.number took 3ms
[18:59:37.778][C][component:173]: Setup ledc.output took 0ms
[18:59:37.778][D][light:089]: 'Display Backlight' Setting:
[18:59:37.779][D][light:077]: Brightness: 50%
[18:59:37.780][C][component:173]: Setup light took 1ms
[18:59:37.780][C][component:173]: Setup psram took 0ms
[18:59:37.781][C][component:173]: Setup ina226.sensor took 1ms
[18:59:37.784][C][component:173]: Setup touchscreen took 3ms
[18:59:37.835][D][esp-idf:000]: E (1907) i2c.master: I2C hardware NACK detected
[18:59:37.836][D][esp-idf:000]: E (1908) i2c.master: I2C transaction unexpected nack detected
[18:59:37.837][D][esp-idf:000]: E (1909) i2c.master: s_i2c_synchronous_transaction(945): I2C transaction failed
[18:59:37.838][D][esp-idf:000]: E (1909) i2c.master: i2c_master_execute_defined_operations(1366): I2C transaction failed
[18:59:37.838][D][esp-idf:000]: E (1910) i2c.master: I2C hardware NACK detected
[18:59:37.839][D][esp-idf:000]: E (1911) i2c.master: I2C transaction unexpected nack detected
[18:59:37.840][D][esp-idf:000]: E (1912) i2c.master: s_i2c_synchronous_transaction(945): I2C transaction failed
[18:59:37.841][D][esp-idf:000]: E (1913) i2c.master: i2c_master_execute_defined_operations(1366): I2C transaction failed
[18:59:37.842][E][component:314]: touchscreen set Error flag: Communication failed
[18:59:37.842][E][component:211]: touchscreen was marked as failed
[18:59:37.914][D][sensor:131]: 'Battery Percentage': Sending state nan % with 1 decimals of accuracy
[18:59:38.782][D][sensor:131]: 'Battery Voltage': Sending state 8.20375 V with 2 decimals of accuracy
[18:59:38.783][D][sensor:131]: 'Battery Current': Sending state 0.00050 A with 3 decimals of accuracy
[19:00:37.912][D][sensor:131]: 'Battery Percentage': Sending state 98.82288 % with 1 decimals of accuracy
[19:00:38.780][D][sensor:131]: 'Battery Voltage': Sending state 8.20375 V with 2 decimals of accuracy
[19:00:38.782][D][sensor:131]: 'Battery Current': Sending state 0.00050 A with 3 decimals of accuracy
If the default config below doesn’t work then it really seems like an i2c issue, probably hardware if the below doesn’t work because it’s posted on esphomes site. Might be worth trying to “clean build files” and compiling from scratch if you haven’t already. Sometimes things get messed up in the build directory that can produce some interesting errors during compile.
I am having this same issue. It appears that the display driver was changed as of 10/14 per the note in the documentation.
Starting from October 14, 2025, the Tab5’s original independent display driver ILI9881C and touch driver GT911 will be replaced by the integrated display‑touch driver ST7123. Some early firmware builds may not run properly. The latest versions of M5Unified and M5GFX have already been adapted for compatibility with this new screen driver, and older programs can be recompiled using the latest M5Unified and M5GFX to achieve proper compatibility.
Saw that, there is a PR for the hardware changes by m5stack. See the post below for the PR YAML that needs to be added for it work due to the hardware changes. Just need to point to 2 external components. YAML below although spacing isn’t correct, will edit later on desktop because mobile is being a headache.
https://www.reddit.com/r/homeassistant/s/oZQyjzdnnJ
external_components:
source:
github://pr#12075
components:
refresh: 1h
source:
github://pr#12074
[st7123]
components: [mipi_dsi]
refresh: 1h
See above post, fixed via PR and external component. Confirmed working by 2 people on Reddit.
thanks for your help, i can confirm via PR the i2c is compiled now.
but now gives the mipi_dsi problems? sorry for my english and i am no programmer ![]()
Compiling .pioenvs/zentraleinheit02/src/esphome/components/mipi_dsi/mipi_dsi.cpp.o
src/esphome/components/mipi_dsi/mipi_dsi.cpp: In member function 'void esphome::mipi_dsi::MIPI_DSI::smark_failed(const esphome::LogString*, esp_err_t)':
src/esphome/components/mipi_dsi/mipi_dsi.cpp:17:20: error: no matching function for call to 'esphome::mipi_dsi::MIPI_DSI::mark_failed(const esphome::LogString*&)'
17 | this->mark_failed(message);
| ~~~~~~~~~~~~~~~~~^~~~~~~~~
In file included from src/esphome/components/mipi_dsi/mipi_dsi.h:8,
from src/esphome/components/mipi_dsi/mipi_dsi.cpp:3:
src/esphome/core/component.h:158:16: note: candidate: 'virtual void esphome::Component::mark_failed()'
158 | virtual void mark_failed();
| ^~~~~~~~~~~
src/esphome/core/component.h:158:16: note: candidate expects 0 arguments, 1 provided
src/esphome/core/component.h:160:8: note: candidate: 'void esphome::Component::mark_failed(const char*)'
160 | void mark_failed(const char *message) {
| ^~~~~~~~~~~
src/esphome/core/component.h:160:32: note: no known conversion for argument 1 from 'const esphome::LogString*' to 'const char*'
160 | void mark_failed(const char *message) {
| ~~~~~~~~~~~~^~~~~~~
src/esphome/components/mipi_dsi/mipi_dsi.cpp: In member function 'virtual void esphome::mipi_dsi::MIPI_DSI::setup()':
src/esphome/components/mipi_dsi/mipi_dsi.cpp:102:24: error: no matching function for call to 'esphome::mipi_dsi::MIPI_DSI::mark_failed(const esphome::LogString*)'
102 | this->mark_failed(LOG_STR("Malformed init sequence"));
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/esphome/core/component.h:158:16: note: candidate: 'virtual void esphome::Component::mark_failed()'
158 | virtual void mark_failed();
Which ESPHOME version are you using? regular or dev?
Have you tried cleaning build files under the 3 dot options for the device in ESPHome builder? Things can get messed up and throw errors on occasion because of possible files that exist. ESPHome tries to compile only what is needed for faster minor updates. If that doesn’t work post your config either on here or GitHub, mainly the top two off the ESPHome device page for the M5Tab with the updated changes per the external components PR above.
thank you again, yes i have always clean the build files.
i have config a new device, with this yaml
esphome:
name: zentraleinheit01
friendly_name: zentraleinheit01
esp32:
variant: esp32p4
flash_size: 16MB
framework:
type: esp-idf
advanced:
enable_idf_experimental_features: true
#external_components:
# - source: github://pr#12075
# components: [st7123]
# refresh: 1h
# - source: github://pr#12074
# components: [mipi_dsi]
# refresh: 1h
# Enable logging
logger:
hardware_uart: USB_SERIAL_JTAG
# Enable Home Assistant API
api:
encryption:
key: ""
ota:
- platform: esphome
password: "a8d10c6a7a5288df734cd2d18cc32f7c"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
manual_ip:
static_ip: 10.0.0.70
gateway: 0.0.0.0
subnet: 255.255.255.0
network:
enable_ipv6: false
# Enable fallback hotspot (captive portal) in case wifi connection fails
#ap:
# ssid: "Zentraleinheit01"
# password: "HowBkg7ogQom"
esp32_hosted:
variant: esp32c6
active_high: true
clk_pin: GPIO12
cmd_pin: GPIO13
d0_pin: GPIO11
d1_pin: GPIO10
d2_pin: GPIO9
d3_pin: GPIO8
reset_pin: GPIO15
slot: 1
psram:
mode: hex
speed: 200MHz
i2c:
- id: bsp_bus
sda: GPIO31
scl: GPIO32
frequency: 400kHz
pi4ioe5v6408:
- id: pi4ioe1
address: 0x43
# 0: O - wifi_antenna_int_ext
# 1: O - speaker_enable
# 2: O - external_5v_power
# 3: NC
# 4: O - lcd reset
# 5: O - touch panel reset
# 6: O - camera reset
# 7: I - headphone detect
- id: pi4ioe2
address: 0x44
# 0: O - wifi_power
# 1: NC
# 2: NC
# 3: O - usb_5v_power
# 4: O - poweroff pulse
# 5: O - quick charge enable (inverted)
# 6: I - charging status
# 7: O - charge enable
switch:
- platform: gpio
id: wifi_power
name: "WiFi Power"
pin:
pi4ioe5v6408: pi4ioe2
number: 0
restore_mode: ALWAYS_ON
- platform: gpio
id: usb_5v_power
name: "USB Power"
pin:
pi4ioe5v6408: pi4ioe2
number: 3
- platform: gpio
id: quick_charge
name: "Quick Charge"
pin:
pi4ioe5v6408: pi4ioe2
number: 5
inverted: true
- platform: gpio
id: charge_enable
name: "Charge Enable"
pin:
pi4ioe5v6408: pi4ioe2
number: 7
- platform: gpio
id: wifi_antenna_int_ext
pin:
pi4ioe5v6408: pi4ioe1
number: 0
- platform: gpio
id: speaker_enable
name: "Speaker Enable"
pin:
pi4ioe5v6408: pi4ioe1
number: 1
restore_mode: ALWAYS_ON
- platform: gpio
id: external_5v_power
name: "External 5V Power"
pin:
pi4ioe5v6408: pi4ioe1
number: 2
binary_sensor:
- platform: gpio
id: charging
name: "Charging Status"
pin:
pi4ioe5v6408: pi4ioe2
number: 6
mode: INPUT_PULLDOWN
- platform: gpio
id: headphone_detect
name: "Headphone Detect"
pin:
pi4ioe5v6408: pi4ioe1
number: 7
select:
- platform: template
id: wifi_antenna_select
name: "WiFi Antenna"
options:
- "Internal"
- "External"
optimistic: true
on_value:
- if:
condition:
lambda: return i == 0;
then:
- switch.turn_off: wifi_antenna_int_ext
else:
- switch.turn_on: wifi_antenna_int_ext
sensor:
- platform: ina226
address: 0x41
adc_averaging: 16
max_current: 8.192A
shunt_resistance: 0.005ohm
bus_voltage:
id: battery_voltage
name: "Battery Voltage"
current:
id: battery_current
name: "Battery Current"
# Positive means discharging
# Negative means charging
# Tab5 built-in battery discharges from full (8.23 V) to shutdown threshold (6.0 V)
- platform: template
name: "Battery Percentage"
lambda: |-
float voltage = id(battery_voltage).state;
// Adjust these values based on your battery's actual min/max voltage
float min_voltage = 6.0; // Discharged voltage
float max_voltage = 8.23; // Fully charged voltage
float percentage = (voltage - min_voltage) / (max_voltage - min_voltage) * 100.0;
if (percentage > 100.0) return 100.0;
if (percentage < 0.0) return 0.0;
return percentage;
update_interval: 60s
unit_of_measurement: "%"
accuracy_decimals: 1
touchscreen:
- platform: gt911
interrupt_pin: GPIO23
update_interval: never
reset_pin:
pi4ioe5v6408: pi4ioe1
number: 5
calibration:
x_min: 0
x_max: 720
y_min: 0
y_max: 1280
id: touch
esp_ldo:
- voltage: 2.5V
channel: 3
display:
- platform: mipi_dsi
dimensions:
height: 1280
width: 720
model: M5Stack-Tab5
reset_pin:
pi4ioe5v6408: pi4ioe1
number: 4
show_test_card: true
output:
- platform: ledc
pin: GPIO22
id: backlight_pwm
frequency: 1000Hz
light:
- platform: monochromatic
output: backlight_pwm
name: "Display Backlight"
id: backlight
restore_mode: RESTORE_DEFAULT_ON
default_transition_length: 250ms
lvgl:
byte_order: little_endian
captive_portal:
this is including the two external components
src/esphome/components/mipi_dsi/mipi_dsi.cpp: In member function 'bool esphome::mipi_dsi::MIPI_DSI::check_buffer_()':
src/esphome/components/mipi_dsi/mipi_dsi.cpp:225:22: error: no matching function for call to 'esphome::mipi_dsi::MIPI_DSI::mark_failed(const esphome::LogString*)'
225 | this->mark_failed(LOG_STR("Could not allocate buffer for display!"));
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/esphome/core/component.h:158:16: note: candidate: 'virtual void esphome::Component::mark_failed()'
158 | virtual void mark_failed();
| ^~~~~~~~~~~
src/esphome/core/component.h:158:16: note: candidate expects 0 arguments, 1 provided
src/esphome/core/component.h:160:8: note: candidate: 'void esphome::Component::mark_failed(const char*)'
160 | void mark_failed(const char *message) {
| ^~~~~~~~~~~
src/esphome/core/component.h:160:32: note: no known conversion for argument 1 from 'const esphome::LogString*' to 'const char*'
160 | void mark_failed(const char *message) {
| ~~~~~~~~~~~~^~~~~~~
*** [.pioenvs/zentraleinheit01/src/esphome/components/mipi_dsi/mipi_dsi.cpp.o] Error 1
========================= [FAILED] Took 146.13 seconds =========================
and this is without external components
[05:54:20.145][C][component:173]: Setup light took 3ms
[05:54:20.145][C][component:173]: Setup psram took 0ms
[05:54:20.148][C][component:173]: Setup ina226.sensor took 2ms
[05:54:20.150][C][component:173]: Setup touchscreen took 2ms
[05:54:20.206][D][esp-idf:000]: E (221) i2c.master: I2C hardware NACK detected
[05:54:20.207][D][esp-idf:000]: E (222) i2c.master: I2C transaction unexpected nack detected
[05:54:20.208][D][esp-idf:000]: E (222) i2c.master: s_i2c_synchronous_transaction(945): I2C transaction failed
[05:54:20.209][D][esp-idf:000]: E (223) i2c.master: i2c_master_execute_defined_operations(1401): I2C transaction failed
[05:54:20.209][D][esp-idf:000]: E (224) i2c.master: I2C hardware NACK detected
[05:54:20.210][D][esp-idf:000]: E (225) i2c.master: I2C transaction unexpected nack detected
[05:54:20.211][D][esp-idf:000]: E (225) i2c.master: s_i2c_synchronous_transaction(945): I2C transaction failed
[05:54:20.212][D][esp-idf:000]: E (226) i2c.master: i2c_master_execute_defined_operations(1401): I2C transaction failed
Ah, looking at the PR they left out something on the Reddit thead. Change model under display to “model: M5STACK-TAB5-V2” per the example in the link below. The display driver wasn’t actually changed, only the touch chip so display model needed a new name
yes i have found also now the two models, but with
model: M5STACK-TAB5-V2
i might have a hardware defect? i dont know ![]()
|-- lvgl @ 8.4.0
Compiling .pioenvs/zentraleinheit01/src/esphome/components/mipi_dsi/mipi_dsi.cpp.o
src/esphome/components/mipi_dsi/mipi_dsi.cpp: In member function 'void esphome::mipi_dsi::MIPI_DSI::smark_failed(const esphome::LogString*, esp_err_t)':
src/esphome/components/mipi_dsi/mipi_dsi.cpp:17:20: error: no matching function for call to 'esphome::mipi_dsi::MIPI_DSI::mark_failed(const esphome::LogString*&)'
17 | this->mark_failed(message);
| ~~~~~~~~~~~~~~~~~^~~~~~~~~
In file included from src/esphome/components/mipi_dsi/mipi_dsi.h:8,
from src/esphome/components/mipi_dsi/mipi_dsi.cpp:3:
src/esphome/core/component.h:158:16: note: candidate: 'virtual void esphome::Component::mark_failed()'
158 | virtual void mark_failed();
| ^~~~~~~~~~~
src/esphome/core/component.h:158:16: note: candidate expects 0 arguments, 1 provided
src/esphome/core/component.h:160:8: note: candidate: 'void esphome::Component::mark_failed(const char*)'
160 | void mark_failed(const char *message) {
| ^~~~~~~~~~~
src/esphome/core/component.h:160:32: note: no known conversion for argument 1 from 'const esphome::LogString*' to 'const char*'
160 | void mark_failed(const char *message) {
| ~~~~~~~~~~~~^~~~~~~
src/esphome/components/mipi_dsi/mipi_dsi.cpp: In member function 'virtual void esphome::mipi_dsi::MIPI_DSI::setup()':
src/esphome/components/mipi_dsi/mipi_dsi.cpp:102:24: error: no matching function for call to 'esphome::mipi_dsi::MIPI_DSI::mark_failed(const esphome::LogString*)'
102 | this->mark_failed(LOG_STR("Malformed init sequence"));
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/esphome/core/component.h:158:16: note: candidate: 'virtual void esphome::Component::mark_failed()'
158 | virtual void mark_failed();
| ^~~~~~~~~~~
src/esphome/core/component.h:158:16: note: candidate expects 0 arguments, 1 provided
src/esphome/core/component.h:160:8: note: candidate: 'void esphome::Component::mark_failed(const char*)'
160 | void mark_failed(const char *message) {
| ^~~~~~~~~~~
src/esphome/core/component.h:160:32: note: no known conversion for argument 1 from 'const esphome::LogString*' to 'const char*'
160 | void mark_failed(const char *message) {
| ~~~~~~~~~~~~^~~~~~~
src/esphome/components/mipi_dsi/mipi_dsi.cpp:113:26: error: no matching function for call to 'esphome::mipi_dsi::MIPI_DSI::mark_failed(const esphome::LogString*)'
113 | this->mark_failed(LOG_STR("Malformed init sequence"));
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/esphome/core/component.h:158:16: note: candidate: 'virtual void esphome::Component::mark_failed()'
158 | virtual void mark_failed();
| ^~~~~~~~~~~
src/esphome/core/component.h:158:16: note: candidate expects 0 arguments, 1 provided
src/esphome/core/component.h:160:8: note: candidate: 'void esphome::Component::mark_failed(const char*)'
160 | void mark_failed(const char *message) {
| ^~~~~~~~~~~
src/esphome/core/component.h:160:32: note: no known conversion for argument 1 from 'const esphome::LogString*' to 'const char*'
160 | void mark_failed(const char *message) {
| ~~~~~~~~~~~~^~~~~~~
src/esphome/components/mipi_dsi/mipi_dsi.cpp: In member function 'bool esphome::mipi_dsi::MIPI_DSI::check_buffer_()':
src/esphome/components/mipi_dsi/mipi_dsi.cpp:225:22: error: no matching function for call to 'esphome::mipi_dsi::MIPI_DSI::mark_failed(const esphome::LogString*)'
225 | this->mark_failed(LOG_STR("Could not allocate buffer for display!"));
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/esphome/core/component.h:158:16: note: candidate: 'virtual void esphome::Component::mark_failed()'
158 | virtual void mark_failed();
| ^~~~~~~~~~~
src/esphome/core/component.h:158:16: note: candidate expects 0 arguments, 1 provided
src/esphome/core/component.h:160:8: note: candidate: 'void esphome::Component::mark_failed(const char*)'
160 | void mark_failed(const char *message) {
| ^~~~~~~~~~~
src/esphome/core/component.h:160:32: note: no known conversion for argument 1 from 'const esphome::LogString*' to 'const char*'
160 | void mark_failed(const char *message) {
| ~~~~~~~~~~~~^~~~~~~
*** [.pioenvs/zentraleinheit01/src/esphome/components/mipi_dsi/mipi_dsi.cpp.o] Error 1
========================== [FAILED] Took 9.49 seconds ==========================
In the YAML you posted above the external components are commented out. Are they still commented out? If so remove the comments, they need to be in there.
yes, sorry i commented out also, it does not work for me
![]()




