Home Assistant Container

Home Assistant Container has no app store. You run the same app as its own container next to Home Assistant, from a ready image; the ESPHome tools are in it. On Home Assistant OS you don't need this page: install the app instead.

Which route is yours ​

Your setupWhat to follow
Linux host, Home Assistant with network_mode: host (the standard Home Assistant Container setup)Install, then Open Tessera
Windows or macOS with Docker Desktop, or Home Assistant published with ports:Install steps 1 and 2, then Home Assistant on a bridge network
Synology NAS (Container Manager)Synology NAS

What you need ​

  • Home Assistant Container, and Docker with Compose on the same machine (amd64 or aarch64).
  • Nothing to build: Compose pulls a ready image from GitHub (ghcr.io/maxgramser/homeassistant_espscreen, for amd64 and arm64), the same app the Home Assistant app store offers. You don't need git, so it also works on a Synology NAS.
  • The ESPHome integration in Home Assistant. Tessera adds the screens to it by itself.
  • A Home Assistant account with administrator rights, to create an access token.

Install ​

  1. Create a folder, for example esp-screens, and save compose.yaml in it.

  2. Create an access token. In Home Assistant, open your profile, go to the Security tab, and under Long-lived access tokens choose Create token. Paste only the token into a new file named ha_token, next to compose.yaml. On Linux, make it readable for you only:

    sh
    chmod 600 ha_token

    On Docker Desktop, continue with Home Assistant on a bridge network now.

  3. Check two lines in compose.yaml:

    • HA_API: http://127.0.0.1:8123/api is right when Home Assistant runs on the same machine on port 8123. Keep /api at the end.
    • ./esphome:/config keeps the screens' ESPHome files in a new esphome folder. If you already use ESPHome Device Builder, put its folder here instead, so both see the same files.
  4. Start the container from the folder:

    sh
    docker compose up -d

    The first start downloads the image, which is based on the official ESPHome image. This takes a few minutes.

  5. Check that it runs:

    sh
    docker compose logs -f

    What you'll see: the line Home Assistant connected once the token works. Press Ctrl+C to stop following the log. After about a minute, docker ps shows (healthy) next to esp-screens.

Open Tessera ​

The page has no login of its own, so it only listens on 127.0.0.1:8099 of the Docker host and answers nothing else. Don't make port 8099 reachable from your network.

  1. Install hass_ingress from HACS.

  2. Add this to configuration.yaml:

    yaml
    ingress:
      tessera:
        title: Tessera
        icon: mdi:view-grid
        require_admin: true
        url: http://127.0.0.1:8099
  3. Restart Home Assistant.

What you'll see: Tessera in the sidebar. Home Assistant handles the login, just like the app panel on Home Assistant OS.

Through an SSH tunnel ​

From your own computer:

sh
ssh -L 8099:127.0.0.1:8099 you@docker-host

Then open http://localhost:8099. A screen's card offers Open Devices & services when Tessera can't add the screen to Home Assistant by itself. That button only works in the sidebar panel; here, open Home Assistant yourself.

Home Assistant on a bridge network ​

Use this when Home Assistant does not use network_mode: host but publishes its ports under ports:. That is the usual setup with Docker Desktop on Windows and macOS, where "host" means Docker's own Linux VM and not your computer.

Without these steps the sidebar panel shows 502: Bad Gateway: inside the Home Assistant container, 127.0.0.1 is Home Assistant itself, not Tessera. The fix is to let Tessera share the network of the Home Assistant container, so 127.0.0.1 means the same in both.

  1. Move the esp-screens service from the downloaded compose.yaml into the compose file that already holds Home Assistant. Copy the secrets: block at the bottom along with it, and put ha_token next to that file.

  2. Change the two services like this. Put the service name of Home Assistant after service::

    yaml
    services:
      homeassistant:
        # ... your existing settings ...
        ports:
          # ... your existing ports ...
          - 8098:8098                    # camera images for the screens
    
      esp-screens:
        # ... image, restart, init, secrets, volumes and healthcheck stay as they are ...
        network_mode: "service:homeassistant"   # replaces network_mode: host
        depends_on:
          - homeassistant
        environment:
          SCREEN_DEV: "1"
          HA_API: http://127.0.0.1:8123/api     # Home Assistant in the shared network, see the https note below
          HA_TOKEN_FILE: /run/secrets/ha_token
          ESPHOME_CONFIG: /config
          SCREEN_DATA: /data
          SCREEN_CAMERA_URL: http://192.168.1.20:8098   # your computer's address on the home network

    Home Assistant on https only? Then http://127.0.0.1:8123 doesn't answer, and https://127.0.0.1:8123 fails the certificate check. Point HA_API at an http address that reaches Home Assistant, such as a reverse proxy in front of it. On Docker Desktop, http://host.docker.internal:<port>/api reaches a port your computer publishes.

  3. Start both:

    sh
    docker compose up -d
  4. Check that Home Assistant reaches the app. Replace homeassistant with the name of your Home Assistant container (docker ps shows it):

    sh
    docker exec homeassistant curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8099/

    What you'll see: 200 means the panel works. 000 means the two containers don't share a network yet.

  5. Set up the sidebar panel as in Open Tessera. The configuration stays the same.

