Skip to content

Repository files navigation

Smart TV Remote Control

Universal Flutter remote for Samsung Tizen and LG WebOS TVs — discovery, control, and reconnect without the original remote.

CI License Flutter Version


Screenshots

Device picker Remote Manual IP dialog
screenshot coming soon screenshot coming soon screenshot coming soon

Features

Discovery

  • Parallel UPnP and mDNS network scan
  • Manual IP entry as a fallback when the TV refuses to broadcast
  • Known-TV memory: previously paired sets are remembered and auto-connected on next launch

Connectivity

  • Real network state via connectivity_plus (no DNS polling)
  • Native WebSocket pingInterval-based heartbeat (no manual 500 ms / 5 s timer loops)
  • Wake-on-LAN: when a known TV refuses the connection, the app sends a magic packet and retries once
  • Samsung pairing token persisted locally — the on-TV "Allow" popup only appears the first time

Brands

  • Samsung Tizen — real WebSocket v2 (wss://) implementation in lib/services/samsung/samsung_tv_service.dart
  • LG WebOS — full client in lib/services/lg/lg_tv_service.dart (replaces the previous stub)
  • Other brands — manual IP + generic key codes

UX

  • Material 3 dark theme
  • Haptic feedback on every key press
  • Semantics labels on every button (screen-reader friendly)
  • Localized: English, Spanish, Arabic (ARB files under lib/l10n/)

Supported TVs

Brand Models Protocol Notes
Samsung 2016+ Tizen WebSocket v2 (wss://<ip>:8002) Token saved after first "Allow"
LG WebOS 3.0+ WebSocket (ws://<ip>:3000) Client-key pairing persisted
Other Any networked TV Manual IP + generic codes Best-effort, no discovery

Quickstart

git clone https://github.com/<your-org>/Smart-TV-Remote-Control.git
cd Smart-TV-Remote-Control
flutter pub get
flutter run

Requirements:

  • Flutter >= 3.24.0, Dart >= 3.5.0
  • Phone and TV must be on the same Wi-Fi / VLAN
  • On Android 13+ grant the Local Network / nearby-devices permission when prompted

Architecture

┌─────────────────────────────────────────────────────┐
│  UI  (screens, widgets)                             │
│   - DeviceSelectionScreen                           │
│   - RemoteScreen                                    │
│   - ManualIpDialog                                  │
└───────────────▲─────────────────────────────────────┘
                │ BlocBuilder / BlocListener
┌───────────────┴─────────────────────────────────────┐
│  Bloc layer   (lib/blocs/)                          │
│   - TvConnectionBloc                                │
│   - DeviceDiscoveryBloc                             │
│   - ConnectivityCubit                               │
└───────────────▲─────────────────────────────────────┘
                │ calls
┌───────────────┴─────────────────────────────────────┐
│  Repository layer                                   │
│   - TvRepository       (brand-agnostic facade)      │
│   - DiscoveryRepository                             │
│   - KnownTvsStorage / TvTokenStorage                │
└───────────────▲─────────────────────────────────────┘
                │ delegates to
┌───────────────┴─────────────────────────────────────┐
│  Service layer  (lib/services/)                     │
│   - samsung/samsung_tv_service.dart   (WSS v2)      │
│   - lg/lg_tv_service.dart             (WebOS)       │
│   - mdns/mdns_discovery_service.dart                │
│   - upnp/upnp_discovery_service.dart                │
│   - wol/wake_on_lan_service.dart                    │
└───────────────▲─────────────────────────────────────┘
                │ TCP / UDP / WebSocket
┌───────────────┴─────────────────────────────────────┐
│  TV  (Samsung Tizen / LG WebOS / other)             │
└─────────────────────────────────────────────────────┘

DI is wired with get_it in lib/di/service_locator.dart. Blocs depend on repositories; repositories depend on services. UI never touches a service directly.


Troubleshooting

TV not found

  • Confirm the phone and TV share the same Wi-Fi SSID and are not on isolated guest / IoT VLANs.
  • On Android 13+, accept the local-network permission prompt — without it mDNS and UPnP both fail silently.
  • Try Add manually by IP from the device picker. The TV's IP is usually under Settings → Network → Status.

"Allow" popup never appears on Samsung

  • The TV may already have your token cached but blocked it. On the TV: Settings → General → External Device Manager → Device Connection Manager → Access Notification → set to First time only, then delete this phone from Device List and reconnect.
  • Clear app data to drop the stored token and force a fresh handshake.

Won't reconnect after the TV sleeps

  • This is what Wake-on-LAN is for. Open Settings → General → Network → Expert Settings on the TV and enable Power On with Mobile. The app stores the MAC on first connection and will fire a magic packet on the next attempt.
  • If WoL still fails, the TV is likely on a different subnet from your phone — magic packets do not cross routers.

Roadmap / Known limitations

  • Hardware volume-button capture (Android MediaSession / iOS MPRemoteCommandCenter) — not yet wired
  • App launcher (Netflix, YouTube, Disney+ deep links) — protocol supports it, UI pending
  • Swipe trackpad for cursor-style WebOS navigation — planned
  • Sony Bravia (IRCC-IP) and Roku (ECP) — not implemented
  • iOS background reconnect is best-effort; system may suspend the socket

Contributing

Pull requests welcome. See CONTRIBUTING.md for setup, code style, and the commit convention.

License

MIT — see LICENSE.

About

A universal Smart TV remote control made using flutter

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages