TV Hack
Log 01 / 06

Getting in

A device called "SONY" on my Wi-Fi, a Developer Mode that was already on, and the first of two black screens.

By prutxviBuilt with Claude~6 min read

What's on my Wi-Fi?

The first thing I asked for was a list of what's on my network. Claude scanned it and came back with my phones, a Jio set-top box, and a device advertising itself as "[TV] SONY".

It was my Samsung. Someone had renamed it years ago. One HTTP request to the TV's own API settled it:

# every Samsung Smart TV answers this on port 8001
curl http://<tv>:8001/api/v2/

# → model UA43T5310 · Tizen 5.5 · "developerMode": "1"

That response held the most useful fact of the whole project: Developer Mode was already switched on. It also became the health check I used for the rest of the build. If that URL answers, the TV is awake and on the network.

The Jio box was a dead end

The Jio set-top box runs Jio's own Android TV skin. The developer options have been removed from that firmware, the "Version & Build" row can't be tapped seven times, and every ADB port is closed. The only open ports belong to Chromecast. It's leased hardware anyway, so I left it alone. The Samsung became the target.

The TV
ModelSamsung UA43T5310, 2020, 43" Full HD
OSTizen 5.5
Web engineChromium 94, with WebGL and a WebAssembly JIT
Hardware4 CPU cores, about 1 GB of RAM
Background servicesNode.js v4.4.3 (from 2016: ES5 only, no npm)

How code gets onto a Samsung TV

Samsung TVs run Tizen, and Tizen apps are web apps: HTML, CSS and JavaScript, zipped and signed into a .wgt file. To install your own, you tell the TV which computer it should trust, then push the signed package over Wi-Fi.

  1. On the TV, open Apps and type 1 2 3 4 5 on the remote. A hidden Developer Mode dialog appears.
  2. Turn it on and set Host PC IP to your laptop's IP address.
  3. Hold the Power button for about five seconds until the Samsung logo appears. A short press only sleeps the TV and the setting won't apply.

On the laptop, Samsung's Tizen Studio command-line tools do the rest. sdb talks to the TV on port 26101, and tizen packages, signs, installs and runs. The whole loop, which we ran dozens of times:

sdb connect <tv>
sdb shell 0 was_kill PvHomeLnch.Home      # kill the running copy FIRST
tizen package -t wgt -s <profile> -o out -- src
tizen install -n Home.wgt -- out
tizen run -p PvHomeLnch.Home

Two things cost real time here:

Black screen #1

The first app installed fine and showed a completely black screen.

This is where the real skill of the project lives: debugging a TV with no developer console. The remote-debug command hangs on this model, so there is no inspector, no console and no error messages.

Claude's trick was a beacon. A tiny Python web server on the laptop logs every request it receives. Inside the TV app, every interesting moment sends a request to it by loading an "image":

// in the TV app: report anything to the laptop
function beacon(msg){
  new Image().src = 'http://<laptop>:8765/log?m=' + encodeURIComponent(msg);
}
beacon('boot');
window.onerror = function(m, src, line){ beacon('err ' + m + ' @' + line); };

The log stayed empty. Not even boot. So the problem wasn't a crash in our code; our code never ran at all. That pointed at the one file that runs before any code: the app's config.xml.

The cause was a single navigation rule (<tizen:allow-navigation>) that stopped the page from rendering. The fix was humbling: stop writing the config from memory and copy the shape of a config from a TV app that's known to work. The next install drew the screen.

The beacon became the main debugging tool for everything after this, including both Doom bugs.

One setting, two jobs

Later in the project we also used TizenBrew, an open-source tool that injects modules into TV apps (it's how ad-free YouTube and TV Browser+ work). TizenBrew injects through the TV's debugger, and for that it needs Host PC IP set to 127.0.0.1, the TV itself.

Laptop ── sdb :26101 ──▶ TV Developer Mode   Host PC IP = laptop    → install our apps
TV ── debugger ──▶ TizenBrew modules          Host PC IP = 127.0.0.1 → TizenTube, TV Browser+

The two needs conflict, so the routine is: switch the Host PC IP to the laptop, batch every install into one session, then switch it back.