Hackster is hosting Hackster Holidays, Ep. 5: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 5 on Friday!
BuddyC
Published © GPL3+

WiFi IR Blaster

A connected universal remote.

IntermediateFull instructions provided3 hours135,580
WiFi IR Blaster

Things used in this project

Hardware components

ESP8266 ESP-01
Espressif ESP8266 ESP-01
You could do this with a standard ESP8266 instead or the NodeMCU development kit
×1
Arduino Nano R3
Arduino Nano R3
×1
General Purpose Transistor NPN
General Purpose Transistor NPN
×1
Adafruit IR LEDs
×1

Software apps and online services

Arduino IDE
Arduino IDE
NodeMCU firmware
NodeMCU firmware

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

Simple Schem

Nothing really to it, just power and a single pin connected to an NPN transistor to drive two IR LEDs in series (with no resistors) off the 5v supply voltage.

Adding LEDs

If you want to run additional LEDs or need less voltage drop from a 3.3v source, you can use a NPN transistor to switch multiple PNP transistors (one per LED). This configuration allows you to use as many LEDs as your source voltage can supply current for.

Code

WiFi IR Blaster for ESP8266 Arduino Sketch

C/C++
You'll need the ESP8266 wifi library and IRremote.h. You should also opt to not use the Raw IR codes if your remote is supported in the library. I adapted this sketch from an air conditioner controller I built that used non-standard IR codes.
/*
 * WiFi IR Blaster by Buddy Crotty
 *  Use an ESP8266 module or dev board to receive HTTP GET request
 *  and then send IR codes to an attached IR LED based on those requests.
 *  This works best with another web server acting as a front end that 
 *  sends cURL requests based on which buttons are pressed. 
 *  cURL format: http://ESP8266/IRcode
 */

#include <ESP8266WiFi.h>
#include <IRremoteESP8266.h>
#include <ESP8266mDNS.h>

const char* ssid = "AP_SSID";
const char* password = "AP_Pass";
MDNSResponder mdns;

int khz = 38; // 38kHz carrier frequency for both NEC and Samsung

IRsend irsend(4); //an IR led is connected to GPIO4 (pin D2 on NodeMCU)

  // Insert RAW IR signal for "TV Power"
unsigned int irTVpwr[] = {4650,4250, 700,1550, 650,1550, 700,1550, 650,450, 650,500, 600,500, 600,500, 600,550, 550,1700, 550,1650, 600,1650, 550,550, 600,500, 600,550, 550,550, 600,500, 600,550, 550,1650, 600,550, 550,550, 600,500, 600,550, 550,550, 600,500, 600,1650, 600,500, 600,1650, 550,1700, 550,1650, 600,1650, 550,1650, 600,1650, 600};  // SAMSUNG E0E040BF

  // Insert RAW IR signal for "TV Source"
unsigned int irTVsrc[] = {4600,4300, 700,1550, 650,1550, 650,1600, 650,450, 650,450, 600,550, 550,550, 600,500, 600,1650, 550,1650, 600,1650, 550,550, 600,500, 600,550, 550,550, 550,550, 600,1650, 550,550, 550,550, 600,500, 600,500, 600,550, 550,550, 600,500, 600,550, 550,1650, 550,1700, 550,1650, 600,1600, 600,1650, 600,1600, 600,1650, 550};  // SAMSUNG E0E0807F
  
  // Insert RAW IR signal for "TV Mute"
unsigned int irTVmute[] = {4650,4250, 700,1550, 650,1550, 700,1550, 650,450, 650,500, 600,500, 600,500, 600,500, 600,1650, 600,1600, 600,1650, 550,550, 600,500, 600,550, 550,550, 600,500, 600,1650, 550,1650, 600,1650, 550,1650, 600,550, 550,550, 550,550, 600,500, 600,550, 550,550, 550,550, 600,500, 600,1650, 550,1650, 600,1650, 550,1650, 600};  // SAMSUNG E0E0F00F
  
  // Insert RAW IR signal for "TV Volume Down"
