Introduction: Customizable WiFi IR Remote V1
There are a bunch of remotes for controlling various devices and using them is a frustrating thing because every device has its own routine that is made by default and users have to go through the same routine to open up what they desire. So what's the solution? That's where this project comes into play. In this project, you can customize your IR remote in such a way that you can control various activities like switching between your favorite channels, switching between entertainment apps or even powering ON/OFF various devices with a single button.
So hands on to create your perfect entertainment experience.
Supplies
Hardware
- Nodemcu or any other ESP8266 board
- IR Transmitter and Receive
- 220-ohm Resistor
- Rechargeable Battery(Optional)
Software
- Arduino IDE
- IRremoteESP8266 Library
Step 1: Get Your IR Code
Hex code and protocol are the prominent members who actively play in controlling IR devices. Most of the devices except AC's use NEC or RC6 protocol, Still, there are some companies like LG, Sony, Mitsubishi, etc which have their own IR protocol. In order to crack all those codes, you have to run the example code of IRremoteESP8266 called IRrecvDumpV3. This program will give you the Hex code as well as the protocol for the required remote button.
Copy down the Hex code of each button as well as its protocol.
Step 2: Customize It!
In order to customize our IR signals, we need to arrange them in the form "Device Name / Protocol"-R"Repetition"-"Hex Code", Where Repetition means the number of times to repeat a signal.
Example: TV-R10-0xFF4398
The given example denotes that the Hex Code 0xFF4398 of TV will repeat 10 times.
In order to send multiple signals, the format is repeated again with a Hyphen("-").
Example: TV-R1-0xFF4398-SB-R1-0xF24F2-TV-R5-0xF398-TV-R1-0xFF001
But this kind of large code will consume a lot of memory. So to reduce it we can make some default arrangements like
- Repetition R1 is made default. So the above code if formatted to
TV-0xFF4398-SB-0xF24F2-TV-R5-0xF398-TV-0xFF001
- If the consecutive signals you send are for the same Device Name / Protocol, then you only need to define the Device Name at the beginning.
TV-0xFF4398-R5-0xF398-SB-0xF24F2-TV-0xFF001.
- Some remote have the same protocol with the same parameters. In such cases, you can even use the protocol name itself.
If you haven't got an idea and want a demo of it, please run the Custom IR.ino file below.
Attachments
Step 3: Designing Front-end
It's important to have a good UI for controlling it because a better UI gives a better User Experience. So create an HTML page and make it beautiful using CSS.
Other than HTML and CSS, we will have to use JavaScript for improving User Experience and in this project, it plays one of the most important role. Here it is used for events on button click, Transferring data to the back-end without reloading the page, etc.
Advice: If you wish to create your HTML page, try to design it via any code editor like VS Code, because editing via Arduino IDE is time-consuming work.
Step 4: My Front-end Design
Since I wanted to create an HTML page to control my TV and Set-Top Box, Firstly I had to start by creating tabs that are used for selecting the remote. Also, I had to include a jQuery script for revoking the previous tab that was in use as well as some on-click functions to change the color of the buttons.
<div class="tab"> <ul class="nav nav-tabs" id="myTab"> <li class="nav-item"> <a href="#TV" class="nav-link" data-toggle="tab" onclick="bgcol('orange') ">TV</a> </li> <li class="nav-item"> <a href="#STB" class="nav-link" data-toggle="tab" onclick="bgcol('indigo') ">Tata Sky</a> </li> </ul> </div>
Secondly, I need to create a div tag that stores all the HTML code of the buttons in an id equal to the href value(Excluding '#' ) of the tab button.
<div class="tab-content"> <div id="TV" class="tab-pane">// Here id ="TV" because href = "#TV". // HTML code for TV's remote buttons. </div> <div id="STB" class="tab-pane">// Here id ="STB" because href = "#STB". // HTML code for STB's remote buttons. </div> </div>
Now it's time to create the buttons for the remote. Like regular buttons, it has value, style, shape, etc. In addition, I have added an attribute called "name" which holds the remote button's customized IR code and an on-click function to send this value. Also, I have added custom icons for buttons using the Font Awesome library to make them more beautiful.
<button class="button1 button-on" name=" " onclick="showname(this.name)">OK</button> //OR <button class="btn button-on" name=" " onclick="showname(this.name)"> <span class="fa fa-tv"></span></button>
Since the number of buttons I wished to add doesn't fit the layout, I had to create a div to hold all those buttons as well as a function that would open and close it on a button click.
<button class="button3 button-on" onclick="onmore()">return</button>// To open the overlay <div id="Overlay"> <button style="margin: 100px" class="button3 button-on" onclick="offmore()">return</button>// To close the overlay // HTML code for buttons. </div> function onmore() { document.getElementById("Overlay").style.display = "block"; } function offmore() { document.getElementById("Overlay").style.display = "none"; } </script>
Since I have included a showname() to every button, I have to define it to send the name value to the backend.
<div id="Btnvalue" style="display:none"></div> <script> function showname(btnname) { if (btnname.length == 0) { document.getElementById("Btnvalue").innerHTML =""; return; }else { const xmlhttp = new XMLHttpRequest(); xmlhttp.onload = function() { var x = document.getElementById("Btnvalue").innerHTML = this.responseText; } xmlhttp.open("GET", "btnstate?Btnvalue=" +btnname); xmlhttp.send(); } document.getElementById("Btnvalue").innerHTML = btnname; } function bgcol(col) {// For changing the button color const collection = document.getElementsByClassName("button-on"); for (var i = 0; i < collection.length; i++) { collection[i].style.backgroundColor = col; localStorage.setItem("btn-color", col); } } </script>
With these basics, I designed my Front-end code which is linked below.
Attachments
Step 5: Designing Back-end
Now coming to the back-end, most of the program is for the basic functioning of our webserver. Other than that we have to include functions for
- Implementing a Static IP Address.
- Receiving the values from the front-end.
- Including Arduino OTA for wireless programming.
- Sending out IR Signal for controlling, etc.
Step 6: My Backend Design
First, as I mentioned, I had started with the basic program required for the basic functioning of our web server in which I had to define my WiFi SSID and Password.
Secondly, I had to set up a Static IP Address for my webserver because by default they use a dynamic IP Address to connect to a network. So with a Static IP Address, our IP Address always remains the same.
IPAddress local_IP(192, 168, 1, 184);//Set your Static IP Address IPAddress gateway(192, 168, 1, 1);// Set your Gateway IP address IPAddress subnet(255, 255, 0, 0);
Next, I need to define a function that would receive the button values from the front end. The main reason why I defined the HEX Code of buttons in the front-end is that users can easily edit it with respect to the button. Whereas in the backend, users have to define multiple variables and functions which I believe is a difficult task because of the time consumption.
void handlebtn() { btncode = server.arg("Btnvalue"); ir_sending(btncode); server.send(200, "text/html", btncode); }
Lastly, I included the Arduino OTA program for wireless programming.
Attachments
Step 7: Setup IR Sending
Now coming to IR sending, Firstly I have started with the basic code for sending IR signals where I have set the output pin as D2(4).
Secondly, If you have gone through Step 1 and Step 3, you might be familiar with codes written like TV-R1-0x1109807F, SB-R10-0xC00020, etc. Since these values are returned in the form of a string. To iterate it, we have to change its datatype into char.
char str[200]; code.toCharArray(str, 200);
After that, we can split each term that is separated by "-" and are sorted into Device Name, Repeat, and Hex Code.
char* token = strtok(str, "-"); String dev; String rep; while (token != NULL) { keys= String(token); if (keys[0] == '0' && keys[1] == 'x') { // For Hex Code rece(dev, keys, rep); rep = '0'; } else if (keys[0] == 'R' && isDigit(keys[1])) {// For Repeat rep = keys; } else { dev = keys; // For Device Name } token = strtok(NULL, "-"); }
As we sort out when a new Hex code is received, a function is called to send the HEX Code, Repeat and Device Name.
If you are familiar with the IRremoteESP8266 library, the parameters that we pass into are uint8_t(unsigned integer 8 bit) but since our HEX code is in String, we have to convert it into decimal using the strtoul function.
void rece(String device, String val, String repeat) { char valch[50]; val.toCharArray(valch, 50); repeat.remove(0, 1); if (repeat == "") { repeat = '1'; }
Since we have only defined the Device name, now we have to define which type of signal it should send. Before going to it, if you have gone through the documentation of IRremoteESP8266, you might have seen that each IR protocol has its own syntax. For NEC it is sendNEC() and they usually have 3 parameters: HEX code, bit size, and repeat.
Hex code and bit size can be found through the example code IRrecvDump. But in case of repeat, you might be thinking of it as the value which starts with "R" in the example codes, right? No, here the repeat value means the no of times this signal has to send to make it a valid signal so that the device would recognize it. In the case of protocols of LG, Mitsubishi, SONY, etc have a default value which can be found through the IRremoteESP8266 documentation. But in other cases, this value varies and you have to find it on your own.
So to define it we start with the if condition inside which a for loop is used for repeating the signal R times with a delay of 110ms. Also, I have mentioned that some remotes have the same protocol with the same parameters, in such cases we can link both the device name in a single if condition.
if (device == "TV" || device == "Player") { for (int i = 0; i < repeat.toInt(); i++) { irsend.sendNEC(b, 24, 1); // .sendNEC(Hex Code, bit size, repeat) delay(110); } } else if (device == "STB") { for (int i = 0; i < repeat.toInt(); i++){ irsend.sendRC6(b, 32, 0); delay(110); } }
Attachments
Step 8: Frontend + Backend + Send IR
Now link all the 3 parts into an Arduino IDE compatible file and upload it.
My Code Link: https://create.arduino.cc/editor/Tkmrizwan/0a075403-3537-4f88-bebc-7ed02df530ea/preview
Step 9: Hardware
Now coming to the hardware part, Connect all the components as shown in the circuit diagram. If you wish to add a battery or power it via an external pin, I recommend it to be inside 9v or better if it is 5v because going beyond it would blow it up!
After completing the circuit, it's time to enclose it. Take a small box which would fit all the components inside it. Make holes for the button, IR Transmitter, and the charging/ power supply point. Also, make sure that the poles of the battery are well insulated to avoid any hazards.
Step 10: Run
Finally, it's time to run it. Connect your device to the network where Nodemcu is connected and enter the IP Address you have defined in the program.
While testing it you might have noted that the IR transmitter can only work within a range of 2m. This is because of using the 200-ohm resistor in it. To increase the signal strength, you have to use transistors like BC547(recommended), 2N222, etc which would amplify the IR signal.