Przejdź do głównej zawartości

AVR-IplaTV-Box, czyli Ipla TV na Twoim telewizorze!

· 11 min aby przeczytać
AVR-IplaTV-Box, czyli Ipla TV na Twoim telewizorze!

AVR-IplaTV-Box to urządzenie, które pozwala na oglądanie oraz zarządzanie kanałami TV z serwisu Ipla za pomocą zwykłego pilota wyposażonego w nadajnik IR.

Czym właściwie jest AVR-IplaTV-Box?

AVR-IplaTV-Box jest urządzeniem, które pozwala na oglądanie kanałów TV z serwisuIpla.tv na Twoim telewizorze. Dodatkowo urządzenie wyposażone jest w odbiornik IR, który jest odpowiedzialny za obsługę zmiany kanałów za pomocą zwykłego pilota wyposażone w nadajnik podczerwieni IR.

Co właściwie potrafi robić to urządzenie?

AVR-IplaTV-Box pozwala w bardzo szybki oraz wygodny sposób na oglądanie oraz zarządzenie kanałami TV z serwisu Ipla za pomocą tego samego pilota, którego używamy do obsługi telewizora.

Główne funkcjonalności jakie zostały przeze mnie zaimplementowane w tym projekcie to:

  • zamiana kanałów TV,
  • zatrzymywanie oraz wznawianie transmisji,
  • dwustopniowe przewijanie kanałów (10 sekund lub 5 minut) w tył i przód,
  • regulacja poziomu jasności,
  • automatyczne logowanie do konta Ipla,
  • pełna kontrola urządzenia za pomocą pilota od telewizora,
  • wyświetlanie informacji odnośnie aktualnie emitowanego programu - nazwa oraz krótki opis,
  • wyświetlanie aktualnego paska postępu dla wszystkich programów,
  • łatwa konfiguracja aplikacji za pomocą pliku application.properties,
  • możliwość edytowania dostępnych kanałów TV za pomocą pliku channels.json,
  • możliwość wyłączenia urządzenia z poziomu pilota.

Poniżej zamieszczam krótki filmik prezentujący wyżej wymienione funkcjonalności.

Skąd wzięła się potrzeba stworzenia takiego urządzenia?

Obecnie serwis Ipla TV pozwala na zakup pakietów z kanałami TV (Discovery, Polsat itd.), które można oglądać za pośrednictwem serwisu Ipla TV lub aplikacji na Anroida i iOS. Niestety nie ma możliwości oglądania kanałów TV w aplikacji Ipla na Smart TV, co oznacza że do oglądania kanałów TV jest wymagany komputer lub smartphone. Kontaktowałem się nawet w tej sprawie z pomocą techniczną Ipla, lecz powiedzieli mi, że nie planują w najbliższym czasie wyprowadzenia kanałów TV na smart TV (pewnie wynika to ze sposobu szyfrowania danych, ale o tym później).

Zarządzanie Prawami Cyfrowymi, czyli DRM

Serwis Ipla wykorzystuje popularny ostatnimi czasy system DRM (ang. Digital Rights Management) do zarządzania prawami autorskimi. W praktyce oznacza, to że nie jest możliwe oglądanie kanałów TV na takich urządzeniach jak Raspberry PI, co wiązało się z koniecznością zastosowania komputera z architekturą inną niż ARM.

Zotac ZBOX B1324 - "mózg" całego systemu

System zabezpieczeń DRM ograniczył zakres urządzeń, które mógłbym wykorzystać w projekcie do właściwie trzech grup: komputer klasy PC, notebook lub mini PC. Jednym z kluczowych aspektów przy wyborze była cena oraz jak najmniejsze zużycie energii przez urządzenie, co ostatecznie przyczyniło się do wyboru urządzenia klasy mini PC, a dokładniej mówiąc komputer Zotac ZBOX B1324.

Wygoda przede wszystkim!

Jednym z głównych założeń projektu było, aby całe urządzenie można obsługiwać w taki sam sposób, jak zwykły telewizor. Co wiązało się z koniecznością stworzenia dodatkowego interfejsu, który pozwoliłby na sterowanie urządzeniem za pomocą pilota od telewizora.

Opis klawiszy pilota sterującego
Opis klawiszy pilota sterującego

