Intro: Control Any TV With ESP8266 and Android
Have you ever wondered why you can't control "Smart" TVs with an app?
You're probably not alone. Most of them nowadays have built in WiFi, so to a layman such as myself, it would seem fairly simple to create a simple app and do away with the archaic IR remote. Nothing plagues me more than thinking about this while I search my room endlessly to find the remote. But as I was looking for it one day last week, I decided this was a problem I could fix myself.
Cue the ESP8266, a dirt cheap Arduino based WiFi capable development board. When I was a kid, you had to buy a fairly large and expensive WiFi shield (or heaven forbid an Ethernet shield) in order to connect an Arduino to the internet. The ESP8266 achieves this (in a much smaller package) for as low as $2.
To really make this more efficient than finding and using the remote, I was able to build a (very) simple app to access and control the whole set up. I also wrote an Amazon Echo Skill to control it; I'll include that in an update later.
Before we move on, I just want to say that this project is not about being elegant or smart or doing things the best way they could be done. This project was built out of necessity and it gets the job done. The code for the app in particular is somewhat "sloppy" and if I were building this as a product, perhaps I would find another way to attach the system to my TV other than duct tape, but it's not a product; I'm a freshman in college who got sick of digging through his room to find his remote. I plan to make some upgrades in the future, such as a 3D printed enclosure and new features in the app. That being said, happy building!
Also, if you like what you read, please log in and vote for the instructable of your choice (this one or any other one) in the contests by clicking vote at the top right of the page!
Step 1: Bill of Materials
- An Arduino - I have plenty of these lying around from other projects; it can most likely be done without one, but it was just slightly easier to use than the ESP8266 to get the signals from the remote. If this is your first Arduino, get an Uno. If not, I highly recommend having a few Nanos on hand.
- ESP8266 - the core of this project. Some of you are probably wondering why I said this was $2 in the Intro and it's $9 here. You can buy ESP8266s for as little as $2, but they only come with one GPIO pin. This model has a handful of pins and comes with an FTDI chip so it's no harder to program than an Arduino. However, you only need 1 pin, so if you know what you're doing, feel free to get one of the smaller, cheaper modules. I have some of these smaller ones on the way for other projects and I'll update this with instructions for those once I get them working.
- IR LED and Receiver - If you haven't figured it out yet, I'm an Amazon kind of guy and these were the cheapest I could find, so you get 5 pairs.
- Android Studio - what did you think I was just going to let you download my app and use it or something? Of course not, I'm going to walk you through how to build your own!
- A simple scripting language will also help to generate some of the code. I used Python 3.5, but you can do it by hand if you have the patience.
That's it! You never have to touch your remote again for like $15. I do assume that you have simple supplies and tools on hand such as a bit of wire and duct tape/hot glue/a method to attach this to the back of your TV.
Step 2: Some Theory and an Outline
Let's talk about how all this is going to work. Using preexisting Arduino and ESP8266 IR libraries, I will set up the IR transceiver on the Arduino and get the hexadecimal codes for each button. Then I will use an example program found in the ESP8266 IR Library to test these codes and the IR LED using the website it generates. I will then modify this program so that it can work with all the buttons I want to use (I don't actually get TV service on the TV I built this for so I won't include channel buttons etc.). At this point, I should be able to operate the device from the website at its IP address so after testing it, I'll build a simple (just go ahead a lower your expectations for me here) app to act as a client to that website.
The information that tells the TV what to do is sent by flashing the IR LED really quickly in very specific patterns that the TV can recognize. The pattern that the LED uses is called the protocol; my TV uses NEC protocol, but yours might use something different so just google it! No matter the IR protocol, however, not much changes.
Step 3: Getting the IR Codes From Your Remote
The first step is to determine the type of signal protocol that your TV uses and get the hex codes for each button.
Bust out your Arduino and install the Arduino IR Library and the ESP8266 IR Library (Sketch > Include Library > Manage Libraries). I was able to find a fantastic IR Dump modification (pjrc_IR_dump.ino) that prints the hex code AND protocol type for any signal received. This program is not mine, it came from here; I don't take credit for it, etc. Wire up the transceiver according to the pinout in the diagram (output to pin 6, or change the pin number in the code), load the pjrc_IR_dump program and open your serial monitor. Go dig around in the couch to find your remote (hopefully, for the last time). Now point it at the transceiver and you should see an output in the Serial monitor. You'll see the IR protocol type followed by a hexadecimal number. This number is the coded signal that you will need to write down somewhere to use later. Go ahead and collect the codes/hex numbers for all the buttons you want your website/app to use.
See the attached picture for an example output.
Note: This step can be done on an ESP8266 but the code that classified the signal protocol was for Arduino so I used that. If you don't have an Arduino on hand, play around with the ESP8266 IR Library examples
Step 4: ESP8266 Code
Now comes the fun part. Attach the IR LED to GPIO Pin 15. If you're like me, new to ESP8266, you probably didn't read that sentence properly, connected the LED to D15 and wondered why nothing was working. GPIO Pin numbers and Digital Pin numbers are not the same thing! Refer to the handy diagram to see which digital pin is GPIO pin 15. If you didn't buy the model I linked in the introduction, find a pinout for your model. If pin 15 is inconvenient feel free to change it to whatever you'd like in the code.
If this is your first ESP8266, you have a bit of setup to do. Add the ESP8266 boards (Tools > Board > Boards Manager..) and install any necessary drivers (Google).
Download the code attached and add your WiFi credentials, then upload it to your ESP8266. Open the Serial monitor and hopefully you see that it successfully connected to your WiFi network and has an IP address. Navigate to your IP address and you should see a plain text HTML website with a link on it. If you point it at your TV, it will only work if you have exactly the same model TV as I do so don't get all excited yet.
Step 5: HTML Generation
Anything that can be done on a computer, can be done faster with a script. This step required a lot of repetitive code so I used a Python script to write a lot of it for me:
At this point, you can edit the HTML in the code to add your own title and headers (and any other stylistic features you want) to the interface. Lets add the links for all the other buttons. If you've come this far, I'm assuming you have a small amount of coding experience. If not in Python, don't worry; Python is very friendly, and far simpler than C, C++, or Java or most other languages. Even if you have no experience you can probably still read Python. Open up the attached Python 3.5 script and notice the buttons and codes list. You may notice that your codes are much longer than mine. That is because mine had a 4 (hex) digit "address" that started all of the codes so I didn't bother writing it for each one, I had the script add it to the beginning of them all. Delete whatever is in both lists and add your own codes. Notice the comments that say to keep them in the same order; this is important.
If you have an "address" like I did, change the address variable to whatever your address was. Leave the "0x" in the front. If not, delete the line "codes[i] = address + codes[i]" and just make sure you start your codes with "0x" (you could change the address variable to this and leave that line there if you wanted). Follow the instructions in the comments to add the names and codes for your TV. If you save and run the script, you should see a few things in the output; this is all code that we can copy and paste to a few different places. All we need for now is the HTML bit at the top. The number you'll see (ir?code = _______ ) is the decimal equivalent of the hex codes you recorded earlier. Replace these HTML links with the one Link in the code (the line right after "Add a header here"). If you reupload, you should see the website now has links with all your buttons on it and if you point it at your TV and click a link, it should work at this point! I attached a picture of my website after I added the right HTML.Pat yourself on the back because you're halfway done! If you want to stop here either because you don't have an Android phone or you're satisfied to use the website, that's perfectly fine, but I wanted to take it a step further and build an app so the rest of the instructable will focus on that.
Step 6: Setup Android Studio and App Overview
If you don't already have it, download Android Studio and install it. It's a hefty download, fair warning. You may want to go through a few of the getting started tutorials to familiarize yourself with the various pieces of an app before continuing here. I will do my best to explain things as I go but I'm pretty new to this myself.
A crash course into app development - terms and vocabulary
- Manifest - XML Document that is important for declaring permissions.
- The Java Files - Where most of the actual code happens
- Activity - More or less a "screen" in the app. This app only has one activity "Main Activity" so don't worry about these too much
- Resources (res) - pretty much any kind of hard coded values should go here. Writing the app that way was more complicated so I opted to just write the values in the java
- Gradle - don't worry about all this (although if you have an older version of Android, you may have to change some of the build options to use a lower API version)
All of those files (above) can be found on the left-hand side of the workspace under "structure".
Here's an overview of how the app works - if your website is working, you'll notice that when you click on one of the links, the website redirects you to a different URL (without changing the page); in that URL, you'll see the decimal representation of the hex codes that you found earlier. All the app needs to do is act as a client to the website and open that URL with the decimal code on the end, and it should trigger the same process in the ESP8266 as if the user clicked on the link in the website.
If you look through the Java in the Android Studio Project I attached (unzip and copy folder to your Android Studio workspace folder), you'll notice there's a main class, and a custom class called pingit that extends AsyncTask. In software, it is a bad practice (and not allowed in Android Studio) to call network functions in the main UI thread. This is because if the user has a poor internet connection, the application will have to wait for the connection before proceeding onto whatever else it is supposed to do and in some cases, this could cause it to break entirely. Android Studio provides developers with AsyncTask so that it is possible to run network operations in the background "asynchronously" to avoid this problem. AsyncTask has 4 methods, but the only one we'll use is doInBackground (it does what it sounds like) to open a connection with the URL we create in the main thread. To create that URL, we'll create an onClickListener (also does what it sounds like it does), and wait for a button to be pushed. We'll get the ID of that button and use a switch statement to create a URL with the appropriate decimal representation of the hex codes we found earlier. Once we have this, we'll send it to the AsyncTask and have it open a connection with it and Bob's your uncle. Because we have a lot of buttons, we'll use the same python script to generate the code that gets the buttons and links them to the onClickListener.
Note: I included my project so that people who aren't so much interested in the mechanics of app development can tweak a few things and move on and have an app to use. However, I encourage people with coding experience to try to build it from scratch using this and my app as a guide.
Step 7: More Cheating With Python
For every button, we need a line of code that creates a button reference on the java side:
Button power = (Button) findViewById(R.id.power);
and a line that attaches said button to the onClickListener
Don't worry about creating the actual buttons or the user interface yet, we'll create that later. You'll get a lot of errors because the buttons don't exist yet so just ignore those for now. In the python script from earlier, change the list buttonids (in the same order as codes and buttons), to hold variable names for the buttons. These are names you'll call later in the java to find out when the buttons are clicked later so follow proper variable naming conventions. I left mine in there as an example. Then, click run again and you'll see both necessary lines of code generated for you. Paste those over the top of where mine are in the MainActivity.java file.
Now that we have those buttons in the program, we need them to do something when we push them. For this, we'll use a switch statement whose argument is the ID of the button that was pushed. For example, if power was pushed, go to the URL with the power code, etc. for each button. Once again, writing each case by hand could be tedious, but not when you have a python script. The last output of the python script should be a case statement for each button. Paste that inside the switch statement (obviously deleting what is currently there).
Make sure to change the IP address to the IP of your ESP8266 wherever you see an IP address in the Java.
Lastly, we get to create the User Interface.
Step 8: The User Interface
So far, we haven't seen much happen. You've moved some code around, and done a fair amount of copying and pasting. This is where everything comes together.
Click over to the activity_main.xml tab. If you're not already looking at the graphic design (if you see a bunch of XML), click "Design" at the bottom. If you're using my project as a template, you will already see a grid of buttons there; get rid of those. Now go to the Palette on the left and click and drag a button into the middle of the screen and play with it a little. Notice on the right, you have a properties tab; the ID field is where you'll enter the ID you made up in the python code for each button, and the text field is what you want the button to say.
Before you continue, it's probably a good idea to have some idea of how you want to layout everything on your UI so pause for a moment and figure that out. This is where you can get creative; I'm not much of a visual designer so I didn't take much time to play around with different button styles etc., but I'd love to see what you come up with. Here is a tutorial on Building a UI with the Layout Editor. Knock yourself out.
If you're like me, and don't really care much for the graphic design, the one thing you'll need from that tutorial is knowledge of constraints. If you placed all your buttons in a nice neat grid, and then built your app, you probably found that they all went to the top left corner; constraints make sure they don't do that; they're the little handles in the middle of each edge that you can drag to either an edge or the edge of another button, etc. Once you have everything the way you like it, the IDs set, and imported any libraries you need to import (if Android Studio recognizes you need to import a library, it'll turn it red and underline it and if you place your cursor over it and hit Alt + Enter, it will import it for you), you should be all set. If you get any other errors, it's probably a naming issue; even if not, use your best debugging skills and get on StackOverflow and/or the comments section here. Once all the errors are resolved, enable debugging on your phone, then connect it to your computer, unlock your phone, and build the app selecting your phone as the debugging device when it asks.
The app will then be installed on your phone and should launch automatically when it's done building. Congratulations! You've just made an app to control your TV! Go ahead and mount your ESP8266 to the back of your TV more permanently however you see fit, and position the IR LED so that the IR receiver on your TV can see it quite clearly. Because the ESP8266 uses very little power, the brightness of the LED will probably be very low so I put mine right in front of the receiver on my TV.
Here's a picture of the final product; as you can see; even with my pink duct tape, it's very discrete and hardly visible from afar.