unsigned int irTVvdn[] = {4650,4250, 700,1550, 650,1550, 700,1550, 650,450, 650,450, 650,450, 600,550, 550,550, 600,1650, 550,1650, 550,1650, 600,550, 550,550, 550,550, 600,500, 600,500, 600,1650, 600,1600, 600,500, 600,1650, 550,550, 600,500, 600,500, 600,550, 550,550, 600,500, 600,1650, 550,550, 550,1650, 600,1650, 550,1650, 600,1650, 550};  // SAMSUNG E0E0D02F
  
  // Insert RAW IR signal for "TV Volume Up"
unsigned int irTVvup[] = {4600,4300, 650,1600, 650,1550, 650,1600, 600,500, 600,550, 600,500, 600,550, 550,550, 550,1700, 550,1650, 600,1650, 550,550, 600,500, 600,550, 550,550, 600,500, 600,1650, 600,1650, 550,1650, 600,550, 550,550, 600,500, 600,550, 550,550, 600,500, 600,550, 550,550, 600,1600, 600,1650, 600,1650, 550,1650, 600,1650, 600};  // SAMSUNG E0E0E01F
  
  // Insert RAW IR signal for "TV Channel Up"
unsigned int irTVchup[] = {4650,4250, 700,1550, 650,1600, 650,1550, 650,500, 600,500, 600,500, 650,500, 600,500, 600,1650, 550,1650, 600,1650, 600,500, 600,500, 600,550, 550,550, 600,550, 550,550, 550,1650, 600,550, 600,500, 600,1650, 550,550, 600,500, 600,550, 550,1650, 600,550, 550,1650, 600,1650, 600,500, 600,1650, 600,1600, 600,1650, 600};  // SAMSUNG E0E048B7
  
  // Insert RAW IR signal for "TV Channel Down"
unsigned int irTVchdn[] = {4600,4350, 650,1550, 650,1600, 650,1600, 600,500, 600,500, 600,550, 550,550, 600,550, 550,1650, 600,1650, 550,1700, 550,550, 550,550, 600,500, 600,550, 550,550, 600,500, 600,550, 550,550, 550,550, 600,1650, 600,500, 600,500, 600,550, 550,1650, 600,1650, 600,1650, 550,1650, 600,550, 550,1650, 600,1650, 600,1650, 550};  // SAMSUNG E0E008F7
  
  // Insert RAW IR signal for "Receiver Power"
unsigned int irRECpwr[] = {9050,4350, 650,500, 600,1600, 600,500, 650,500, 600,1600, 600,550, 600,1600, 600,1650, 550,550, 600,500, 600,1600, 650,1600, 600,500, 600,1650, 600,1600, 600,500, 600,1650, 600,1600, 600,550, 600,1600, 600,500, 600,550, 600,1600, 600,1600, 650,500, 600,500, 600,1600, 650,500, 600,1600, 600,1650, 600,500, 600,500, 600};  // NEC 4B36D32C

  // Insert RAW IR signal for "Receiver Power On"
unsigned int irRECpwrON[] = {9000,4400, 600,550, 600,1600, 600,500, 600,550, 600,1600, 600,500, 600,1600, 650,1600, 600,1600, 600,500, 650,1600, 600,1600, 600,500, 650,1600, 600,1600, 600,500, 600,550, 600,500, 600,1600, 600,550, 600,500, 600,500, 650,500, 600,500, 600,1600, 650,1600, 600,500, 600,1600, 650,1600, 600,1600, 600,1600, 600,1600, 650};  // NEC 4BB620DF
  
  // Insert RAW IR signal for "Receiver Power Off"
unsigned int irRECpwrOFF[] = {9000,4400, 600,550, 550,1650, 600,550, 550,550, 600,1650, 550,550, 600,1650, 550,1650, 600,550, 550,550, 550,1650, 600,1650, 600,550, 550,1650, 600,1650, 550,550, 600,1650, 550,1650, 600,1650, 600,500, 600,550, 550,550, 600,1650, 550,550, 600,500, 600,550, 550,550, 550,1700, 550,1650, 600,1650, 550,550, 600,1650, 550};  // NEC 4B36E21D

  // Insert RAW IR signal for "Receiver Mute"
