Projects

1000 Button Remote Control

Oliver Higgins

Issue 1, July 2017

This article includes additional downloadable resources.
Please log in to access.

Log in

Here's how you can turn your smartphone into a network-connected remote control, so you can turn the volume up on your stereo while you're on the patio, control your A/V equipment from another room, and lots more.

Infrared (IR) remote controls are taken for granted. They provide a reasonably complex function, often to simply remove the need for us to get off the couch to change a channel! But IR remotes have limitations; they require line of sight between the remote and the receiver, and they tend to have a limited range, which is generally a 7m maximum. This project removes this limitation and expands functionality to the coverage of local WiFi ethernet network, or wherever you have internet access.

HOW IT WORKS

We have created a very basic HTML, which you can use on your smartphone. This HTML is fully customisable to your own uses for the project, and you can label the buttons whatever you like. If you’re familiar with HTML / CSS, you can modify it and work up a fantastic looking remote interface. For now, we’ve kept it simple and functional.

We have provided the URL structure that you need in order to make your own requests to the web server, but you don’t have to use our template files. We have effectively built a very basic, unauthenticated API, which allows you to learn just about any simple IR code, then replay it to control your equipment. This means that if you would like to develop your own native app, or integrate the system into another existing project, it’s very easy to do

This system will allow you to control infrared devices from anywhere within your own WiFi coverage. You can also combine many remote controls into one smartphone system

THE BROAD OVERVIEW

Effectively there are two major parts to this project: the HTML package, and the Arduino web server. With the web server running, the HTML package forms the requests to send to the server. It’s done using AJAX. We won’t go into AJAX here as it will derail our focus to a degree, but it allows us to send and receive data with a web server, without having to refresh the web page itself.

These days, virtually every major website online uses AJAX, so chances are high that you’ve experienced it even without knowing. The topology diagram below demonstrates the communication paths with the equipment.

HOW IT WORKS

We have created a very basic HTML, which you can use on your smartphone. This HTML is fully customisable to your own uses for the project, and you can label the buttons whatever you like. If you’re familiar with HTML / CSS, you can modify it and work up a fantastic looking remote interface. For now, we’ve kept it simple and functional.

We have provided the URL structure that you need in order to make your own requests to the web server, but you don’t have to use our template files. We have effectively built a very basic, unauthenticated API, which allows you to learn just about any simple IR code, then replay it to control your equipment. This means that if you would like to develop your own native app, or integrate the system into another existing project, it’s very easy to do.

The web server is configured to receive two types of requests (you need to replace the IP address with the one used by your Arduino, see our notes elsewhere in this article):

LEARN A CODE:

127.0.0.1/?learn=001

This will initiate the IR receiver on the Arduino, and wait for you to press the IR remote button you wish to learn. When the code is received, it will store it to the SD card in raw format, using the button-number pushed on your smartphone or web browser.

PLAYBACK A CODE:

127.0.0.1?playback=001

This will initiate the Arduino and retrieve the stored code from the SD card based on the request made, and retransmit it via the IR transmitter.

In order to keep the code that processes these requests simple, we have restricted the key codes to be three numbers. This creates a limit of 1000 buttons, which – let’s be honest – is more than enough. It wouldn’t take much to enable alphanumeric keys (which would expand the limit to 46,000 or so), but it seemed totally unnecessary.

THE BUILD

Parts Required: JAYCAR Altronics
1 x Arduino Mega XC-4420 Z6281
1 x Ethernet / SD Shield XC-4412 Z6242
1 x IR Receiver XC-4427 Z6374
1 x IR Transmitter XC-4426 -
1 x Red LED ZD-0150 Z0800
1 x Green LED ZD-0170 Z0801
2 x 2200 Resistors RR-0556 R7038
1 x MicroSD Card XC-4983 D0327

You'll also need prototyping hardware such as a breadboard and jumper wires.

IP Addresses

We are specifying an IP address in our code. If this doesn’t work on your network, or if you’re happy to let the router take care of address assignment, it’s quite easy to modify. Around line 60 of the sketch, we initialise the ethernet module. Find this code:

Ethernet.begin(mac, ip);

Modify by removing the IP specification. You'll end up with:

Ethernet.begin(mac);

By removing the IP specification, you tell the ethernet shield to “ask” the network for an IP address. Usually your internet router will run a service called Dynamic Host Configuration Protocol (DHCP). DHCP makes networking easier by automatically assigning IP addresses for you (the Arduino will display it in serial monitor). However, if you use DHCP for IP address configuration on your projects, note the following:

1. Your ethernet shield must be connected to the network during testing, or the system will not boot correctly.

