Full Control of Your TV Using Alexa and Arduino Cloud
Learn how to use Arduino Cloud and Amazon Alexa to switch the channel, adjust the volume and turn on or off any TV.
Components and Supplies
- Arduino Nano 33 IoT
- Resistor 330 ohm
- IR receiver (generic)
- IR transmitter (generic)
- Jumper wires (generic)
- Breadboard (generic)
Apps and Online Services
About This Project
Intro: Arduino Cloud
Arduino Cloud is a platform that enables anyone to build IoT connected object with ease. In order to control our TV using Alexa, we'll also be using the Official Arduino Alexa Skill.
If you are new to Arduino Cloud, we advise to first take a look at this introductory project, which will give you an overview and guide you through the process of setting up one of the supported boards, IoT Cloud Things and Properties and get you onboard.
Part 1: How to Control a TV Set
The easiest way to control any kind of television, is to act as if we were its very own remote infrared controller. In order to do so, we'll have to listen for the signals the remote will send, capture the data and mimic it with our Arduino board. Once the circuit is assembled, we'll upload this sketch to our board. It will translate the IR signal bursts generated by remote button presses into an array of unsigned integers. Let's point the remote at the Arduino IR Receiver we built and press the following buttons:
- POWER/STANDBY
- CHANNELS FROM 1 TO 9
- VOLUME UP
- VOLUME DOWN
- MUTE
- CHANNEL UP
- CHANNEL DOWN
We'll see the values coming through the Serial Monitor, reported as
rawData
. Let's take note of them into a text file for now, and assign each list its own array name (chan1
, chan2
and so on). The following values are just for reference, and are generated by a Samsung's TV remote.1CHANNEL 12unsigned int chan1[67] = {4450,4500, 550,1700, 500,1700, 550,1700, 550,550, 550,600, 500,600, 550,550, 550,600, 500,1700, 550,1700, 550,1700, 500,600, 500,600, 550,550, 550,600, 500,600, 550,550, 550,600, 500,1700, 550,600, 500,600, 550,550, 550,600, 500,600, 550,1700, 500,1700, 550,600, 500,1700, 550,1700, 550,1700, 500,1700, 550,1700, 500};3CHANNEL 24unsigned int chan2[67] = {4500,4500, 550,1700, 500,1700, 550,1700, 550,550, 550,550, 550,600, 500,600, 550,600, 500,1700, 550,1700, 500,1700, 550,600, 500,600, 550,550, 550,600, 500,600, 550,1700, 500,600, 550,1700, 500,600, 550,550, 550,600, 500,600, 550,550, 550,650, 450,1700, 550,600, 500,1700, 550,1700, 500,1700, 550,1700, 550,1700, 500};5CHANNEL 36unsigned int chan3[67] = {4500,4500, 500,1700, 550,1700, 550,1700, 500,600, 550,550, 550,600, 500,600, 550,550, 550,1700, 500,1700, 550,1700, 550,550, 550,600, 500,600, 550,550, 550,600, 500,600, 550,1700, 500,1700, 550,600, 550,550, 550,550, 550,600, 550,550, 550,1700, 500,600, 550,550, 550,1700, 550,1650, 550,1700, 550,1700, 500,1700, 600};7CHANNEL 48unsigned int chan4[67] = {4450,4450, 550,1700, 550,1700, 500,1700, 550,600, 500,600, 550,550, 600,550, 500,600, 550,1700, 500,1700, 550,1700, 550,550, 550,600, 500,600, 550,550, 550,600, 500,600, 550,550, 550,600, 500,1700, 550,600, 500,600, 550,550, 550,600, 500,1700, 550,1700, 550,1700, 500,600, 550,1700, 500,1700, 550,1700, 550,1700, 500}; 9CHANNEL 510unsigned int chan5[67] = {4500,4500, 500,1700, 550,1700, 550,1700, 550,550, 550,550, 550,550, 600,550, 550,550, 550,1700, 550,1650, 550,1700, 550,550, 550,600, 500,600, 550,550, 550,600, 500,1700, 550,600, 500,600, 550,1700, 500,600, 550,550, 550,600, 550,550, 550,550, 550,1700, 550,1700, 500,600, 550,1700, 500,1700, 550,1700, 550,1700, 500}; 11CHANNEL 612unsigned int chan6[67] = {4500,4500, 550,1650, 550,1700, 550,1700, 500,600, 550,550, 550,600, 500,600, 500,600, 550,1700, 500,1700, 550,1700, 550,550, 600,550, 500,600, 550,550, 600,550, 550,550, 550,1700, 500,600, 550,1700, 500,600, 550,550, 550,600, 500,600, 550,1700, 500,600, 550,1700, 500,600, 550,1650, 600,1650, 550,1700, 550,1650, 600}; 13CHANNEL 714unsigned int chan7[67] = {4500,4500, 550,1700, 500,1700, 550,1750, 500,550, 550,600, 500,650, 500,550, 550,550, 550,1750, 500,1700, 500,1700, 550,650, 450,650, 500,550, 550,600, 500,650, 500,550, 550,600, 500,1700, 550,1750, 500,600, 500,550, 550,600, 500,650, 500,1750, 450,1700, 550,600, 500,650, 500,1700, 500,1700, 550,1750, 500,1700, 500}; 15CHANNEL 816unsigned int chan8[67] = {4450,4550, 500,1700, 550,1700, 550,1650, 550,600, 500,600, 550,550, 550,600, 500,600, 550,1700, 500,1700, 550,1700, 550,550, 550,600, 500,600, 550,550, 550,600, 500,1700, 550,600, 500,1700, 550,1700, 500,600, 550,550, 550,650, 450,600, 550,550, 550,1700, 550,550, 550,600, 500,1700, 550,1700, 550,1700, 500,1700, 550}; 17CHANNEL 918unsigned int chan9[67] = {4450,4500, 550,1700, 550,1700, 500,1700, 550,600, 500,600, 550,550, 550,600, 500,600, 550,1700, 500,1700, 550,1700, 500,600, 550,550, 550,600, 500,600, 550,550, 550,600, 500,1700, 550,1700, 550,1700, 500,600, 550,550, 550,550, 550,600, 500,1700, 550,600, 500,600, 550,550, 550,1700, 550,1700, 500,1700, 550,1700, 550}; 19VOLUME UP20unsigned int volUp[67] = {4500,4500, 550,1700, 500,1750, 500,1700, 550,600, 500,600, 500,600, 550,550, 550,600, 500,1700, 550,1700, 550,1700, 500,650, 450,600, 550,600, 500,650, 450,650, 500,1700, 500,1750, 500,1750, 500,550, 550,600, 500,650, 500,550, 550,600, 500,650, 500,600, 500,600, 500,1700, 550,1750, 450,1750, 500,1700, 550,1700, 500}; 21VOLUME DOWN22unsigned int volDown[67] = {4450,4550, 500,1700, 550,1700, 550,1650, 550,600, 550,550, 550,600, 500,600, 500,600, 550,1700, 500,1700, 550,1700, 550,550, 550,600, 500,600, 550,550, 550,600, 500,1700, 550,1700, 550,600, 500,1700, 550,600, 500,600, 500,600, 550,550, 550,600, 500,650, 500,1700, 500,650, 500,1700, 500,1750, 500,1700, 550,1700, 500}; 23CHANNEL UP24unsigned int chanUp[67] = {4500,4450, 550,1700, 550,1650, 550,1700, 550,550, 550,600, 550,550, 550,550, 600,550, 550,1650, 550,1700, 550,1650, 600,550, 550,550, 550,600, 500,600, 550,550, 550,550, 550,1700, 550,550, 600,550, 550,1650, 550,600, 550,550, 550,550, 550,1700, 550,550, 550,1700, 550,1700, 550,550, 550,1650, 600,1650, 550,1700, 550}; 25CHANNEL DOWN26unsigned int chanDown[67] = {4500,4450, 600,1650, 550,1700, 550,1650, 550,600, 550,550, 550,550, 550,600, 500,600, 550,1700, 500,1700, 550,1700, 550,550, 550,600, 550,550, 550,550, 550,550, 600,550, 550,550, 550,600, 500,600, 550,1650, 600,550, 550,550, 550,550, 600,1650, 550,1700, 500,1700, 600,1650, 550,550, 600,1650, 550,1700, 500,1700, 550};
Part 2: Arduino Cloud
From the main Arduino Cloud page, we'll create a new Thing and assign it a meaningful name. Let's call it TVRemoteController. We'll then select the board we are going to use. For this tutorial we used an Arduino Nano 33 IoT, but if you have another compatible board it will also be fine, just keep in mind that the pinout and the behavior of the IR library might change. If at this point you cannot see your board, you might have skipped the Getting Started procedure we mentioned above, if this is the case, go back through that process.
Once done, we'll add one Property to our Thing, it will represent our TV set. Under the Smart Home category, select "TV" as Property Type, set it as "Read & Write", and under "Update" select "When the value changes".
Here it is what the Properties view of our Thing should look like at this point:
Part 3: Arduino Web Editor
The time has come to click on the "EDIT SKETCH" button, which will take us the Web Editor, where we can add some custom code to the Sketch automatically generated by IoT Cloud.
The first thing we have to include is the IR Remote library, by Ken Shirriff.
1#include <IRremote.h>
We then have to setup one two-dimensional array for our channels, and 6 arrays for the commands we need. If you remember, in Part 1 we captured some IR data which we'll now use to fill our arrays
1const unsigned int chan[9][67] = {2 {chan1},3 {chan2},4 {chan3},5 {chan4},6 {chan5},7 {chan6},8 {chan7},9 {chan8},10 {chan9}11};12const unsigned int volUp[67] = {...}; 13const unsigned int volDown[67] = {...};14const unsigned int chanUp[67] = {...}; 15const unsigned int chanDown[67] = {...};16const unsigned int onoff[67] = {...};17const unsigned int mute[67] = {...};
Let's then setup the IR library and the required frequency (for this kind of application it will always be 38KHz)
1IRsend irsend;2const int freq = 38;
We'll also need a function to send out IR commands and blink the built-in LED (at this stage mostly for debugging purposes). The delay value used will depend on the make and model of your television, so feel free to tweak it if things aren't working as expected (wrong commands or no commands received).
1void sendIR(const unsigned int buf[]) {2 digitalWrite(LED_BUILTIN, HIGH);3 irsend.sendRaw(buf, 67, freq);4 delay(300);5 digitalWrite(LED_BUILTIN, LOW);6}
The final step is to complete the generated callback
onTvChange()
with some custom code in order to send IR commands when the TV property is changed by Alexa commands. For example, if the volume is increased, we have to virtually press the button Volume Up, if the channel is set to 7, we have to send the sequence for the channel 7 button, and so on.1void onTvChange() {2 Serial.println("==================");3 Serial.println("Switch:"+String(tv.getSwitch()));4 Serial.println("Volume:"+String(tv.getVolume()));5 Serial.println("Channel:"+String(tv.getChannel()));6 Serial.println("Mute:"+String(tv.getMute()));7 Serial.println("==================");8 if (first){9 prevSwitch = tv.getSwitch();10 prevVolume = tv.getVolume();11 prevChannel = tv.getChannel();12 prevMute = tv.getMute();13 first = false;14 return;15 } 16 // Volume changed17 if (tv.getVolume() > prevVolume) {18 tv.setMute(false);19 prevMute = false;20 for (int k = prevVolume + 1 ; k<=tv.getVolume(); k++) {21 sendIR(volUp);22 Serial.println("Volume requested:"+String(tv.getVolume())+" Set:"+String(k)); 23 }24 prevVolume = tv.getVolume();25 }26 else if (tv.getVolume() < prevVolume) {27 tv.setMute(false);28 prevMute = false;29 for (int k = prevVolume - 1; k>=tv.getVolume(); k--) {30 sendIR(volDown);31 Serial.println("Volume changed:"+String(tv.getVolume())+" Set:"+String(k)); 32 }33 prevVolume = tv.getVolume();34 }35 // Mute changed36 if (tv.getMute() != prevMute && tv.getMute()) {37 prevMute = tv.getMute();38 sendIR(mute);39 Serial.println("Mute changed:"+String(tv.getMute()));40 }41 else if (tv.getMute() != prevMute && !tv.getMute()) {42 prevMute = tv.getMute();43 sendIR(mute);44 Serial.println("Mute changed:"+String(tv.getMute()));45 }46 // Channel changed47 if (tv.getChannel() != prevChannel) {48 int newChannel = tv.getChannel();49 if (newChannel > 0 && newChannel < 10) {50 sendIR(chan[newChannel-1]);51 } else if (newChannel > 9) {52 if (newChannel > prevChannel) {53 for (int ch = prevChannel; ch < newChannel; ch++) {54 sendIR(chanUp);55 Serial.println("Chan requested:"+String(newChannel)+" Set:"+String(ch)); 56 } 57 } else if (newChannel < prevChannel) {58 for (int ch = prevChannel; ch > newChannel; ch--) {59 sendIR(chanDown);60 Serial.println("Chan requested:"+String(newChannel)+" Set:"+String(ch)); 61 }62 }63 }64 prevChannel = newChannel;65 Serial.println("Channel changed:"+String(tv.getChannel()));66 }67 // On/Off changed68 if (tv.getSwitch() != prevSwitch) {69 prevSwitch = tv.getSwitch();70 if (tv.getSwitch()) {71 sendIR(chan[6]);72 } else {73 sendIR(onoff);74 }75 Serial.println("Switch changed:"+String(tv.getSwitch()));76 }
Complete Sketch
Schematics
Part 4: Amazon Alexa
We will now need the Amazon Alexa app which can be downloaded from the Apple App Store or the Google Play Store. Once installed, login with your existing account or create a new one.
Let's go through the steps necessary to install the Arduino Alexa Skill and configure it to access and control our TV. We'll follow the sequence of images below to see all the required steps.
Conlusion
We're done, it's now time to voice control our TV asking things like:
- ”Alexa, turn the volume up on TV.”
- ”Alexa, mute TV" or “Alexa, unmute TV.”
- ”Alexa, next channel on TV.”
Have fun playing with Alexa and IoT Cloud.
Thank you,
The Arduino Team.
Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything wrong, you can edit this page here.
License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike 4.0 license.