unsigned int irRECmute[] = {9000,4400, 650,450, 650,1600, 600,500, 600,500, 650,1600, 600,500, 600,1650, 600,1600, 600,1600, 650,500, 600,1600, 650,1600, 600,500, 600,1600, 650,1600, 600,500, 600,1650, 600,500, 600,1600, 650,500, 600,500, 600,500, 600,500, 650,500, 600,500, 600,1600, 650,500, 600,1600, 600,1600, 650,1600, 600,1650, 600,1600, 600};  // NEC 4BB6A05F
  
  // Insert RAW IR signal for "Receiver Volume Down"
unsigned int irRECvdn[] = {9150,4250, 750,350, 700,1550, 700,400, 700,450, 650,1550, 700,450, 600,1600, 650,1600, 600,1650, 600,500, 600,1650, 600,1600, 600,550, 600,1600, 600,1650, 600,500, 600,1650, 600,1600, 650,500, 600,500, 600,500, 650,500, 600,500, 600,500, 600,550, 600,500, 600,1650, 600,1600, 600,1650, 600,1650, 600,1600, 600,1650, 600};  // NEC 4BB6C03F
  
  // Insert RAW IR signal for "Receiver Volume Up"
unsigned int irRECvup[] = {9050,4400, 650,500, 600,1600, 600,550, 600,500, 600,1650, 600,500, 600,1600, 650,1600, 600,1600, 600,550, 600,1600, 600,1600, 650,500, 600,1600, 650,1600, 600,500, 600,550, 600,1600, 600,550, 600,500, 600,550, 600,500, 600,550, 600,500, 600,1600, 650,500, 600,1600, 600,1650, 600,1600, 600,1650, 600,1600, 600,1600, 600};  // NEC 4BB640BF

  // Insert RAW IR signal for "Receiver Source CBL/SAT"
unsigned int irRECsrc[] = {8950,4450, 600,500, 600,1650, 600,500, 600,500, 600,1650, 600,500, 600,1600, 600,1650, 600,1600, 600,550, 600,1600, 600,1650, 600,500, 600,1600, 600,1650, 600,500, 600,500, 600,1650, 600,1600, 600,1650, 600,500, 600,500, 600,500, 650,500, 600,1600, 600,500, 600,550, 600,500, 600,1600, 600,1650, 600,1600, 600,1650, 600};  // NEC 4BB6708F

// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);


void setup() {
  Serial.begin(115200);
  delay(10);

  irsend.begin();
  
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi Connected");

  // Start the server
  server.begin();
  Serial.println("HTTP Server Started");

  // Print the IP address
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  if (mdns.begin("IRBlasterLR", WiFi.localIP())) {
    Serial.println("MDNS Responder Started");
  }

  Serial.println();
  Serial.println();
}

