Удаленное управление VLC player’ом при помощи Arduino и Python

от автора

Добрый день, уважаемые читатели.

Я давно интересовался Arduino, и вот однажды решился на покупку этой замечательной платформы. После недолгих поисков приобрел небольшой Arduino kit, в котором, помимо прочего, был ИК-датчик и пульт к нему. Изучив примеры из мануала, понял, что настало время придумать что-то свое. В итоге я решил сделать удаленное управление VLC player’ом, используя магию Arduino и Python3.

Аrduino магия

Схема подключения и скетч честно взяты без изменений из мануала Arduino kit, скачанного с сайта производителя.

Cкетч

/*  Arduino Advanced Kit example  Project 11 - IRRemote  * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv  * An IR detector/demodulator must be connected to the input RECV_PIN.  * Version 0.1 July, 2009  * Copyright 2009 Ken Shirriff  * http://arcfn.com  */ #include <IRremote.h>  int RECV_PIN = 7; IRrecv irrecv(RECV_PIN); decode_results results;  void setup() {     Serial.begin(9600);     irrecv.enableIRIn(); // Start the receiver }  void loop() {     if (irrecv.decode(&results)) {         Serial.println(results.value,HEX); // print received values         irrecv.resume(); // Receive the next value   } } 

В итоге, на монитор порта нам приходят коды нажатых клавиш. Опытным путем было выяснено, что подходят разные ИК-пульты. Хотя это известный факт, но для меня это было в новинку. А вот дальше интереснее. VLC media player имеет удобный web-интерфейс. И управлять им можно посредством обычных http-get запросов вида:

«host:port/page.html?var=value&var2=value2&…»

Более подробную информацию можно найти на videolan.org.

Python3 магия

Используя Python3 и его богатые библиотеки, возможно как посылать http-requests, так и считывать данные с serial port. Этого оказалось достаточно для исполнения моей задумки. Скрипт на Python3 написан с использованием ООП подхода.

Вкратце работа скрипта состоит в следующем:

1. Создаем экземпляр класса vlc_remote_contol, в конструктор передаем адрес нашего Vlc player, список с кодами клавиш, и имя виртуального сom порта.
2. Вызываем метод control в котором происходит считывание с порта кода клавиши.
3. Код клавиши передается в метод __switch_button. где вызывается метод __command с определенными параметрами
4. __command непосредственно осуществляет get запрос к VLC player.

Скрипт

import getpass import time  import subprocess import requests import serial import sys import lxml.etree as etree  class vlc_remote_contol:     def __init__(self,hst,blist,pname):         self.host = hst         self.btn_list = blist         self.port = serial.Serial(pname, 9600, timeout = 0)         self.__sess = requests.Session()         self.__sess.auth = ('',getpass.getpass())         self.old_vol = self.__get_param(self.__sess.get(self.host+'/requests/status.xml').text, 'volume')         self.curr_vol = 0 	     def  __get_param(self,info,param):         beg = info.find('<'+param+'>')+len('<'+param+'>')         end = info.find('</'+param+'>')         return int(info[beg:end])              def  __command (self,host,comm,val):         if (val == ''):             req = self.__sess.get(host+'/requests/status.xml'+'?'+'command='+comm)         else:             req = self.__sess.get(host+'/requests/status.xml'+'?'+'command='+comm+'&val='+val)         req.close()              def  __switch_button(self,btn_code):         if (btn_code == 'FFC23D'):   ## play/pause             self.__command(self.host,'pl_pause','')         elif (btn_code == 'FF906F'): ## fullscreen             self.__command(self.host,'fullscreen','')         elif (btn_code == 'FFE01F'): ## volume down             self.__command(self.host,'volume','-10')         elif (btn_code == 'FFA857'): ## volume up             self.__command(self.host,'volume','+10')         elif (btn_code == 'FF22DD'): ## rewind back             self.__command(self.host,'seek','-0.5%')         elif (btn_code == 'FF02FD'): ## rewind forward             self.__command(self.host,'seek','+0.5%')         elif (btn_code == 'FFA25D'): ## previous track             self.__command(self.host,'pl_previous','')         elif (btn_code == 'FFE21D'): ## previous next             self.__command(self.host,'pl_next','')         elif (btn_code == 'FF6897'): ## mute             self.cur_vol = self.__get_param(self.__sess.get(self.host+'/requests/status.xml').text, 'volume')             if (self.cur_vol  == 0):                 self.__command(self.host,'volume',str(self.old_vol))             else:                 self.old_vol = self.cur_vol                 self.__command(self.host,'volume','0')         else:             pass      def control(self):         print('Success')         while True:             res = self.port.readline().strip().decode("UTF-8")             if (res in self.btn_list):                 self.__switch_button(res)          def main():     conf = etree.parse('conf.xml')     vpath = conf.xpath('/document/vpath/text()')[0]     vhost = conf.xpath('/document/vhost/text()')[0]     try:         subprocess.Popen([vpath])     except:         input('VLC player not found')         return      try:         buttons0 = ['FFA25D','FF629D','FFE21D','FF22DD','FF02FD','FFC23D','FFE01F','FFA857','FF906F','FF6897',                 'FF9867','FFB04F','FF30CF', 'FF18E7','FF7A85','FF10EF','FF38C7','FF5AA5','FF42BD','FF4AB5', 'FF52AD']         vrc = vlc_remote_contol(vhost,buttons0,"COM3")          vrc.control()     except:         input("Connection or authorization error.")         return  if  __name__ ==  "__main__" :      main() 

Заключение

Я понимаю, что не придумал ничего оригинального и нового. Это мой первый опыт в промышленном программировании, до этого были только лабораторные работы в Университете и решение олимпиадных задач. Жду от сообщества конструктивной критики и советов по улучшению скрипта. Пока в планах добавить коды клавиш в сonf.xml файл, что было использовать другие пульты, и возможно простой графический интерфейс.

Все исходники опубликованы на GitHub.

ссылка на оригинал статьи http://habrahabr.ru/post/232401/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *