So I wanted to be able to quick prototype a UI for the ESPHome LVGL integration (as recompiling and flashing for each change takes some time).
I have never used the host integration with LVGL before and it turns out it isn't that easy toi get running. So i thought I would write it down - and well this is the gist of it.
(if lazy look at the included docker-compose.yaml, Dockerfile - i stripped my config down to the bare necessities the simple bare config runs - esphome-host-lvgl-example.yaml - requires xquartz)
I started out with a minimum host: SDL LVGL config (whats in a name):
# esphome-host-lvgl-example.yaml
# Host mode
host:
# Enable logging
logger:
level: DEBUG
# ============================================================
#
# Define the SDL display for LVGL
#
#
# Define the SDL display (required for LVGL rendering)
#
display:
- platform: sdl
id: sdl_display
dimensions:
# Configure the display size
width: 320
height: 240
#
# Define the SDL virtual touchscreen (required for LVGL interaction)
#
touchscreen:
- platform: sdl
id: sdl_touchscreen
display: sdl_display
# ============================================================
#
# LVGL Minimal Config; Displays a Basic Widget Showcase
#
lvgl:
But ran into issues; as I run ESPHome in docker on MacOS. The perfect storm it turns out.
The first hurdle was that currently the official docker image (v2026.2.4 as of time of writing) does not include the required libs for SDL (though the official esphome docs mention them):
apt install libsdl2-dev libsodium-dev build-essential gitSo the first step was to add the required libs to the docker image. The build-essential and git are not required (i checked) so that is why it deviates from what is officially proposed (which is probably due to them making the docker image). So we just need to add the sdl and sodium libs:
# Dockerfile
FROM ghcr.io/esphome/esphome:2026.2.4
RUN apt update && apt install -y \
libsodium-dev \
libsdl2-dev \
&& rm -rf /var/lib/apt/lists/*As I actually already run the original image using docker-compose I just needed to change my config to use the Dockerfile instaead of the original image.
# docker-compose.yaml
services:
esphome:
#image: ghcr.io/esphome/esphome:2026.2.4
build:
dockerfile: ./Dockerfile
# ...Ok gets past that error. But now another error:
XDG_RUNTIME_DIR is invalid or not set in the environment
Head scratch; I know this from days gone by; probably need a DISPLAY variable to run on, but what is it on macos?
So, yeah, grabs the favorite LLM and ask it; and after a lot and a lot and a lot or trial and error and repeating (slightly different solutions):
As MacOS does not run X11 (or compat) you dont have a display to pass. And so, so far the only workable way to get it working is to install something called XQuartz (an X11 server for your macos host). So I unhappily installed that (I dont like installing things). Make sure after installing you disable all the wm integrations (as you probably dont want it -- see also troubleshooting).
Ensure XQuartz -> Settings -> Security -> Allow connections from network clients is enabled. Then to actually allow access it is required to add the client host to the X11 server auth.
Run these once:
defaults write org.xquartz.X11 enable_iglx -bool true
# disable some wm stuff that annoys me
defaults write org.xquartz.X11 wm_ffm -bool false
defaults write org.xquartz.X11 wm_active -bool false
So every time you relogin/reboot you need to do this before you can actually use the X11 server (via DISPLAY):
# allows localhost access to the X11 server
xhost +localhostNow I can pass the DISPLAY.
environment:
- "DISPLAY=host.docker.internal:0"Ok, so this gets much further and actually now the linux env in the container can run GUI applications on your host. But does LVGL work now?
No, but after looking at the docs and a lot of tweaking and LLM bashing I got it working with the following extra env:
# Forces SDL to use X11 instead of trying Wayland
SDL_VIDEODRIVER=x11
# Tells SDL not to expect a hardware GPU (common in Docker)
SDL_RENDER_DRIVER=software
# Prevents SDL from trying to use a physical keyboard/mouse driver
SDL_MOUSE_RELATIVE=0
# Prevents SDL from trying to use direct rendering
LIBGL_ALWAYS_INDIRECT=1I now get the LVGL window and it is interactive!
Now to clean up my configs and get that xhost command hooked to run on docker-compose-up (so i dont need to add it via login/profile or some such - it is a secutiry thing)
| Error | Possible fix |
|---|---|
| Any "Authorization Required" error | X11 has security levels. The Docker container is not allowed access. Running xhost +localhost (or xhost +[Your IP]) to whitelist the incoming connection. |
| swrast / libGL errors | The container tried to use "Direct Rendering" (hardware GPU access), which doesn't work through an X11 tunnel. It needed "Indirect Rendering." Setting enable_iglx -bool true in XQuartz and adding LIBGL_ALWAYS_INDIRECT=1 to your Docker environment. |
| If you ever find the window "freezing" or not opening after a few hours of development | Check XQuartz: It sometimes goes to sleep. Reset Permissions: Just run the xhost command again. |
| XQuartz interferes with alt tabbing and refocusing mimimized windows | Yea hi know it sucks if this happens on your host. The only way to sort of gegt them windows back is via command+tab -tab +option -command -option or via the application's window options if they have them. WIP. |
This is the gist of a reasonable usable integration: See the full configuration in the files. at yr own risk.
p.s.