void loop() {
  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
  
  // Wait until the client sends some data
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
  
  // Read the first line of the request
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();
  
  // Match the request
  if (req.indexOf("/irTVpwr") != -1){
      irsend.sendRaw(irTVpwr, sizeof(irTVpwr) / sizeof(irTVpwr[0]), khz);   
      Serial.println("IRreq irTVpwr sent");
  }
  else if (req.indexOf("/irTVsrc") != -1){
      irsend.sendRaw(irTVsrc, sizeof(irTVsrc) / sizeof(irTVsrc[0]), khz);   
      Serial.println("IRreq irTVsrc sent");
  }
  else if (req.indexOf("/irTVmute") != -1){
      irsend.sendRaw(irTVmute, sizeof(irTVmute) / sizeof(irTVmute[0]), khz);   
      Serial.println("IRreq irTVmute sent");
  }
  else if (req.indexOf("/irTVvdn") != -1){
      irsend.sendRaw(irTVvdn, sizeof(irTVvdn) / sizeof(irTVvdn[0]), khz);   
      Serial.println("IRreq irTVvdn sent");
  }
  else if (req.indexOf("/irTVvup") != -1){
      irsend.sendRaw(irTVvup, sizeof(irTVvup) / sizeof(irTVvup[0]), khz);   
      Serial.println("IRreq irTVvup sent");
  }
  else if (req.indexOf("/irTVchup") != -1){
      irsend.sendRaw(irTVchup, sizeof(irTVchup) / sizeof(irTVchup[0]), khz);   
      Serial.println("IRreq irTVchup sent");
  }
  else if (req.indexOf("/irTVchdn") != -1){
      irsend.sendRaw(irTVchdn, sizeof(irTVchdn) / sizeof(irTVchdn[0]), khz);   
      Serial.println("IRreq irTVchdn sent");
  }
  else if (req.indexOf("/irALLpwr") != -1){
      irsend.sendRaw(irRECpwrON, sizeof(irRECpwrON) / sizeof(irRECpwrON[0]), khz);   
      irsend.sendRaw(irTVpwr, sizeof(irTVpwr) / sizeof(irTVpwr[0]), khz);   
      delay(2000);
      irsend.sendRaw(irRECsrc, sizeof(irRECsrc) / sizeof(irRECsrc[0]), khz);         
      Serial.println("IRreq irALLpwr sent");
  }
  else if (req.indexOf("/irRECpwr") != -1){
      irsend.sendRaw(irRECpwr, sizeof(irRECpwr) / sizeof(irRECpwr[0]), khz);   
      Serial.println("IRreq irRECpwr sent");
  }
  else if (req.indexOf("/irRECpwrON") != -1){
      irsend.sendRaw(irRECpwrON, sizeof(irRECpwrON) / sizeof(irRECpwrON[0]), khz);   
      Serial.println("IRreq irRECpwrON sent");
  }
  else if (req.indexOf("/irRECpwrOFF") != -1){
      irsend.sendRaw(irRECpwrOFF, sizeof(irRECpwrOFF) / sizeof(irRECpwrOFF[0]), khz);   
      Serial.println("IRreq irRECpwrOFF sent");
  }
  else if (req.indexOf("/irRECmute") != -1){
      irsend.sendRaw(irRECmute, sizeof(irRECmute) / sizeof(irRECmute[0]), khz);   
      Serial.println("IRreq irRECmute sent");
  }  
  else if (req.indexOf("/irRECvdn") != -1){
      irsend.sendRaw(irRECvdn, sizeof(irRECvdn) / sizeof(irRECvdn[0]), khz);   
      Serial.println("IRreq irRECvdn sent");
  }
  else if (req.indexOf("/irRECvup") != -1){
      irsend.sendRaw(irRECvup, sizeof(irRECvup) / sizeof(irRECvup[0]), khz);   
      Serial.println("IRreq irRECvup sent");
  } 
  else {
    Serial.println("invalid request");
    client.stop();
    return;
  }
  
  client.flush();
   
  // Send the response to the client
  //client.print(s);
  client.print("HTTP/1.1 200 OK\r\n");
  delay(1);
  Serial.println("Client Disconnected");
  Serial.println();
  // The client will actually be disconnected 
  // when the function returns and 'client' object is detroyed
}

script.js

JavaScript
javascript for webapp (requires jquery)
// Function to send IR commands
function buttonClick(clicked_id){

    if (clicked_id == "irTVpwr"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irTVpwr"} );  
    } 

    if (clicked_id == "irTVsrc"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irTVsrc"} );  
    } 

    if (clicked_id == "irTVmute"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irTVmute"} );  
    } 

    if (clicked_id == "irTVvdn"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irTVvdn"} );  
    } 

	if (clicked_id == "irTVvup"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irTVvup"} );  
    } 
	
    if (clicked_id == "irTVchup"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irTVchup"} );  
    } 

	if (clicked_id == "irTVchdn"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irTVchdn"} );  
    } 
	
    if (clicked_id == "irRECpwr"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irRECpwr"} );  
    } 

    if (clicked_id == "irALLpwr"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irALLpwr"} );  
    } 

	if (clicked_id == "irRECpwrON"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irRECpwrON"} );  
    } 

	if (clicked_id == "irRECpwrOFF"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irRECpwrOFF"} );  
    } 

    if (clicked_id == "irRECmute"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irRECmute"} );  
    } 

    if (clicked_id == "irRECvdn"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irRECvdn"} );  
    } 

	if (clicked_id == "irRECvup"){
        $.get( "curl.php", {
        room: "192.168.1.62", button: "irRECvup"} );  
    } 
 
}

