Spoofer IR per decoder TV

Problema da risolvere: genitori che si dimenticano di spegnere il decoder quando spengono la TV

Soluzione? Uno spoofer sul ricevitore infrarossi del decoder che, alla ricezione del comando per accendere/spegnere la TV, inietta al decoder il suo comando di accensione/spegnimento.

Materiale necessario:

  • Per lo spoofer: un microcontrollore Attiny85, un socket DIP8, un jack audio 3.5mm maschio
  • Per la programmazione: una scheda Arduino Uno (o simili), un ricevitore infrarosso, una breadboard e relativi cavetti di collegamento

Veniamo al sodo: i telecomandi infrarosso trasmettono una serie di impulsi, modulati tipicamente a 38 kHz, che trasportano alcuni byte di informazione e che i dispositivi comandati interpretano, agendo di conseguenza. Esistono diversi protocolli di trasmissione, ma la libreria IRRemote di Arduino è in grado di gestirne la maggior parte.

Il ricevitore infrarosso è un componente che riceve il segnale modulato, e lo invia demodulato su una singola linea open-drain. Il decoder in questione ha un ingresso per un ricevitore IR esterno, che è collegato come in figura, ossia in parallelo al ricevitore interno.

Schematico del circuito

Questo ci permette di collegare direttamente un microcontrollore (ho scelto un Attiny85 perchè è piccolo, facile da saldare dato il package DIP e ha sufficiente memoria per lo sketch) alla medesima linea del segnale: esso potrà quindi “ascoltare” la ricezione infrarossa demodulata e, al momento della ricezione del comando “accendi/spegni TV”, che viene ignorato dal decoder, può iniettare sulla medesima linea il corrispondente elettrico del segnale “accendi/spegni decoder”. Inoltre, non si invalida alcuna garanzia perchè non è necessario aprire il decoder o modificarlo in alcun modo: il jack ci fornisce tutto il necessario!

Dopo aver discusso lo schematico, passiamo al codice: ci servirà una scheda Arduino Uno (o qualunque altro Arduino, in realtà) a cui collegare un altro ricevitore infrarosso per capire i due segnali che ci servono: “accendi/spegni TV” e “accendi/spegni decoder”. Per farlo possiamo usare l’esempio “IRrecvDump” collegando un ricevitore infrarosso al pin 11, alimentandolo da +5V e GND della scheda Arduino. Carichiamo lo sketch, apriamo il monitor seriale e premiamo il tasto sul telecomando che ci interessa: il microcontrollore ci dirà il protocollo di codifica, il comando e il numero di bit (“Decoded NEC: 807F807F (32 bits)” e “Decoded NEC: 20DF10EF (32 bits)” nel mio caso, per il tasto di accensione della TV e del decoder, rispettivamente). Prendiamone nota.

A questo punto possiamo passare al codice per l’Attiny: seguiamo questa guida selezionando però un clock “16 MHz internal” per l’Attiny. Scarichiamo inoltre la libreria tiny_IRremote e mettiamola nella cartella delle librerie di Arduino per poterla utilizzare. Riavviare la IDE per renderla disponibile e utilizziamo il codice seguente:

#include <tiny_IRremote.h>

#define NEC_BITS          32
#define NEC_HDR_MARK    9000
#define NEC_HDR_SPACE   4500
#define NEC_BIT_MARK     560
#define NEC_ONE_SPACE   1690
#define NEC_ZERO_SPACE   560
#define NEC_RPT_SPACE   2250

int RECV_PIN = 3;
int TX_PIN = RECV_PIN;

IRrecv irrecv(RECV_PIN);

void sendwire(unsigned long data,  int nbits) {

  pinMode(TX_PIN, OUTPUT);
  noInterrupts();
  //Header
  digitalWrite(TX_PIN, 0);
  delayMicroseconds(NEC_HDR_MARK);
  digitalWrite(TX_PIN, 1);
  delayMicroseconds(NEC_HDR_SPACE);

  //data
  for (unsigned long  mask = 1UL << (nbits - 1);  mask;  mask >>= 1) {
    if (data & mask) {
      digitalWrite(TX_PIN, 0);
      delayMicroseconds(NEC_BIT_MARK);
      digitalWrite(TX_PIN, 1);
      delayMicroseconds(NEC_ONE_SPACE);
    } else {
      digitalWrite(TX_PIN, 0);
      delayMicroseconds(NEC_BIT_MARK);
      digitalWrite(TX_PIN, 1);
      delayMicroseconds(NEC_ZERO_SPACE);
    }
  }

  //Footer

  digitalWrite(TX_PIN, 0);
  delayMicroseconds(NEC_BIT_MARK);
  digitalWrite(TX_PIN, 1);
  interrupts();
  pinMode(TX_PIN, INPUT);
}

