Display Soccerscores on AwTrix3 (Ulanzi TC001)

Ahoi - Don't fork
This is my personal server. I try to maintain it and keep it running, but I cannot guarantee it.
So if you want to fork - especially if the idea is to have a backup - do not use the "Fork" button here.
Instead use

git clone --mirror
and push it to your preferred service like Codeberg

  • C# 98%
  • Dockerfile 2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Ole Albers c373f7f819 x
2026-08-08 18:27:10 +02:00
.gitea ci: add FUNDING.yml for sponsor links 2026-03-31 13:41:18 +02:00
cache fix friendlies on espn 2026-08-08 18:25:03 +02:00
doc Added docs; added configfile 2025-08-17 12:52:58 +02:00
Entities fix espn friendlies 2026-08-08 18:25:46 +02:00
.gitignore x 2026-08-08 18:27:10 +02:00
AwTrix.cs fix espn friendlies 2026-08-08 18:25:46 +02:00
Collector.cs fix espn friendlies 2026-08-08 18:25:46 +02:00
Config.cs switch to FotMob 2025-10-05 16:44:59 +02:00
config.json fix espn friendlies 2026-08-08 18:25:46 +02:00
Dockerfile fix espn friendlies 2026-08-08 18:25:46 +02:00
Espn.cs fix espn friendlies 2026-08-08 18:25:46 +02:00
Looper.cs switch to FotMob 2025-10-05 16:44:59 +02:00
Program.cs fix espn friendlies 2026-08-08 18:25:46 +02:00
README.md fix espn friendlies 2026-08-08 18:25:46 +02:00
Rest.cs Detect Games in the past (and don't show them as future games) 2025-08-24 10:39:07 +02:00
SoccerUlanzi.csproj fix espn friendlies 2026-08-08 18:25:46 +02:00
SoccerUlanzi.sln Initial Commit 2025-08-16 19:42:53 +02:00
TeamConfig.cs better TeamInfo on logging 2025-09-21 11:07:39 +02:00
Tracker.cs fix espn friendlies 2026-08-08 18:25:46 +02:00

SoccerUlanzi

A tool that displays live soccer scores on external devices such as the Ulanzi TC001 or any device with AwTrix3 installed.

Data source

All fixtures and scores come from ESPN's public site API - the same source the Home Assistant TeamTracker integration uses. Two endpoints are enough:

Purpose Endpoint
Current or next fixture of a team, across all competitions /soccer/all/teams/{teamId}
Score and clock of a known fixture /soccer/all/summary?event={eventId}

Because both use the all scope, league games, cup rounds and european nights are picked up automatically - there is no list of competitions to maintain.

Note: ESPN answers 403 to requests without a User-Agent as well as to browser-like ones (Mozilla/...). Espn.cs therefore sends a plain HTTP client identifier and falls back to another one should it ever be rejected.

Configuration

Configure the application by editing the config.json file with the following options:

Basic Configuration

  • Teams: Array of teams you want to track, each with an Id and a Name. The name is only used for logging, so an emoji is fine. To find a team ID:

    1. Go to the ESPN website and search for your team
    2. Select the team from the search results
    3. The team ID is in the URL

    Example: For St. Pauli (ID: 270), the URL is: https://www.espn.co.uk/football/club/_/id/270/st-pauli

  • DeviceIp: IP address of your Ulanzi display device

  • Uninstall: Set to true to remove all created score apps from the display

  • DisplayDelayOnGames: Duration (in seconds) the app stays visible on the display during live games

  • DisplayDelayWhenOff: Duration (in seconds) the app stays visible on the display when no live games are active (default: 7 seconds when display starts for the first time)

  • DelayOnActiveGames: How frequently game data is updated during active games (format: "HH:MM:SS")

  • DelayWhenIdle: How frequently game data is updated when no games are active (format: "HH:MM:SS")

Example Configuration

{
  "Teams": [
    { "Id": "270", "Name": "St. Pauli" },
    { "Id": "137", "Name": "Werder" },
    { "Id": "127", "Name": "HSV" }
  ],
  "DeviceIp": "192.168.178.10",
  "Uninstall": false,
  "DisplayDelayOnGames": 40,
  "DisplayDelayWhenOff": 7,
  "DelayOnActiveGames": "00:00:10",
  "DelayWhenIdle": "00:15:00"
}

How a game is followed

For every team the application keeps track of exactly one fixture at a time:

  1. It asks ESPN which fixture is currently relevant for the team and remembers its event id in cache/tracked.json, so a restart does not lose a result that is still being displayed.
  2. From then on only that fixture is polled - every DelayOnActiveGames while the game is running, every DelayWhenIdle otherwise.
  3. The result stays on the display for 24 hours after kick off, then the next fixture is picked up. A preview appears 24 hours before kick off.

Postponed and abandoned games are recognised and removed from the display instead of being shown forever.

Team Logos

Team logos are automatically downloaded from ESPN. If you want to use custom logos or if an image is missing, you can place your own logos in the ./cache directory.

Logo file naming convention:

  • <teamid>.png - Standard 8x8 logo, used for the score display
  • <teamid>.6x6.png - Smaller 6x6 logo, used for the pre-match preview

Example for St. Pauli (Team ID: 270):

  • 270.png
  • 270.6x6.png

Missing crests

Not every club has a logo at ESPN. This is not a question of the division - it simply depends on whether ESPN maintains a crest for that club at all. As of the 2026/27 season:

Competition Clubs with a crest
1. Bundesliga 18 / 18
2. Bundesliga 17 / 18 - missing: Energie Cottbus (ID 123)
DFB-Pokal, 1st round 45 / 64 - missing: 3. Liga and below, plus Cottbus

So a regular league fixture can be affected too, not just cup ties against amateur sides. Those games are still displayed, just without the missing crest. Dropping <teamid>.png and <teamid>.6x6.png into ./cache fills the gap - the same mechanism used for the custom logos above.

Note: The example images below show custom logos - St. Pauli's logo has been replaced with a skull and HSV's logo with the red eye of Sauron.

Display Examples

The application shows different displays depending on the game state:

Pre-Match Display

Before Match

Displayed 24 hours before a match starts. Shows the game time and team logo.

Live Match Display

During Match

Shown during active games. Features:

  • Home team logo (left side)
  • Guest team logo (right side)
  • Current score (center)
  • Progress bar at top indicating minutes played (90-minute scale)

Match Paused

Match Paused

Same layout as live match, but the progress bar turns yellow when the game is paused.

Overtime Display

Overtime

During overtime periods (e.g., cup games), the progress bar becomes red to indicate extended play time (120-minute scale).

Match Finished

Match Finished

After the final whistle, the progress bar disappears, showing only the final score and team logos.

Installation & Usage

Running with Docker

  1. Build the Docker image:

    docker build -t soccer-ulanzi .
    
  2. Run the container:

    docker run -v $(pwd)/config.json:/app/config.json -v $(pwd)/cache:/app/cache soccer-ulanzi
    

    This command:

    • Mounts your local config.json file into the container
    • Mounts the local cache directory for logo storage
    • Starts the application
  3. Run in the background:

    docker run -d --name soccer-ulanzi -v $(pwd)/config.json:/app/config.json -v $(pwd)/cache:/app/cache soccer-ulanzi
    

Running with .NET

If you have .NET 9.0 installed locally:

  1. Restore dependencies:

    dotnet restore
    
  2. Run the application:

    dotnet run
    

Prerequisites

  • Ensure your config.json file is properly configured with your team IDs and device IP
  • Make sure your Ulanzi device is accessible on the network