Good to know:

  • Updating Home Assistant recreates its container and takes the shared network away. Run docker compose up -d again afterwards, so the Tessera container is recreated too.
  • Camera images: your computer's firewall has to let the screens in on port 8098 (Windows Firewall on Windows).
  • USB: Docker Desktop passes no USB ports to containers. Plug the screen into your computer and install it from the browser, as in Installing screens.

Opening the panel this way is confirmed on Docker Desktop for Windows with WSL 2. Camera images and updates over Wi-Fi have not been tested on Docker Desktop yet. If you try them, please report back in an issue.

Synology NAS ​

The ready image is what makes a Synology NAS work: Container Manager has no git and doesn't need to build anything.

  1. In File Station, create a folder for the app, for example docker/esp-screens.
  2. Put compose.yaml and your ha_token file in it, as in Install steps 1 to 3.
  3. In Container Manager, open Project, choose Create, pick that folder and use its existing compose.yaml.
  4. Start the project. Container Manager pulls the image and starts the app.

Then open the panel as in Open Tessera. A Synology usually can't pass a USB port to the container, so install your screens from your own computer, as in Installing screens.

Running Synology Container Manager with the ready image is new. Please report how it goes.

Prefer to build the image yourself? compose.yaml has the build: lines ready, in a comment above image:. That needs git on the host.

Installing screens ​

From here it works like the app on Home Assistant OS: New screen installs a screen, Tessera adds it to Home Assistant by itself once it is on your Wi-Fi, and then you choose the tiles. Add a screen walks through it.

Tessera knows a screen's key from its file in the folder mounted at /config. A screen whose file lives somewhere else, such as an ESPHome Device Builder folder you didn't mount here, is added to Home Assistant by hand.

How to get the first firmware onto a screen:

Your hostHow
Linux, screen plugged into the Docker hostConnect the screen, uncomment devices: in compose.yaml with its port (/dev/ttyUSB0 or /dev/ttyACM0), and run docker compose up -d. Then choose that port under Install via.
Docker Desktop, Synology, or a server out of reachPlug the screen into the computer you are using. Under Install via, in Plugged into this computer, choose Install from this browser (Chrome or Edge) and click Connect & install. The container builds the firmware and the page writes it to the screen. This needs Tessera opened over https, or on localhost (such as through the SSH tunnel). Otherwise choose Download the file and flash it yourself and put the file on the screen with ESPHome Web.

After the first install, every update goes over Wi-Fi and needs nothing extra.

Camera images: every screen except the CYD, the Waveshare 3.5-inch and the Hosyond 4-inch shows camera pictures and album covers. The screens load them from port 8098 of the Docker host, so keep that port open to them. By default the app gives the screens Home Assistant's own network address. If the screens reach the Docker host under another address, set SCREEN_CAMERA_URL. More in Cameras and pictures.

Claude: the Install for Claude Code button is meant for the Claude Code app on Home Assistant OS. Use Download for claude.ai instead.

Updating ​

Update the app first, then update each screen.

To update the app, run this in the folder with compose.yaml:

sh
docker compose pull
docker compose up -d

This pulls the latest image, the same version the Home Assistant app store offers. On a Synology, stop the project in Container Manager, pull the new image and start the project again. Afterwards, Tessera shows for each screen whether newer firmware is available.

To stay on one version, replace latest in the image: line of compose.yaml with a version number:

yaml
image: ghcr.io/maxgramser/homeassistant_espscreen:0.3.25

Set up before app 0.3.22? Your compose.yaml still builds from GitHub with build:. Download the current compose.yaml and keep your own HA_API and folders.

Backups ​

Home Assistant backups don't include this container. Keep a copy of:

  • data/screens.json and data/updates.json: your layouts and update settings.
  • The ESPHome folder (esphome by default): the screens' files and Wi-Fi secrets.

data/build, data/esphome, data/idf and data/platformio are caches and can be left out.

Settings in compose.yaml ​

SettingWhat it does
SCREEN_DEV: "1"Runs the app without Home Assistant's Supervisor: it reads the token from HA_TOKEN_FILE, and the page listens on 127.0.0.1 only. Camera images for the screens stay on port 8098 on every address.
HA_APIHome Assistant's address, ending in /api
HA_TOKEN_FILEThe token file inside the container (the ha_token secret)
ESPHOME_CONFIGThe ESPHome folder inside the container. Keep it /config: /esphome holds the ESPHome tools themselves.
SCREEN_DATALayouts, update settings and build caches
SCREEN_CAMERA_URLOptional: where screens load camera images, such as http://192.168.1.20:8098. By default Home Assistant's own network address.
SCREEN_CAMERA_PORTOptional: another port for camera images instead of 8098

If something doesn't work ​

What you seeWhat to do
An error that git can't be foundYour compose.yaml is from before app 0.3.22 and still builds from GitHub. Use the current one, which pulls the ready image (see Updating).
No Home Assistant connected in the logCheck that ha_token holds only the token, and that HA_API ends in /api and reaches Home Assistant from inside the container.
502: Bad Gateway in the sidebar panelHome Assistant is on a bridge network. Follow Home Assistant on a bridge network.
The page asks you to open it through Home AssistantYou opened port 8099 from another address. Use the sidebar panel or the SSH tunnel.
Camera tiles stay emptyOpen port 8098 on the Docker host to the screens, and set SCREEN_CAMERA_URL if the screens reach the host under another address.

Still stuck? Please open an issue.