decode_results results;

unsigned long last = 0;
unsigned armed = 0;

void setup()
{
  pinMode(RECV_PIN, INPUT);
  irrecv.enableIRIn(); // Start the receiver
}

void loop() {
  if (irrecv.decode(&results)) {
    last = millis();
    if (results.decode_type == NEC)
  //change according to your remote
      if (results.value == 0x20DF10EF ) {
 //change according to your remote
        armed = 1;
delay(500);
      }
    irrecv.resume(); // Receive the next value
  }
  else {
    if (armed == 1)
      if ((millis()-last) > 500) {
        sendwire(0x807F807F, 32);
 //change according to your remote
        irrecv.enableIRIn(); // Restart the receiver
        irrecv.resume();
        armed = 0;
      }
  }
  delay(100);
}

L’attiny resta in ascolto del segnale infrarosso e, quando protocollo e dato corrispondono al segnale di accensione della TV, il nostro microcontrollore si arma e si prepara a trasmettere il comando di accensione al decoder. Notare che per trasmettere il codice utilizzeremo lo stesso pin che usiamo per la ricezione: aspettiamo quindi 500 ms dall’ultima ricezione prima di trasmettere, tramite “if ((millis()-last) > 500)”. Inoltre, non utilizziamo la funzione “irsend” perchè questa trasmetterebbe un segnale modulato, che andrebbe bene per pilotare un LED infrarosso ma non la linea digitale, dove invece vogliamo il segnale demodulato.

Per trasmettere quindi il segnale demodulato con protocollo NEC sono partito dal file “ir_NEC.cpp” della libreria IRremote, dove si capisce che la trasmissione avviene alternando un ‘1’ di durata NEC_BIT_MARK ad uno zero di durata differente per un ‘1’ e uno ‘0’ digitali (NEC_ONE_SPACE, NEC_ZERO_SPACE”). Quindi ho scritto la funzione sendwire che scrive direttamente ‘1’ e ‘0’ per la durata necessaria sul pin del microcontrollore connesso alla linea di segnale. Notare che, essendo una linea open drain, ‘1’ logico corrisponde alla linea abbassata, quindi la logica è negata.

Per altri protocolli dovreste prendere il rispettivo file ir_PROTCOLLO.cpp (che trovate nella libreria “IRremote”) e riscrivere la vostra funzione di trasmissione. Non è particolarmente complicato: utilizzate i comandi “noInterrupts()” e “interrupts()” rispettivamente ad inizio e fine funzione, perchè altrimenti le tempistiche sono sballate e il segnale non viene trasmesso correttamente.

Programmiamo il nostro Attiny e saldiamolo al nostro jack audio maschio con un accrocchio del genere: (io ho utilizzato un socket per permettermi di rimuovere facilmente il microcontrollore per riprogrammarlo).

L’intero circuito saldato sul jack, in modo molto artigianale. Ho lasciato volutamente “lungo” un terminale del jack per facilitare l’estrazione del jack dal decoder tramite una pinza.

Se tutto va bene, alla pressione del tasto di accensione/spegnimento del TV, anche il decoder si accenderà/spegnerà “magicamente”.

Consiglio di isolare il circuito tramite del nastro isolante, del termorestringente, abbondante colla a caldo o una piccola scatola stampata in 3D.

Nota: IL SITO E L’AUTORE NON SI ASSUMONO ALCUNA RESPONSABILITA’ IN CASO DI DANNI DERIVANTI DALLA REALIZZAZIONE E DALL’IMPIEGO DEL CIRCUITO QUI RIPORTATO. LA GUIDA E’ DA CONSIDERARSI A SCOPO PRETTAMENTE DIDATTICO.