W tym calu zastosowałem zestawy uruchomieniowy (ewaluacyjny) Atnel ATB 1.05a, wyposażony w m.in. mikrokontroler Atmega 32A oraz odbiornik podczerwieni TSOP31236. Do obsługi odbiornika podczerwieni po stronie mikrokontrolera wykorzystałem bibliotekę IR_UNI autorstwa Mirosława Kardaśa, która była dołączona do książki Język C Pasja programowania mikrokontrolerów 8 - bitowych. Dodatkowo zestaw ten jest wyposażony w układ FT232RL, który pozwala na komunikację z komputerem za pomocą interfejsu USB.

Schemat blokowy urządzenia - hardware
Schemat blokowy urządzenia - hardware

Selenium, czyli Ipla TV pod naszą kontrolą

Najtrudniejszym etapem podczas tworzenia tego projektu, był wybór sposobu w jaki mógłbym sterować kanałami Ipla z poziomu własnego programu. Długo borykałem się z tym problemem. Normalnie w takiej sytuacji korzysta się z zewnętrznego API, które jest dostarczane przez serwis z którym chcemy się komunikować. Niestety Ipla nie dostarcza żadnego API za pomocą którego mógłbym zarządzać treścią na ich stronie. Jeszcze kilka lat temu problem ten można było obejść umieszczając kontent w tagu iframe i za pomocą skryptów JS sterować jego zawartością. Niestety obecnie prawie każdy serwis blokuje tą możliwość. Po długiej analizie postanowiłem w tym celu wykorzystać framework Selenium, czyli narzędzie przeznaczone do tworzenia testów automatycznych dla stron internetowych. Selenium udostępnia również własne SDK, które pozwala na tworzenie testów automatycznych z poziomu programu napisanego w Javie. Po dokonaniu wyboru sposobu w jaki będę mógł zarządzać treścią w serwisie Ipla przystąpiłem do tworzenia scenariusza testowego, odpowiedzialnego za logowanie do serwisu. Kolejnym etapem był żmudny proces analizowania struktury elementów zawartych w drzewie DOM (ang. Document Object Model) oraz skryptów JS odpowiedzialnych za kontrolę odtwarzacza (play, pausa, przewijanie do przodu i do tyłu itd.). Większość tych procesów można wyzwolić za pomocą wywołania odpowiednich funkcji JS, niestety niektóre (np. tryb pełnoekranowy) jest niemożliwy do wyzwolenia z poziomu zewnętrznego skryptu (zabezpieczenie CORS), co oznaczało że musiałem stworzyć własny skrypt dla trybu pełnoekranowego.

Łączymy poszczególne klocki w całość

Na tym etapie miałem już przygotowane dwa interfejsy. Pierwszy, odpowiedzialny za odczytywanie komend z pilota od telewizora (zestaw ATB + biblioteka IR_UNI) i następnie wysyłanie ich przez magistralę UART do komputera (UART<->USB). Natomiast drugi interfejs jest przeznaczony do zarządzania treścią w serwisie Ipla (Java + Selenium). W celu połączenia tych dwóch niezależnych interfejsów w całość wykorzystałem bibliotekę librxtx-java, która jest dostępna w centralnym repozytorium (sudo apt-get install librxtx-java).

Schemat blokowy urządzenia - software
Schemat blokowy urządzenia - software

Biblioteka ta pozwala na komunikację z urządzeniami peryferyjnymi wyposażonymi w port szeregowy, z poziomu programu napisanego w Javie. W naszym przypadku pod pojęciem protu szeregowego rozumiemy komunikację pomiędzy interfejsem UART mikrokontrolera, a magistralą USB naszego komputera. Konwersja UART<->USB jest dokonywana za pośrednictwem dedykowanego do tego celu układu FT232RL, który jest fabrycznie montowany w zestawach ATB.

Komunikacja i konfiguracja

Komunikacja pomiędzy aplikacją desktop'ową, a zestawem ATB jest realizowana za pomocą portu szeregowego, gdzie przesyłane są komendy w postaci kodów ASCII (zwykły tekst). Poniżej zamieszczam wykaz komend wraz z ich opisem.

KomendaOpis
6:16Zaloguj się do konta Ipla TV
124:16Odtwórz kanał
120:16Poprzedni kanał
121:16Następny kanał
26:16Tryb pełnoekranowy
2:16Play
1:16Pause
0:16Resetuj odtwarzacz (Go To Now)
52:16Przewiń 10 sekund w przód
51:16Przewiń 10 sekund w tył
49:16Przewiń 60 sekund w przód
48:16Przewiń 60 sekund w tył
18:1Zwiększ jasność
19:1Zmniejsz jasność
37:1Resetuj jasność
115:16Zmień rozdzielczość
5:16Włącz/wyłącz dźwięk aplikacji
123:16Pokaż okno aplikacji
122:16Ukryj okno aplikacji
7:16Aktualizacja EPG
4:16Pokaż/ukryj opis programu
21:1Wyłącz system

