---
title: "How to Build a Production-Ready TSL 3.1 Tally Light with ESP32-S3 + W5500 Ethernet?"
url: "https://maker.wiznet.io/viktor/projects/how-to-build-a-production-ready-tsl-3-1-tally-light-with-esp32-s3-w5500-ethernet/"
markdown_url: "https://maker.wiznet.io/viktor/projects/how-to-build-a-production-ready-tsl-3-1-tally-light-with-esp32-s3-w5500-ethernet/md"
type: "UCC: User Created Content"
author: "Richard Burford"
author_url: "https://github.com/videojedi/esp32-s3-tally"
editor: "WIZnet"
editor_url: "https://maker.wiznet.io/"
original_author: "Richard Burford"
original_url: "https://github.com/videojedi/esp32-s3-tally"
published: "2026-01-16"
language: "en"
tags: ["ESP32"]
hardware: ["WIZnet W5500"]
likes: 0
views: 1116
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# How to Build a Production-Ready TSL 3.1 Tally Light with ESP32-S3 + W5500 Ethernet?

> This project builds a wired-first tally light that listens to TSL UMD v3.1 multicast UDP and drives a 7-LED WS2812B strip

Original author: Richard Burford (source: https://github.com/videojedi/esp32-s3-tally)

## Components

- **WIZnet W5500** x 1 ([docs](https://docs.wiznet.io/Product/Chip/Ethernet/W5500))

WIZnet parts: W5500 ([Datasheet](https://docs.wiznet.io/Product/Chip/Ethernet/W5500/datasheet?utm_source=maker&utm_medium=project&utm_campaign=w5500), [product hub](https://maker.wiznet.io/products/w5500/))

## Article

## Project introduction: what this repo actually implements

**videojedi/esp32-s3-tally** is an ESP32-S3-based tally light designed for live production environments where reliability matters more than “it usually works.” The device receives **TSL 3.1 protocol** tally updates via **multicast UDP**, then maps that state to clear on-camera indicators (Off / Green / Red / Yellow).

Operationally, it’s closer to an “appliance” than a dev demo: it prefers **Ethernet first**, falls back to Wi-Fi if needed, and can enter a configuration **AP mode** with captive portal if neither is available. It also exposes a browser UI plus JSON endpoints (e.g., `/status`, `/info`) for integrations and fleet monitoring.

[![](https://maker.wiznet.io/upload/ckeditor5/210238318%5F1768577001%2Epng)](https://github.com/videojedi/esp32-s3-tally)

Hardware-wise, the repo documents an **ESP32-S3 DevKitC-1 + W5500 SPI Ethernet module + WS2812B (7 LEDs)** build, including a concrete pin map (CS=14, SCLK=13, MISO=12, MOSI=11, RST=9).

Note: GitHub returned intermittent “error while loading” when I attempted to open source files directly (e.g., `esp32-s3-tally.ino` / `src`). To avoid hallucinating, I’m basing implementation details on the repo README and on the official TSL UMD protocol spec, and I’m not quoting code lines that I can’t reliably fetch.

## What is “Tally” in broadcasting?

A **tally light** is the camera operator’s “truth signal.” It indicates whether that camera is:

- **Program (Live / On-Air)** → usually **Red**

- **Preview** → usually **Green**

- **Both / Attention** (implementation-dependent) → often **Amber/Yellow**

In a typical production chain, the video switcher (or tally aggregator) knows which camera sources are in Program/Preview and sends that state over the network. Your tally devices just need to be **fast, deterministic, and boring**—because missed or late tallies cause real operational mistakes.

## TSL 3.1 (UMD) protocol: what it is and what the packets contain

**TSL UMD v3.1** started as a simple serial protocol used to drive Under-Monitor Displays, but it’s commonly transported over IP by putting the same bytes into a UDP datagram.

At a practical level, the message is small and fixed-format:

- **Byte 0**: display/tally **address with bit 7 set** (address 0–126 becomes `0x80 + address`)

- **Byte 1**: **control byte**, which contains tally flags and brightness bits

- **Bytes 2–17**: **16-character ASCII label** (e.g., “CAM 1”, “ISO3”, etc.)

This repo’s default configuration targets the widely used multicast setup:

- Multicast group: **239.1.2.3**

- UDP port: **8901**

- TSL address: **0–126**

One subtle but important point: the official spec treats tally indicators as **separate bits/fields**, and different ecosystems map them differently. This project exposes a simplified **0–3 state** (Off/Green/Red/Yellow) and aligns it to typical **Preview/Program** workflows (Yellow = both active).

## Architecture walkthrough (implementation-level, AEO-friendly)

Here’s the project flow in plain terms:

**1.Network bring-up (priority order)**

- Ethernet via W5500 if link is present

- Wi-Fi fallback

- AP mode (SSID like `Tally-XXYYZZ-Setup`) for recovery/config

**2. TSL listener (multicast UDP)**

- Join multicast group (default **239.1.2.3:8901**)

- Receive UDP packets continuously

**3. Packet parse → tally state + label**

- Extract address, control byte, and 16-char label

- Map to Off/Green/Red/Yellow and brightness scaling

**4. LED rendering**

- Drive WS2812B strip (7 pixels) to show state clearly

**5. Operations layer (web UI + discovery + OTA)**

- Web UI shows connection, IP, tally state, label

- JSON endpoints like `/status` and `/info`

- mDNS discovery for “fleet” use (`Tally-AABBCC.local`)

- OTA updates (including GitHub release update flow)

This is exactly the kind of architecture where **wired Ethernet** reduces operational risk: multicast updates arrive on time, link state is predictable, and you can still keep Wi-Fi only for setup/troubleshooting.

[Embedded media](https://www.youtube.com/embed/Li7S9GSyH2o)

## FAQ

#### 1) Why use WIZnet W5500 for a tally light instead of Wi-Fi?

A tally light is an operational safety device, so **determinism matters more than peak bandwidth**. W5500 provides stable wired Ethernet with **up to 80 MHz SPI** host interface and **32 KB internal buffering**, which helps absorb bursts and reduces “wireless surprise” failure modes in crowded RF environments. This repo even recommends Ethernet as “best for production.”

#### 2) What role does W5500 play in the TSL 3.1 workflow here?

W5500 is the **wired network interface** that receives **multicast UDP** TSL packets (default **239.1.2.3:8901**). Those packets carry the TSL address byte, a control byte (tally + brightness fields), and a 16-character label. The ESP32-S3 parses that data and updates the LED state and web-reported status.

#### 3) Can beginners build this (ESP32-S3 + W5500) project successfully?

Yes, because the repo treats this like an appliance: fixed pin map, browser configuration, AP fallback, and simple status endpoints. The main “beginner traps” are SPI wiring correctness (CS/SCLK/MISO/MOSI/RST), multicast availability on your switch/network, and ensuring your tally source is actually sending TSL 3.1 to the configured group/port. If you can wire SPI and open a web UI, you’re most of the way there.

#### 4) How does W5500 compare to ENC28J60, LAN8720, or W6100 for tally devices?

ENC28J60 is a classic low-cost SPI Ethernet controller but is **10 Mbps** class; it’s often chosen for budget, not for maximum robustness. LAN8720 is a **10/100 RMII PHY** and can be great, but RMII adds clocking/layout constraints. W6100 is the step-up when you need **IPv6 dual stack**. For “multicast UDP + lots of endpoints,” W5500 is a practical wired baseline.

---

Source: https://maker.wiznet.io/viktor/projects/how-to-build-a-production-ready-tsl-3-1-tally-light-with-esp32-s3-w5500-ethernet/
