Bateu um tédio, pouco serviço pra fazer, e oque precisa ser feito é muito chato. Resolvi fazer um projeto que estava muito tempo na fila: utilizar um controle remoto para controlar um computador que uso no rádio e tv. Da muita preguiça chato ter ir até o computador para mudar de música, pausar o filme no netflix, ou outra coisa qualquer.
O projeto é simples, utiliza um arduino UNO, um controle remoto que estava sobrando - da propria TV, uma panasonic, e um receptor de IR manjado ( TSOP4838 ). O arduino interpreta o sinal vindo do TSOP4838, comunica pelo USB com o computador, e um programa em python converte isso para comandos em Linux.
O hardware não tem nada demais, é o receptor de IR espetado no arduino. Coloquei tudo dentro de um copo do starbuck para não ficar dando curto com o resto dos equipamentos que estão no rack da tv.
O programa utilizado no Arduino é baseado num dos exemplos disponíves com a biblioteca IRremote. Foi adicionado código para lidar coma alimentação do sensor (pino 12 = GND e pino 13 = VCC), e tudo oque era descenessário foi retirado. No meu caso tive sorte do protocolo do controle remoto que eu tinha ser suportado pela biblioteca. No meu caso o protocolo utilizado é o PANASONIC.
Esse programa retorna um número hexadecimal para cada tecla do controle. Mapeando a função com cada código retornado é feito um mapa do controle remoto. Neste controle da Panasonic algumas teclas mandam o mesmo código 3 vezes, geralmente as teclas que vc não que que fique repetindo, como play/pause e outras. As demais teclas com volume ficam mandando o código periodicamente enquanto o botão é apertado.
Interpretador em python
Programa python para recepção dos dados. Utiliza biblioteca pySerial e a ferramenta xdotool. Utilizo o python3. O programa acabou ficando mais complicado que o previsto inicialmente porque o receptor pega um pouco de ruído e envia alguns códigos incorretos. O software também gera uma movimentação não linear para o ponteiro do mouse, ou seja, começa devagar e vai movendo cada vez mais rápido, isso torna o controle pelo controle remoto mais fluido. O código esta bastante comentado.
# Recepção de control remoto
import time
import serial
import os
VERSION = "0.1"
SERIAL_PORT = "/dev/ttyACM0"
BAUD_RATE = 9600
REPEATABLE = True
NOT_REPEATABLE = False
UNKNOW_COMMAND = '??'
NO_COMMAND = ''
NO_DESCRIPTION = ''
NO_IR_CODE = -1
#Lista de relacao entre codigo IR e comando linux. Formato [Codigo IR, Comando Linux, Descricao, Pode Repetir?]
command_list = [
['E17AF807','amixer -q -D pulse sset Master toggle','mute',NOT_REPEATABLE],
['BE3BB37','xdotool key XF86AudioRaiseVolume','aumenta volume',REPEATABLE],
['D4D9F2A7','xdotool key XF86AudioLowerVolume','baixa volume',REPEATABLE],
['21035431','xdotool mousemove_relative -- %MOUSE_MOVE 0','seta para direita',REPEATABLE],
['983AB4C1','xdotool mousemove_relative -- -%MOUSE_MOVE 0','seta para esquerda',REPEATABLE],
['C20370A1','xdotool mousemove_relative -- 0 -%MOUSE_MOVE','seta para cima',REPEATABLE],
['81930A09','xdotool mousemove_relative -- 0 %MOUSE_MOVE','seta para baixo',REPEATABLE],
['BB0ED9E1','xdotool click 1; sleep 0.2','ok',NOT_REPEATABLE],
['AA7B2167','xdotool key XF86AudioPlay','play',NOT_REPEATABLE],
['2E8C2A89','xdotool key XF86AudioNext','fwd',NOT_REPEATABLE],
['1F6E01C9','xdotool key XF86AudioPrev','rew',NOT_REPEATABLE],
['1D15F4D7','xdotool key XF86AudioStop','stop',NOT_REPEATABLE],
['406A954D','systemctl poweroff -i','desliga',NOT_REPEATABLE],
['E17A24DB','xset dpms force off; sleep 1','apaga tv',NOT_REPEATABLE],
['E17A18E7','xdotool key C; sleep 1','apaga tv',NOT_REPEATABLE],
['E17A7887','xdotool getwindowfocus getwindowname;sleep 1','pega nome janela em foco',NOT_REPEATABLE],
['A26409C9','pkill --oldest chrome; google-chrome-stable deezer.com/br/ & sleep 1','Abre pagina deezer',NOT_REPEATABLE],
['240C9161','pkill --oldest chrome; google-chrome-stable www.netflix.com & sleep 1','Abre pagina netflix',NOT_REPEATABLE],
['68E839F1','pkill --oldest chrome; google-chrome-stable www.youtube.com & sleep 1','Abre pagina youtube',NOT_REPEATABLE],
['ABBE1086','xdotool key Escape','esc',NOT_REPEATABLE],
['68E69B7F','xdotool click 4','scrool up',REPEATABLE],
['223C02A7','xdotool click 5','scrool down',REPEATABLE]
]
#Codigo q corresponde a tecla repetida do IR. Tecla ainda esta apertada
button_down = 'FFFFFFFF'
#inicializa para evitar possivel chamada dessa variavel sem inicilizacao
linux_command = NO_COMMAND
last_command = NO_COMMAND
description = NO_DESCRIPTION
allow_repeat = NOT_REPEATABLE
repetition_count=0
last_ir_code = NO_IR_CODE
ir_code = NO_IR_CODE
#tempo max para interpretar que a tecla foi solta
IR_TIMEOUT = 0.3
#sinaliza q tecla esta pressionada desde ultima vez
pressed = False
#Maximo deslocamento do mouse
max_mouse = 35
# Hello message
print("Controle Remoto Arduino/Linux TabaJairo para controle Panasonic")
print("Versao: " + VERSION);
# Tenta conectar a serial
serial_connected = False
print("Procurando porta serial...")
while (not serial_connected):
try:
ser = serial.Serial(port=SERIAL_PORT,baudrate=BAUD_RATE, timeout=1)
serial_connected = True
print("yeah...achei")
except:
print("buuu...ainda não achei")
time.sleep(1)
#Loop infinito - ctrl+c para terminar
while 1 :
#Recebe ir code. Aguarda enquanto nao tem nada na serial
last_ir_code = ir_code
t = 0
while ser.inWaiting() == 0:
time.sleep(0.1)
t = t + 0.1
if t > IR_TIMEOUT:
t=0
#limpa ultimo codigo pois estourou timeout
last_ir_code = NO_IR_CODE
out = ser.readline().rstrip()
ir_code = out.decode('utf-8')
#Procura comando na lista
#Coloca NO_COMMAND em linux_command para indicar q nao foi encontrado
linux_command = NO_COMMAND
for command in command_list:
if ir_code == command[0]:
linux_command = command[1]
description = command[2]
allow_repeat = command[3]
# Se teve timeout na recepcao do codigo IR entao o ultimo comando eh vazio
if last_ir_code == NO_IR_CODE:
last_command = NO_COMMAND
pressed = False
#Verifica se eh comando repetido (tecla pressionada)
if (linux_command == last_command) and (last_ir_code != NO_IR_CODE):
pressed = True
# Aqui tem um truque para melhor responsividade: se o comando atual nao eh reconhecido e
# nao teve timeout na recepcap de IR supoe que houve problema na recepcao do codigo:
# o codigo eh diferente mas corresponde a ultima tecla pressionada
if (linux_command == NO_COMMAND) and (last_ir_code != NO_IR_CODE) and (last_command != NO_COMMAND):
pressed = True
linux_command = last_command
print("Codigo IR invalido! Provavelmente eh o ultimo comando, vamos repetir...");
# Incrementa contador de botao pressionado
if pressed:
repetition_count+=1
else:
repetition_count=0
# Atualiza last command. A posicao da linha eh importante para o codigo funcionar
last_command = linux_command
#subsitui wildcard %MOUSE_MOVE do movimento do mouse para fazer aceleracao
mouse_move = repetition_count*repetition_count+1;
if mouse_move > max_mouse:
mouse_move = max_mouse
linux_command = linux_command.replace("%MOUSE_MOVE",str(mouse_move))
#executa comando se for conhecido. Verifica se ele pode ser repetido ou nao.
# Nao queremos o play/pause repetindo, nem o mute por exemplo
if linux_command != NO_COMMAND:
if repetition_count == 0 or (repetition_count > 0 and allow_repeat):
print(ir_code + ' ' + str(repetition_count) + ' --> ' + description + ' --> ' + linux_command);
os.system(linux_command)
else:
print(ir_code + ' ' + str(repetition_count) + ' --> ' + description + ' --> nao pode repetir');
else:
print(ir_code + ' ' + str(repetition_count) + ' --> buuu, nao conheco esse comando ');
O programa monitor a porta serial /dev/ttyACM0 na qual o arduino esta conectada. Sempre que recebe um comando serial ele dispara o correspondente no linux. A ferramente xdotool permite simular o mouse e teclado, e com isso é possivel enviar comandos como aumentar/baixa volume pelas teclas especiais de volume, play/pause etc. Também é possível utilizar diretamente outros comandos do linux, como por exemplo desligar a tela ou fazer shutdown da máquina.
No exemplo acima estão comandos diretos no linux, comandos que simulam teclado ( xdotool key ... ) e comandos que simulam mouse (xdotool mousemove_relative e click ) .
Na figura acima esta uma amostra do programa recebendo os códugos. O primeiro campo é o código recebido pela IR, depois o numero de repetições, uma descrição do código, e o comando executado no linux.
Para algumas teclas do controle é simulado o uso de teclas de multimedia (volume, play, stop por exemplo), barra de rolagem do mouse, ou é executado algum comando específico, como desligar o sistema.
Ajuste do navegador
Foi encontrado um problema inesperado durante esse projeto: os navegadores de internet de forma geral não aceitam as teclas de acesso rápido multimidia (play, pause, stop...). Para fazer isso funcionar é necessário instalar um plugin no navegador. Não tive sucesso ao utilizar isso no firefox - o plugin não funcionava. No chrome o plugin funcionou corretamente e agora consigo controlar sites de musica, youtube e netflix com o controle remoto.
Falta deixar claro que estamos simulando tecla de atalho multimidia, que é possivel encontra em alguns teclado reais. Existe o padrão XF86 que são as telcas multimidia. Existe diferentes funções que podem ser acessadas com essas teclas.
Recepção Arduino
A comunicação com o Arduino é feita pela USB. Se o sistema não estiver encontrado o arduino verifique o nome da porta que o arduino esta instalado e corrija no programa de recepção em python. Também verifique se o acesso a USB esta liberado. Falta de acesso é um problema comum com o Arduino, existe bastane informação sobre isso na internet.