Dnešní zápisek bude o skriptování velice běžných zařízení – jsou jimi televize Samsung a přehrávač Google Chromecast. Obojí samozřejmě v Pythonu jako součást chytře postaveného hloupého domu.
Skriptování televize
Televize Samsung, které disponují LAN portem, popř. WiFi připojením, lze vzdáleně ovládat pomocí jednoduchého protokolu stejným způsobem, jako kdybyste používali tlačítka z dálkového ovladače. Pro Android existují různé aplikace, já mám například nainstalovaný SamyGo Remote. My se však podíváme na to, jak se s televizí bavit z Pythonu. Použijeme pro to knihovnu samsungctl, která za nás udělá vše nutné.
Samotné použití je velice jednoduché, nejprve na televizi musíme povolit vzdálené ovládání (u mé televize Samsung UE37ES5500 v menu Síť / Nastavení AllShare) a sepsat dohromady konfiguraci:
REMOTE_CONFIG = { "host": "192.168.3.6", "port": 55000, "name": "Chromak MQTT", "description": "MQTT connector for Samsung TV", "id": "chromak", "timeout": 0.5, "method": "legacy", }
V konfiguraci je důležitá položka host
, kde je IP adresa vaší televize (je proto více než vhodné nastavit na DHCP serveru přidělování fixní IP). Položka port
je defaultní port, na kterém televize poslouchá, položky id
, name
a description
jsou libovolné řetězce a televize si klienta s těmito kombinacemi zapamatuje (při prvním pokusu o přístup zobrazí dialog, zda souhlasíte se vzdáleným ovládáním z takto identifikovaného zařízení). Položka timeout
je nastavena na komunikačním socketu, pro lokální síť není třeba žádná vysoká hodnota. A konečně method
(u mě "legacy"
, mám starší televizi) určuje komunikační metodu, dle samsungctl
novější televize podporují i "websocket"
, bohužel televizi již nějaký pátek mám.
Po instalaci samsungctl
(ideálně přes pip install samsungctl|
) je použití až triviálně jednoduché:
from samsungctl import Remote with Remote(REMOTE_CONFIG) as remote: remote.control("KEY_DTV")
Řetězec "KEY_DTV"
je kód tlačítka vybraný z množiny podporovaný kódů. Za zmínku stojí ještě "KEY_POWEROFF"
, který televizi vypne, bohužel vypnutou televizi nejde takto zapnout. Jak toto omezení obejít si povíme později.
Nejprve jsem se snažil nějakým chytrým způsobem recyklovat a udržovat aktivní připojení, ale nakonec jsem rezignoval, samotné poslání kódu včetně nového připojení před každým kódem proběhne v LAN tak rychle, že nemá cenu znovupřipojování řešit.
Skriptování Google Chromecast
Google Chromecast je velice šikovná krabička, obzvlášť pokud na telefonu používáte Google služeb. Já kromě Chromecastu mám i JBL Playlist, což je elegantně jednoduchý, ale výborně hrající reproduktor s podporou Chromecastu. Takto vybaven jsem nalezl projekt pychromecast, který se umí na Chromecast připojit a ovládat jej. Příklady kódu níže jsem vykoukal ze zdrojového kódu a z příkladů v examples, dokumentace moc sdílná není.
Připojení k Chromecast
Nejprve je nutné Chromecast na síti najít a vytvořit objekt, pomocí kterého ho budeme ovládat, mělo by stačit použít:
import pychromecast casts = pychromecast.get_chromecasts()
Bohužel, v mém případě se v seznamu casts
neobjevil JBL Playlist, našel jsem ale alternativu, možná i vhodnější, protože nespoléhá na broadcast po lokální síti, ale můžeme v ní rovnou předdefinovat IP adresy, které Chromecasty mají (opět fixně nastavené na DHCP serveru):
KNOWN_CHROMECASTS = [ ("192.168.1.8", 8009, None, "Chromecast", u"TV Obývák"), ("192.168.1.242", 8009, None, "Chromecast Audio", u"Ložnice"), ] casts = [] for cast_args in KNOWN_CHROMECASTS: cast = pychromecast._get_chromecast_from_host(cast_args) casts.append(cast) lst = ChromeListener(cast) cast.media_controller.register_status_listener(lst) cast.register_status_listener(lst)
Koho by zajímalo, položky v KNOWN_CHROMECASTS
mají následující význam: ip_address
, port
, uuid
, model_name
, friendly_name
.
Nyní jednak máme seznam casts
, kde jsou objekty sloužící k interakci s Chromecasty, ale zároveň jsme k Chromecastům přiřadili instanci ChromeListener
, prostřednictvím které pozorujeme stav Chromecastu. Jak tato třída může vypadat si ukážeme v dalším odstavci.
Pozorujeme a ovlivňujeme stav Chromecastu
První ze záležitostí, které jsem v Pythonu naskriptoval, je automatické nastavení hlasitosti na Chromecastu při spuštění nové položky (ať už hudby nebo videa), neboť maximální hlasitost zvuku při přehrávání z Chromecastu je výrazně vyšší než při přehrávání z televize. Prostřednictvím třídy ChromeListener pozoruji změny aktuální hlasitosti a změnu stavu přehrávače a v případě potřeby reaguji:
VOLUME_THRESHOLD = 0.4 PLAYER_STATE_BUFFERING = "BUFFERING" PLAYER_STATE_UNKNOWN = "UNKNOWN" PLAYER_STATE_IDLE = "IDLE" PLAYER_STATE_PAUSED = "PAUSED" PLAYER_STATE_PLAYING = "PLAYING" class ChromeListener(object): def __init__(self, cast): self.cast = cast self.last_player_state = None self.volume_level = None def new_media_status(self, status): player_state = status.player_state if player_state == PLAYER_STATE_BUFFERING: return if self.last_player_state in (PLAYER_STATE_UNKNOWN, PLAYER_STATE_IDLE) and (player_state in [PLAYER_STATE_PLAYING, PLAYER_STATE_PAUSED]): # Playback just started if self.volume_level > VOLUME_THRESHOLD: self.cast.set_volume(VOLUME_THRESHOLD*0.95) self.last_player_state = player_state def new_cast_status(self, status): self.volume_level = status.volume_level
Hlasitost upravuji následovně: pokud je v době spuštění přehrávání (pozná se přechodem do stavu PLAYING
nebo PAUSED
ze stavu UNKNOWN
nebo IDLE
) hlasitost vyšší než práh, nastavím novou hlasitost pomocí metody set_volume
lehce pod tento práh (VOLUME_THRESHOLD*0.95
). Stav, kdy Chromecast bufferuje stream (BUFFERING
) je ignorovaný.
Zapnutí televize pomocí Chromecastu
Jak jsem již říkal, Samsung televizi nejde pomocí jejich protokolu vzdáleně zapnout. Nicméně moje sestava TV + receiver + Chromecast umí televizi pomocí HDMI zapnout při spuštění nového media na Chromecastu. A tím pádem to lze i z Pythonu, stačí použít cosi jako:
cast.play_media("https://honzas.cz/wp-content/uploads/2014/06/cropped-header.jpg", "image/jpeg") time.sleep(5) cast.quit_app()
a naběhne vám televize s aktivním HDMI vstupem a Chromecast na výchozí obrazovce. Ukončení přehrávání pomocí quit_app()
zajistí, že obrázek ze záhlaví mého blogu ani neuvidíte.
Další náměty na skriptování
Skriptování můžeme použít k řadě dalších vychytávek a drobností. Já používám hlavně tyto:
- Při odchodu z domu (poznám přes MQTT ze stavu zabezpečovačky) vypnu televizi, JBL Playlist a aktuálně běžící aplikaci v Chromecastu.
- Ráno, když děti vstávají a pouští si televizi, v 7:00 vypínám seriály a pustím rádio stream pomocí:
cast.play_media("http://icecast7.play.cz/crojuniormini128.mp3", "audio/mpeg")
Navíc v 7:25 vypnu i tento stream pomocí známého:
cast.quit_app()
Díky tomu děti hned ráno ví, kolik je hodin a jak moc mají přidat, abychom v 7:30 odcházeli z domu. Navíc, abych zabránil zapínání televize v případě, že jsou třeba prázdniny a nikdo se v 7 hodin na televizi nedívá, čtu si stav UniFi controlleru zda je televize on-line (jinými slovy zapnutá).
- Vše, co jsem vám dnes popisoval, je součástí jednoho procesu, který navíc poslouchá na MQTT a umožňuje napojení na zbytek automatizace domu.
Závěrem
Jak vidíte, pokud se povede šikovně poskládat hardware (v mém připadě televize a Chromecast) se software, dají se obejít i omezené daného hardware (nelze po LAN zapnout televizi), navíc se jednoduchým skriptem nechá ovládat spoustu funkcí a vymyslet pár jednoduchých, ale pro život užitečných vychytávek.
Pokud máte Chromecast již naskriptovaný nebo máte v rukávu jiné vychytávky, podělte se o ně pod tweetem níže!
Chytře postavený hloupý dům: Skriptujeme televize a Chromecast
Můj zápisek o tom, jak pomocí Python naskriptovat Samsung televizi a Google Chromecast + pár vychytávek navíc. RT potěší#IoT #Pythonhttps://t.co/94qv6OawZu
— Jan Švec (@honza_svec) 13. února 2018