Aby móc obsługiwać aplikację za pomocą mikrokontrolera, wystarczy wysłać odpowiednią komendę z powyżej tabeli przez magistralę UART do komputera np. wykorzystując w tym celu Arduino. Kody w powyżej tabeli składają się z dwóch liczb oddzielonych znakiem dwukropka, które oznaczają odpowiednio wartość komendy (Command World) oraz adresu urządzenia (Device World), które są specyficzne dla ramki IR pilotów Sony (Sony SIRC infrared protocol).

Użytkownik może również dokonać konfiguracji samej aplikacji za pomocą pliku application.properties w którym wystarczy zmodyfikować wartość dla interesującego nas klucza np. ustawić login i hasło do serwisu Ipla. Poniżej zamieszczam wykaz dostępnym kluczy konfiguracyjnych wraz z opisem i przykładową (domyślną) konfiguracją.

KluczWartośćOpis
loginuser@email.comLogin do serwisu Ipla TV
passwordmy_passwordHasło do serwisu Ipla TV
serial.port/dev/ttyUSB0Nazwa portu
serial.baud.rate9600Szybkość transmisji dla portu szeregowego
offset.x26Przesunięcie okna aplikacji z poziomie
offset.y13Przesunięcie okna aplikacji z pionie
opacity0.86Przezroczystość aplikacji
header.big.font.size46Rozmiar czcionki dla nagłówków wyrażony w pt
header.small.font.size26Rozmiar czcionki dla tekstu wyrażony w pt

Dodatkowo istnieje możliwość konfiguracji dostępnych kanałów TV za pomocą pliku channels.json. Plik ten przechowuje listę dostępnych kanałów w formacie JSON.

{
"channels":[
{
"item":{
"name":"DISCOVERY_CHANNEL",
"url":"https://www.ipla.tv/kanaly-tv/Discovery-Channel-HD/11399",
"icon":"/logo/discovery-channel.png"
}
},
{
"item":{
"name":"POLSAT_PLAY",
"url":"https://www.ipla.tv/kanaly-tv/Polsat-Play-HD/11379",
"icon":"/logo/polsat-play.png"
}
}
]
}

UI/UX, czyli To co cieszy nasze oko

Ostatnim etapem projektu był proces tworzenia odpowiedniego GUI (ang. Graphical User Interface), które pozwoli w prosty sposób zarządzać kanałami. Interfejs graficzny składa się tak naprawdę z dwóch oddzielnych interfejsów. Pierwszy stanowi główna aplikacja napisana w języku Java z wykorzystaniem bibliotek JavaFX oraz JFoenix z moimi modyfikacjami po stronie palety kolorów. Drugi to interfejs graficzny wyświetlany w oknie przeglądarki, który opiera się w głównej mierze o jeden komponent typu SnackBar na którym prezentowane są informacje dotyczące m.in aktualnego statusu odtwarzacza.

Proces pozyskiwanie dodatkowych informacji o kanałach
Proces pozyskiwanie dodatkowych informacji o kanałach
Proces pozyskiwania danych do komponentu SnackBar
Proces pozyskiwania danych do komponentu SnackBar

Informacje odnośnie aktualnie emitowanego programu pozyskiwane są z serwisu Ipla, a następnie parsowane po stronie aplikacji za pomocą biblioteki JSoup.

Kącik dla Developera