2. DHCP assignments can change from time to time, and this is called “lease renewal”. Therefore the IP address may change when this renewal occurs and you’ll have to find out what it’s changed to, which is a bit of a pain. You can tell your router to issue the same address all the time and still reliably use DHCP, but this process is beyond the scope of this article.

This project requires a local network with WiFi and ethernet connectivity, which we wouldn't assume is uncommon amongst DIYODE readers. While the Arduino MEGA uses the ethernet shield to connect, your smartphone will connect via WiFi. You can still test the prototype using your computer (ethernet or WiFi), but you won't have the same level of portability.

BUILDING THE CIRCUIT

This project uses an Arduino Mega, an ethernet shield, an IR receiver module, and an IR Transmitter module. We have also used two LEDs to help provide feedback when not connected to a computer, but these can be omitted if you prefer (you’ll just have no feedback mechanism to tell you if it hasn’t booted correctly, when not connected to your computer). Assembly should only take you a few minutes using a breadboard, following the illustration below.

Circuit Diagram

Load the sketch onto your Mega using the Arduino IDE. Assuming everything compiles and loads correctly, open the serial monitor. The Mega will provide the IP address in serial monitor, so you’ll know what IP address to put into the HTML in the next steps. Go to the resources links below to download on your phone (or open it up on your computer in your favourite web browser – it will work in any modern browser). It has been configured to allow offline access, so you can “Add to Home Screen” on most phones or browser, and you effectively have app-like access, without the hassle.

THE CODE

The code used for this project is reasonably simple. The heavy lifting is done through built-in libraries in Arduino. SPI, ethernet, SD and IRremote. The first three are included with the standard install of the IDE, whilst you will have to add the IRremote library (see resources).

The setup code starts by loading these libraries. We then go on to set up our LED constants, our SD file object, IR variables and the ethernet settings. You should update the MAC address variable to whatever the MAC address is on your ethernet shield; however, not all units have this printed on them. The MAC address given in the code should suffice for the vast majority of users, but if you fail to get the server to respond and give an IP in the serial monitor on boot this could be in conflict.

Next is the IP address. We have included two addresses common in home networks, but I would advise finding out what your local network is using (see our note on IP addresses on previous page).

The final part of initialisation is char linebuf[80]; and int charcount = 0; these are used by the ethernet server, and will hold a CHAR array received from the AJAX call from the HTML app.

SETUP

The first few lines here are just to blink the LEDs, so they’ll quickly flash once and then turn on until the end of the setup sequence. Once they are no longer switched on, the unit is ready to go. Lines 51 through 63 are required to set up and prepare the ethernet shield, while using the built-in SD card. This could be considered supplementary and the unit will most likely work without it; however, during the development we often had weird errors with reading and writing to the SD card, which was resolved with the introduction of this code.

The final part of the setup sees the ethernet webserver started, the server IP address sent to the serial monitor, and the LEDs pulled low to indicate the unit is operating as normal.

After this we have a series of functions used to interact with the IR transmitter (Tx) and IR Receiver (Rx).

dumpRaw (decode_results * results)

This function is used during the “learning” phase of the program. Its only argument is the results object produced when the IR input is received. The function then reads this array of raw timing data, and displays the sequence as well as the buffer size. This is sent to the serial monitor and it is used to make sure your signal being received is consistent.

writeIR (dcode_results * results, int keyCode)

writeIR takes the raw IR results object as well as an integer, which is the specific key received from the AJAX command in the learning phase. This function builds a filename from the keyCode number, and then writes the IR raw data sequence to the file.

getIRCode(int keyCode)

This is the function called when you press a button in the “learn mode”. It takes the keyCode argument, which is the number defined on the button you pressed in the HTML code. The green LED will switch on and if you have the serial monitor open you will see the output “Awaiting IR input”. The unit will wait forever until it gets a code or you restart it. Once it has a code it opens a file for writing. It then writes the sequence of the raw IR data before closing the file.

sendIRCode(int keyCode)

The sendIRCode takes the keyCode integer based upon the key press in the playback mode. It uses this number to open the correct file from the SD card and builds a new array with this data. Once the array is complete the function uses the IRsend object to send the data by creating a waveform using Pulse Width Modulation (PWM) on pin 9.

loop()

In this case, the main loop really only serves one function: to listen for the AJAX call. The first half of this code is to listen to the incoming port, then once we have a connection and get the data received, it is put into the linebuf CHAR array. Once we have the array, we look for a couple of things. Firstly is the AJAX call for playback of a code or do we need to learn? If it’s playback, then we get the playback file number out of the array. This is extracted as a 3-byte array. Once in place, it is converted to an integer before it is passed to the sendIRcode() function as the keyCode. If the AJAX call is for the learning mode, then the process is the same, it just calls the getIRCode function, which calls the writeIR, and finally the dumpRaw to show you the content of the code.