index.html

HTML
Basic html to display buttons.
<html>
<head>
<LINK href="style.css" rel="stylesheet" type="text/css" />

<script type="text/javascript" src="jquery-2.0.3.min.js"></script>
<script type="text/javascript" src="script.js"></script>

<link rel="manifest" href="manifest.json">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel="icon" type="image/png" href="favicon.ico" />

</head>

<body>
	<div align="center" class="div_text_shadow">
	  <button class="btn2" type="button" id="irALLpwr" onClick="buttonClick(this.id)">Power Up Everything</button><BR><BR><BR>
		<H1>TV</H1>
			<button class="btn" type="button" id="irTVpwr" onClick="buttonClick(this.id)">Power</button><BR><BR>
			<button class="btn" type="button" id="irTVvup" onClick="buttonClick(this.id)">Vol +</button>
			<button class="btn" type="button" id="irTVsrc" onClick="buttonClick(this.id)">Source</button>
			<button class="btn" type="button" id="irTVchup" onClick="buttonClick(this.id)">Ch +</button><BR><BR>
			<button class="btn" type="button" id="irTVvdn" onClick="buttonClick(this.id)">Vol -</button>
			&nbsp;&nbsp;
			<button class="btn" type="button" id="irTVmute" onClick="buttonClick(this.id)">&nbsp;Mute&nbsp;</button>
			&nbsp;&nbsp;
			<button class="btn" type="button" id="irTVchdn" onClick="buttonClick(this.id)">Ch -</button>
			<br>
			<br>
			<br>
		<H1>Receiver</H1>
			<button class="btn" type="button" id="irRECpwr" onClick="buttonClick(this.id)">Power</button><BR><BR>
			<button class="btn" type="button" id="irRECmute" onClick="buttonClick(this.id)">Mute</button>
			<button class="btn" type="button" id="irRECvdn" onClick="buttonClick(this.id)">Vol -</button>
			<button class="btn" type="button" id="irRECvup" onClick="buttonClick(this.id)">Vol +</button>
			<br>
			<br>
	</div>
</body>
</html>

curl.php

PHP
php script to send GET requests to ESP8266
<?php

  $room = $_GET['room'];
  $button = $_GET['button'];

  // Create cURL call
  $service_url = 'http://' . $room . '/' . $button;
  $curl = curl_init($service_url);
   
  // Send cURL to Yun board
  curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 ); 
  $curl_response = curl_exec($curl);
  curl_close($curl);

  //Print answer
  echo $curl_response;

?>

manifest.json

JSON
This will allow the webpage to run as a native webapp in android.
{
  "name": "WiFi Remote",
  "icons": [
	{
      "src": "remote_icon_36.png",
      "sizes": "36x36",
      "type": "image/png",
      "density": 0.75
    },
    {
      "src": "remote_icon_48.png",
      "sizes": "48x48",
      "type": "image/png",
      "density": 1.0
    },
    {
      "src": "remote_icon_128.png",
      "sizes": "128x128",
      "type": "image/png",
      "density": 1.0
    },
    {
      "src": "remote_icon_192.png",
      "sizes": "192x192",
      "type": "image/png",
      "density": 1.0
    }
  ],
  "scope": "/remote/",
  "start_url": "/remote/index.html",
  "display": "fullscreen",
  "orientation": "portrait"
}

Credits

BuddyC

BuddyC

10 projects • 102 followers
I collect hobbies.

Comments