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

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 1
2unsigned 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 2
4unsigned 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 3
6unsigned 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 4
8unsigned 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 5
10unsigned 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 6
12unsigned 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 7
14unsigned 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 8
16unsigned 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 9
18unsigned 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 UP
20unsigned 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 DOWN
22unsigned 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 UP
24unsigned 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 DOWN
26unsigned 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:

Our newly created Thing's property view
Our newly created Thing's property view

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 changed
17 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 changed
36 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 changed
47 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 changed
68 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

Nano 33 IoT Schematics
Nano 33 IoT 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.

1/11: Tap on "Devices"
1/11: Tap on "Devices"
2/11: Let's now enable our Smart Home Skills
2/11: Let's now enable our Smart Home Skills
3/11: We'll be presented with the featured ones. Time to search for what we need :)
3/11: We'll be presented with the featured ones. Time to search for what we need :)
4/11: Typing "Arduino" and tapping "search" we'll obtain a list. That's the one we need!
4/11: Typing "Arduino" and tapping "search" we'll obtain a list. That's the one we need!
5/11: Once selected, we'll have to enable it
5/11: Once selected, we'll have to enable it
6/11: Let's login with our Arduino Create account credentials
6/11: Let's login with our Arduino Create account credentials
7/11: Our Alexa and Arduino Cloud can now talk to each other :)
7/11: Our Alexa and Arduino Cloud can now talk to each other :)
8/11: Time to discover our devices
8/11: Time to discover our devices
9/11: A little bit of patience won't hurt...
9/11: A little bit of patience won't hurt...
10/11: There is our TV, managed by IoT Cloud! Exciting :)
10/11: There is our TV, managed by IoT Cloud! Exciting :)
11/11: Let's tap on it to make sure it is enabled
11/11: Let's tap on it to make sure it is enabled

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.