Finally, the loop checks that all the data has been processed before closing off the connection and waiting for the next one. The code itself is quite quick to process, with the SD card read being the slowest part. If you wanted to kill any lag in the system get a class 10 or better SD card, and comment out all of the Serial.println() calls.

LEARNING CODES

For this stage you’ll need to have the working web server within reach and connected to ethernet. Open the HTML package in your web browser. This can be done on your phone or computer. The phone / computer will have to be on your local network too (WiFi or ethernet doesn’t matter). The code uses your local network to talk to the Arduino, even though it’s loaded via our site.

screenshot1
1
Step1

1. Enter the IP address [1] you saw in serial monitor when loading the sketch onto the hardware.

2
Step2

2. Toggle the “playback” button to “learn” [2]. You’re now ready to start teaching IR codes to your Arduino, so get your favourite TV remote control, or whatever IR remote you want to learn, ready.

3
Step3

3. Click / tap on the ON/OFF button. You’ll be prompted by an on-screen dialog [3]. Point your remote control at the Mega and push the power button on the remote. Once the code has been received, the dialog box will confirm and disappear.

4
Step4

4. Toggle the “learn” button back to “playback [4].

5
Step5

5. If you click / tap on the power button now [5], it should turn on/off whatever device that belongs to the remote you just used (of course, that device needs to be within range of the Arduino too).

If nothing happened, repeat steps 2 to 5 again. The range of the IR transmitter is affected by sunlight and can effectively be "drowned out". Make sure you're nice and close to the device you're trying to learn, and this is best done indoors.

Now your system is ready for you to teach it all the infrared codes you want it to store. It’s simply a matter of entering “learn” mode again, and looping through steps 2 to 5 with each button you want to train.

Note: You don't have to toggle the learn/playback button after each learning sequence, unless you want to test each code along the way. Once you have learnt all of your codes, toggle the "LEARN" button back to "PLAYBACK" and you're ready to go.

EXPANDING THE HTML

We have made the web server code intelligent enough that you shouldn’t have to modify it again, in order to further customise the remote control. You simply need to open up the HTML file and add more buttons! You can simply open the HTML file in a text editor, and also in your favourite web browser. You can then preview your changes right in the web browser as you edit. However it is recommended that you use a proper web server process (built in to most operating systems now at a basic level) to ensure everything works as intented. It will also be required in order to get the “web app” back onto your phone.

Download the HTML package from the resources links below. Once you have unzipped the file provided, you’ll see an index.html file, as well as css / js folders. If you’re familiar with HTML coding, you probably don’t need any explanation in order to modify and get the code working. If you’re not too familiar, we’ll give you a breakdown below to get started.

Note: You shouldn’t use rich text editors such as Microsoft Word to edit HTML. They use hidden code to retain styling information and other data. Some suggestions are Notepad++ on Windows, Atom on Mac, and if you're using Linux you're probably already sorted.

MODIFYING A BUTTON

We have provided what is essentially a “demo” set of buttons. Power on/off, volume up/down, and channel up/down. Chances are these aren’t going to cover all of your needs, and they’re not really designed to. So here’s how you modify a button. Open up the index.html file in a text editor.

There are 52-lines of code in the HTML file, but you really only need to be concerned with around 10 of them.

<div class="buttons">
  <button class="power full" data-id="101">
    ON/OFF</button>
  <div class="pull-left">
    <button data-id="102">VOL +</button>
    <button data-id="103">VOL -</button>
  </div>
  <div class="pull-right">
    <button data-id="104">CH +</button>
    <button data-id="105">CH -</button>
  </div>
</div>

This is where the functional display portion of the web interface happens. The code is styled and managed via CSS and JavaScript, but you shouldn’t need to look at those unless you’re looking to make significant modifications to the code.

We have made it VERY easy to add new buttons, since our Arduino sketch is designed to dynamically handle the requests, so you don’t have to recompile the Arduino every time you want to add a button. There are only two parts to the virtual buttons.

data-id="100"

The first part is the data-id. This can be any three digit number, so long as it’s unique. If you have duplicated a data-id between buttons, then they’ll both use the same code (whichever one you trained last), despite possibly having different names. You shouldn’t need to modify the button’s data-id attribute unless you find you have duplicated one.

VOL +

The second part is the display portion. We have just used text, but you could modify further to use images - the possibilities truly are endless. This part is for display only, and the Arduino isn’t made aware of it, so you can call it literally whatever you want.

