Universal Flutter remote for Samsung Tizen and LG WebOS TVs — discovery, control, and reconnect without the original remote.
| Device picker | Remote | Manual IP dialog |
|---|---|---|
| screenshot coming soon | screenshot coming soon | screenshot coming soon |
- 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
- 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
- Samsung Tizen — real WebSocket v2 (
wss://) implementation inlib/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
- Material 3 dark theme
- Haptic feedback on every key press
Semanticslabels on every button (screen-reader friendly)- Localized: English, Spanish, Arabic (ARB files under
lib/l10n/)
| 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 |
git clone https://github.com/<your-org>/Smart-TV-Remote-Control.git
cd Smart-TV-Remote-Control
flutter pub get
flutter runRequirements:
- 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
┌─────────────────────────────────────────────────────┐
│ 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.
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.
- Hardware volume-button capture (Android
MediaSession/ iOSMPRemoteCommandCenter) — 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
Pull requests welcome. See CONTRIBUTING.md for setup, code style, and the commit convention.
MIT — see LICENSE.