W początkowej fazie aplikacja desktopowa była pisana w języku Java w wersji 8, jednak wraz z rozwojem projektu postanowiłem zwiększyć kompatybilność aplikacji tak, aby można było ją uruchomić na maszynie JVM 9+, co wiązało się z koniecznością rozwiązania kilku problemów, a dokładniej mówiąc jednego związanego z wycofaniem bibliotek JavaFX ze standardowego pakietu Javy od wersji 9. W celu rozwiązania tego problemu wykorzystałem darmową alternatywę w postaci biblioteki OpenJFX, którą dołączyłem do projektu w postaci dodatkowej zależność (ang. dependency). Sama aplikacja została tylko zaadaptowana do nowszej wersji Javy, lecz nie wykorzystuje ona żadnych feature z nowszych wersji, co oznacza że można ją uruchomić również na maszynie w wersji 8 (po wcześniejszej modyfikacji pliku pom.xml). Proces budowania aplikacji zrealizowałem wykorzystując Maven'a wraz z dodatkowym pluginem maven-antrun-plugin służącym do wykonywania tasków Ant'owych. Plugin ten wykorzystałem do kopiowania plików (dodatkowe, zewnętrzne zasoby) podczas procesu budowania aplikacji. Dodatkowo zaimplementowałem swój własny mechanizm CI/CD (ang. Continuous Integration/Continuous Delivery) w postaci prostego skryptu napisanego w bash'u do automatycznego aktualizowania aplikacji, budowania (jeśli została zaktualizowana) oraz uruchamiania bez jakiejkolwiek ingerencji użytkownika. Jeśli chodzi o sam kontekst aplikacji, to jest on zarządzany przez Spring Framework (Spring-Boot), a cały kontekst jest definiowany w pliku spring-beans.xml. Sam kontekst Springo'owy składa się z jednego kontrolera, serwisów, fasady, kilku bean'ów do obsługi komunikacji z mikrokontrolerem oraz jednego schedulera ze stałym interwałem czasowym (1 min) odpowiedzialnego za aktualizację informacji EPG. Oczywiście podczas migracji napotkałem mnóstwo problemów związanych z m.in. widocznością pomiędzy modułami OpenJFX a JFonix (koncepcja modułów pojawiła się w Javie 9) oraz podnoszeniem kontekstu Spring'owego z poziomu JAR'a. Wiązało się to z koniecznością zastosowania dodatkowej klasy Launcher ze statyczną metodą main, która wywołuje kolejną statyczną metodę. Nie chcę tutaj zbytnio rozpisywać się o szczegółach tych problemów, jednak same ich rozwiązania można wyczytać bezpośrednio z kodu który umieściłem na github'ie. Jeśli jednak pojawią się dodatkowe pytania dot. samej kwestii developmentu oraz architektury oprogramowania, to zachęcam do zadawania ich w komentarzu. Na koniec dodam jeszcze, że jednym z ciekawszych wzorców, który ostatnio odkryłem i postanowiłem zaimplementować w tym projekcie był wzorzec Command Pattern, który wykorzystałem do rejestrowania metod z serwisów i fasad do zdarzeń, które są generowane w momencie odebrania danych z portu szeregowego.

PS. Wiem, wiem... że obecnie każdy używa Spring-Boot'a i magicznych adnotacji, jednak nauczony doświadczeniem, wiem że lepiej zarządza się strukturą kontekstu z poziomu jednego lub kilku plików XML, a nie skacząc po wszystkich klasach. Dodatkowo taka struktura zwiększa znacznie poziom utrzymania aplikacji, a jeśli chodzi o samego Spring-Boot'a to każdy go dołącza do swoich projektów tak na prawdę nie wiedząc co on ze sobą niesie (czyt. niepotrzebne zależności, które nie są wykorzystywane w aplikacji).

Super projekt! Czy mogę to uruchomić na swoim komputerze?

Cały projekt (po za kodami w C dla zestawu ATB) jest dostępny na moim github'ie, gdzie również znajduje się instrukcja dotycząca procesu konfiguracji oraz uruchomienia aplikacji. Niestety na obecną chwilę nie mogę udostępnić kodów w C, ponieważ w głównej mierze bazują one na bibliotekach Pana Mirosława Kardaśa, które są objęte prawami autorskimi. Jednak jeśli ktoś będzie chciał zrealizować interfejs odpowiedzialny z obsługę pilota, to w tym celu może wykorzystać dowolną płytkę Arduino oraz bibliotekę do obsługi IR, których w Internecie jest bardzo dużo. W przyszłości zamierzam rozwiązać ten problem, ale o tym później.

Perspektywa dalszego rozwoju

Obecnie jedyną rzeczą którą zamierzam zrobić w niedalekiej przyszłości to zamiana zestawu ATB na zwykły mikrokontroler AVR z odbiornikiem podczerwieni. Można tego dokonać na dwa sposoby. Pierwszy to zaprojektować własną płytkę lub skorzystać z płytek uniwersalnych, a następnie przylutować mikrokontroler, odbiornik IR oraz układ FT232. Drugą opcją (prostszą, szybszą i tańszą) to wykorzystanie jednej z płytek Arduino, które domyślnie wyposażone są w przetwornik UART<->USB. Jedyną dodatkową rzeczą do zrobienia w tym przypadku jest podłączenie odbiornika IR. Osobiście będę podążał tą drogą, co oznacza że każdy będzie mógł w bardzo prosty i szybki sposób stworzyć interfejs do komunikacji pomiędzy pilotem a aplikacją desktop'ową.