ADDING A BUTTON

To add a button, simply duplicate a <button> code (grab the entire line, copy + paste). Say you wanted to add a new button below the VOL - button, locate it in the code (around line 40):

    <button data-id="102">VOL +</button>
    <button data-id="103">VOL -</button>
</div>

Duplicate the VOL - line, then modify the new line with a uniqe data-id, and the name you want to give it.

    <button data-id="102">VOL +</button>
    <button data-id="103">VOL -</button>
    <button data-id="106">NEW BUTTON</button>
</div>

As you can see we’ve used data-id of 106, because data-id 104/105 were used already for the CH +/- buttons, and they must be unique so the Arduino can appropriately store the data (otherwise it will overwrite the code on the previous button when you try and learn the new infrared code).

If you refresh the HTML page on your phone or browser, you should see your new button appear. You can then proceed to train the Arduino the infrared code for that button.

REMOVING A BUTTON

If you need to remove a button, you can just delete it from the HTML code. You don’t need to do anything on the Arduino. The previously stored code will remain against the data-id number, but that doesn’t really matter. If you want to re-use the data-id number again you can, you just need to repeat the learning process.

IMPROVING STYLES AND FUNCTIONALITY

We have only provided a "springboard" of HTML code to provide a practical demonstration of functionality, with very basic CSS styling to make it work. How you configure the remote control to work for you is going to be very personal - that's the beauty of this setup! You can modify the CSS file (main.css) as much as you like, to suit whatever style you prefer to have.

We took a similar approach to the JavaScript as we did with the HTML, keeping it lean. However, we do use jQuery for AJAX requests as it simplifies cross-browser compatibility and is familiar to most people with web development experience.

To expand the functionality, you can easily extend the JavaScript to provide more customised updates and responses, and change just about everything. It would even be feasible to stack codes together, detect when a button is continually pressed, and other item's on our "where to" list below.

GETTING UPDATED CODE BACK ON YOUR PHONE

You really need to have a web server process running on your computer (or access to an actual web server) to get the code back on your phone. This process isn’t really covered here, as it’s somewhat out of scope for this article, and is very dependent on your operating system or resources available. Once uploaded, you simply need to visit the URL to access the new files (eg, 127.0.0.1/ircode/index.html) and if you wish, bookmark / save to home screen to provide you with one-button access to your IoT remote control.

WHERE TO FROM HERE

This project works very well but there are several improvements that could be made to further increase functionality :

WiFi: Adapting the project for WiFi would (rather obviously) remove the need for wired ethernet. Our main reason for using ethernet in this project was to use the included SD interface.

MULTI-CODE LEARNING: We could configure the system to allow learning of more than one IR command, assigned to a single button. This would effectively create “smart buttons” which, with a single press, will transmit several codes. A single button for “switch the receiver to Blu-ray, turn the volume up, and change to HDMI 2 on the flat screen”.

CONTINUOUS-PRESS-RECOGNITION: Just as your native remote control will understand if you have kept your finger on the button (like when the volume button turns the volume up for as long as the button is depressed), we could make the javascript more intelligent, so as to detect a single press versus a press and hold. Currently it’s “one press / one activation”. Not a big deal if you want to turn on or off the TV, but it’s a bit of a pain to take the volume from 10 to 40 in one-step increments!

HARDWARE FINISHING: A 3D-printed case to house everything, and installing the modules onto a prototyping board, would make the hardware more of a permanent solution.

TRIMING: We don’t need everything the MEGA has to offer, so we could try and trim the code to get it onto something smaller. We did get it onto an UNO, but processing the IR through the SD card proved too much for reliable operation.

AN IMPORTANT PRINCIPLE

As web technology keeps evolving, web pages can behave more and more like complex software. No longer do you need to "refresh" to see updates or retrieve new content.

This IoT remote demonstrates just the beginning of what's possible when using a web browser to perform display operations with a simple server. Using Arduino to provide hardware expansion, the possibilities are endless.

We could output the HTML page and all its related content directly from the Arduino web server. However the more complicated the HTML, the slower the response will be.

Complex HTML could also quickly overload an Arduino. By utilising the power of the web browser on the display device (smartphone or computer etc), you keep the data flow between devices smaller, the memory requirements for the Arduino lower, and everything less prone to errors.

This principle can be drastically expanded. Consider for a moment, a virtual vehicle dashboard. You can update in almost real time, temperature sensors, motion sensors, and more.

Feeding all this data and driving a display right on the Arduino is not going to be reliable. If you serve a JSON, XML, or other "raw data" stream from the Arduino, you can let the web browser do the processing.