Chrome Apps Office Hours: Controlling an AR Parrot Drone

Chrome Apps Office Hours: Controlling an AR Parrot Drone


[MUSIC PLAYING] MALE SPEAKER 1: Shanghai GDG
is a very interesting developer community. FEMALE SPEAKER 1: I’m
glad somebody has asked this question. MALE SPEAKER 2: This is where
the magic happens. FEMALE SPEAKER 2: This is
primarily a question and answer show. So if any of you out there would
like to ask questions– PETE LEPAGE: All right. Welcome, everybody. My name is Pete LePage. I’m a developer advocate
with the Google Chrome team here at Google. I guess I said Google
a few times. I have Google on
the mind today. And with me today joining from
London, we have Paul Lewis. PAUL LEWIS: Paul Lewis. Yes. PETE LEPAGE: Mr. Lewis, how
are you doing today? PAUL LEWIS: I’m very
good, thank you. As you said, live from London. So yeah all good. PETE LEPAGE: Excellent. Well, so last week, we had a
hackathon back in Mountain View that we were both there
for, and we got to play with some interesting hardware. We did some kind
of neat things. I sort of alluded to it in
our Hangout last week. But one of the big things that
I think you and Paul Kinlan did a couple days before was to
sit down and start doing a little bit of hacking
on one of the Parrot AR.Drones, right? PAUL LEWIS: Absolutely, yeah. So Chrome has the sockets API,
and we knew that this drone communicated over UDP. So what we wanted to do is find
out how difficult or how easy it would be to actually
get Chrome through a Chrome app talking to the drone. So that is exactly right. A couple of days before the
hackathon, as you said, Paul Kinlan and I sat down with the
documentation and started hacking away. PETE LEPAGE: All right. Well, so, we recorded some video
of us playing with this thing a couple days before
the Hangout. Let’s take a quick look at
that video right now. All right. So we didn’t put any audio into
the video, but you can see that drone flying around. Now, you hooked it up via a
gamepad, so the gamepad is actually controlling
the drone. The gamepad is hooked into
Chrome, and then Chrome’s connected via Wi-Fi to the
drone, and the drone goes flying around. Isn’t that– PAUL LEWIS: That’s
pretty much it. And what we’re going to do is
we’ll step through and talk through each of those
bits today. PETE LEPAGE: All right. So we’ll take– I think the video has just
a little bit more to it. We’ll take one more quick sec. We kind of had a lot of fun. We kind of crashed the drone– I don’t know– 300 or 400 times. We ended up having people
run away from it. It was kind of fun. And in fact, I think, we hit
each other with it a few times accidentally. It’s pretty easy to fly once
you sort of get the hang of it, but it took us a little
bit to get the hang of it. So the video is done. So let’s sort of jump in and
take a look at some of the things that went on. So do you want to start just
explaining how you started and what you were thinking about as
you were working on this? PAUL LEWIS: Absolutely. So if you still have me on
camera, this is the drone. PETE LEPAGE: Yep. PAUL LEWIS: This thing is
absolutely brilliant. And we had one of those. We have a standard gamepad. And as we said in the intro,
the gamepad API is what we used to get input. But actually, we didn’t
start with that. What we started with was the
SDK and the documentation. And the team at Parrot actually
have a PDF and a fully-fledged C library that
you can go and look at that will explain to you exactly what
you need to communicate and how and all the rest
of it to the drone. So that’s what we
started with. So if you want to bring
up my screen. PETE LEPAGE: I can do that. All right, so we have
your screen up. PAUL LEWIS: OK. So the first thing we
knew about was the fact that there are– I have them listed here. There are four socket
connections that you can make to a drone. One is on port 554– PETE LEPAGE: OK. PAUL LEWIS: –over UDP. And I’ll talk about what each
of these does in a second, 5555, 5556, and 5559. So we knew these four
ports existed. The 5554 is the one that you get
information back from the drone using. So it will actually
send over UDP. It will send you messages
regarding its altitude, its velocity, it’s battery levels,
all sorts of information that you can actually just get
straight back from this thing. Because this thing has got
really a lot of sensors on it. It actually gathers a lot
of information for you. So that’s how you
get that back. So you get packets on 5554. 5555 is this TCP channel where
it actually streams across H.264 video. So again, you can connect
up to that. As soon as you connect to it,
it starts sending you video information. Now, we actually haven’t
implemented it. I should say about this code,
not only is it on the GitHub samples, but it is not, shall
we say, a fully fledged covers-all-angles API. Certainly, it was more of a–
as you said, we did this at the hackathon as a
proof of concept. We wanted to actually see how
easy it was to get the communication going and
get the thing flying. But it’s not– as I say, it’s
not a replacement for anything that we’ve currently got,
which is a lot. So 5555 is the video. 5556 is what I consider to be
a really interesting one. This is actually how you send
commands to the drone. Now, the drone itself abstracts
away quite a lot of– well, an awful lot of the
hard work, judging from what I understand about flying over
remote-controlled vehicles. So, for example, one of the
AT commands, an AT command actually used to be used
when you’re talking to old-school modems. So you’d actually send
AT commands. We send just stream commands. So you send the drone AT
commands, one of which will be “takeoff, and it will
just take off and hover waiting for you. Another one is “land.” Again,
we’ll step through some of these in a little more detail. So you actually construct all
these AT commands per frame that you want to send
to the drone. And then the last one is the
command one, which you can see at the bottom of my screen,
which is on 5559. And I’ll just scroll up. 5559, and that is used for sort
of admin controls, admin commands that you
need to send. Just because you’re potentially
sending an awful lot of information, as I
understand it anyway, over the AT command on 5556, there is
a chance that you could be losing packets because
this is over TCP. So if you’re not familiar with
the differences, basically TCP is guaranteed delivery. UPD is not. So we send a lot, and so there’s
a possibility that certain command packets
could get lost. So the command one at the bottom
there, that 5559, is like a separate channel on which
to have a discussion with the drone and say certain
things, like emergency cutouts, I believe, on that
channel, which you kind of want, really, if it’s going
to be an emergency. PETE LEPAGE: Yeah. It’s kind of useful. PAUL LEWIS: So those are the
four sockets that we need. And if we go down, you’ll
see that I’ve got an init in the API. And init connects three
of the four. As I say, we haven’t
done the video one. It connects with the AT, the
nav, and the command sockets. And that looks a little
bit like this. So you’ve got
chrome.socket.create. And in those objects that I had,
you’ve either got UDP or TCP, which is the first
parameter, an unused second parameter, and then
the callback. Don’t forget that all the Chrome
APIs are asynchronous. That sends you back soc info
which tells you things like the socket ID of the socket
that you just created. And that then allows you to
do connects and binds. So again, it’s one
of these things. It’s worth looking at the
socket documentation. And it’s worth spending a bit
of time understanding socket communication in general. But we have different things
like bind and connect. So we do, depending on
what it is need. So, for example, when we bind a
socket, that’s normally when we want to receive
information. When we connect, it’s
typically when we want to send out. It’s not entirely the same, so
there are subtleties to this. So what we do is we go through
and create those sockets. And you’ll see when we do that,
we just have a little callback that says when
we’re connected. If we’ve got nothing left to
connect, then we start actually communicating
with the drone, which is always nice. 2 we send the KeepAlive command
roughly every second, which basically says to
the drone, I’m here. I’m here. I’m here. If you don’t do that, after 2
seconds, the drone determines that you are no longer around. And I think it goes into hove
mode waiting for you to actually reconnect. So it’s good to send
those KeepAlives. FlatTrim, that says– because this is the
first thing we do before we take off. We say to the drone, you’re
on horizontal ground. You need to calibrate as though
this was flat ground. Because one of the many
things it does is it keeps itself level. So the FlatTrim is used for that
to actually work out what level and medium it
is, I suppose. Sensitivity. You can set the sensitivity. So when you’re actually flying
this thing, how sensitive it is, I actually have it set quite
sensitive, which may explain how difficult I made
it for you to fly, Pete. PETE LEPAGE: Well, I
wasn’t that bad. It was more the– I don’t know. The first couple of times I
think we were trying this, it was kind of fun because I think
for both you and I, we were trying it for
the first time. We had never done it before,
and we were going on this sucker in a kind of a slightly
windy situation. So we were in an interesting
place where, hey, were outside– because we didn’t want to try it
inside because when we did try it inside, we ended up
hitting a few walls. Oops. And then a few times, once we
got outside, it was good, but we ended up having people
running around. So it made for a kind
of fun time. PAUL LEWIS: It certainly did. So this is all by way of
bootstrap at this point. So we’ve opened up our
socket connections. We’ve sent a few commands. And I can dig into those
commands in a second, but the main thing to know is we
then go into this loop. And this is the bit that is
the heart and soul of what’s going on. So let me drop down to loop. Where is it now? Loop. OK, so you’ll see that we’ve got
these drone commands, and I will show you what one
of those actually is. The first parameter is
the actual command. Now, if you look inside the
documentation, you’ll see that, typically, the commands
are like AT* and then a specific command. And one of those specific
commands is this PCMD_MAG. And then normally there is
a comma-separated list of parameters after which,
actually, what you’re configuring. So in this case, the PCMD_MAG
is for telling the drone how to fly, so it’s left
and right tilt. So here’s the thing. If you’re looking at the drone,
it’s got left and right tilt, front and back tilt, which
is it actually flying. Then there is vertical speed,
which is kind of up and down its elevation, and then there’s rotation, the angular speed. So you see, all four
of those things are actually captured here. PETE LEPAGE: Right. Now, the one thing, and you
probably are going to go into this in a sec, but I saw that
float 32 to int 32. And I’m like, why the heck
would you convert a float to an int? And why are you doing it
yourself instead of just using one of the built-in functions? Like why not just do floor or
ceiling or something like that where we can get a much
more manageable value? PAUL LEWIS: So for whatever
reason, the drone likes to receive float values
as integers. So say, for example, the left
and right tilt, so that’s the sort of flying left and right. You get a number between
minus 1 and 1. That’s what you’ve got
to send the drone. But bit-wise, that comes out
as a completely different number as an integer. So the actual bits for a 32-bit
flow, that make up minus 1 look very different to
the bits that would make up an integer at minus 1, as
I understand it. So we wrote the Util. So DRONE.Util.float32ToInt32,
which converts at the bit level. And what we do is actually
very useful if you ever need to do it. The array buffer is your
best friend here. And so we create a 4 byte,
so that’s 32 bits. We create a 4-byte ArrayBuffer
and then a DataView on that buffer. And then we set a 32-bit float
on our buffer with a value, and then we read back
out an integer 32. So it’s definitely worth looking
into DataViews and ArrayBuffers if you’ve ever
come across them. The ArrayBuffer is sort of– it’s almost data agnostic. It doesn’t really care. It’s just going to store
bits and bytes. It doesn’t really mind. It’s the views that you
attach on the top. So DataView is good when you
need to push in and pull out data of different types like
unsigned integers, integers, floats, some of them 16
bit, 8 bit, 32 bit. So it gives you all these
different ways of actually accessing the underlying
bits and bytes. So that’s how we actually do
that conversion from a 32-bit float to a 32-bit integer. So that’s why. It’s just simply because that’s
how the drone likes to receive its data. How it then actually deals with
it on the other side, I’m not so sure. So one of things we’re doing,
is we’ve got these numbers that we’re converting, the left
and right tilt, the front and back, the vertical speed
and the angular speed. And we’re converting those
or wrapping them up in a drone command. So let me show you a drone
command, which is remarkably simple. We create a command with the
actual command string, which in that case was PCMD_MAG and
then the actual parts of the message that we want to put
after the command, so the actual values themselves. So you’ll see in this case,
this has one, two, three, four, five, six, seven. I’m not using six and seven
as you can see. I’ve just filled them
with zeroes for now. And then whenever we actually
write it out to a string, you’ll see, I mentioned at the
start, we have this AT* followed by the command. PETE LEPAGE: Right. PAUL LEWIS: That’s exactly
what we’re doing here. When we say give me this drone
command in a string format, it converts it and says AT command,
AT*, followed by the actual command. And then you’ll see this
DRONE.Sequence.next. Every message that you send
to the drone increases incrementally, increases
by one every time. That’s a better way
of saying it. So we start off at one. The first command you send has
a sequence number of one, and it just goes up from there. So we just keep a track on that
internally so you don’t have to remember which number
you’re on and so forth. And then we just simply join
together with commas the different parts of
the command. PETE LEPAGE: So I just want
to interrupt for one sec. As people are watching this, if
you have questions, you can go post your questions to the
Google Moderator queue. If you go to
http://goo.gl/gHCgH. I’ll get that posted on
screen here in a sec. But again, that’s small g,
capital H, capital C, small g, Capital H. PAUL LEWIS: Awesome. So we’ve got this command that
actually tells the drone where to fly and so forth, but for the
eagle eyed among you, you will have realized we’ve
not actually told the drone to take off. Luckily, that’s the next one. And that simply just
takes a number. So the commander here is ref
and it takes a number. There are two numbers– takeoff and land. So they’re just stored in
certain, I believe, open constants up here. I have take off and land. It’s two magic numbers. So let me see now. Take off and land. So it’s interesting then
that you’re in this situation where– oh, it’s also worth saying
these numbers are absolute values. So one of the things about
sending these packets repeatedly to the drone is you
might be thinking, well, what if packets get dropped? How is it going to
cope with that? So there’s a couple
of things here. One is that we lop about
every 30 milliseconds. And again, the SDK recommends
roughly that rate, that you send these commands roughly
that often. But these values are absolute. So for example, the tilt is a
value between minus 1 and 1. The drone seemingly doesn’t
expect you to interplay between numbers or anything
like that. If you say 0, it’s just
going to stop there. If you say minus 1, it’s
going to go off. And as soon as you say 0 again,
it’s going to stop. So it’s not like you have to
manage the transition between those numbers. So in that sense, we’re sending
more than enough packets to just get through to
the drone to say, here’s how I want you to behave right now. And certainly in our
experience it’s worked out just fine. PETE LEPAGE: All right. PAUL LEWIS: And then let’s look
at the actual action. So we expose through this API
a number of actions that you can actually do– take off, land, raise and lower
the drone, tilt left and right, which we talked about. So there’s the flying ones,
the tilting ones. Then there is rotation, and
then there’s an all stop, which basically just resets
all those values to zero. You can see they’re all set on
this status object, which we use when we’re actually pulling
out those values. So we have this single source of
truth internally to the API as to what we think the drone
should be doing, OK? PETE LEPAGE: All right. PAUL LEWIS: So these
all get exposed. And that’s really all there is
to it in terms of actually sending out information. We do pick up the nav data. Let me just find that. Now, I don’t pick it
up all that often. It’s something I like to do with
mine is to actually pull in enough data and to use it to
visualize what’s going on a little bit more. But what we do is, we read
from that nav socket. And if you remember back at the
start, I said 5554 is the socket on which the drone
is going to send its information to you. So we read from that. And if we have data, we just
run it through this DRONE.NavData.parse. So this just comes back as
an array buffer, and it contains some data. And the data it contains,
as I said, is things like you can see here. We get things like battery
percentage, its angles, its altitude, and its velocities. And what we do is this array
buffer that comes back in through the socket, we attach
one of those DataViews again on to that data so we could
start pulling things out. And then at very known positions
from within that array buffer, we can start
pulling numbers. So the battery is, for example,
I think at the 24th byte or thereabouts, maybe
slightly further on. So as I say, the documentation
has all this listed for you as does the source code. So it’s more a case of flushing
out and saying, OK, I got this data back
from the drone. It’s just this raw data. Now, I actually need to
specifically attach on a DataView and sort of pull the
numbers out manually. And then obviously, we wrap
those back up as an object and return those if needed. So you might think it’s actually
more complicated to talk to a drone. It’s actually not. Chrome does a great job of
abstracting away this socket read and write, stuff
that you need to do. And so it’s really just a case
of opening the socket, following the instructions,
and start reading and writing data. So then the other side of this,
unless you’ve got any questions, Pete. PETE LEPAGE: No. I’ll let you keep going. PAUL LEWIS: All right. Cool. So now, we’ve got this drone
API, and we wanted to wrap it up inside a Chrome app
and put a gamepad API on it, and so forth. So one of the first things I did
was to get one of these. PETE LEPAGE: Right. So the gamepad controller. PAUL LEWIS: Yep, and drop
that into Chrome. And then on HTML5rocks– and we can put this link up in
a little bit– we have these tutorials on the gamepad. Because one of the things about
the gamepad API is it’s gamepad agnostic. And that means it can be quite
interesting to work with, because it doesn’t say, oh,
this is the X button the square button. It just says this button one or
button two, button three, button four. So when you actually know the
pad you’re dealing with, often it can be good to abstract
that away a little bit. And that’s exactly what this
code does, and it’s on HTML5rocks. It’s definitely worth reading
through because it’s a really good introduction to
the gamepad API. But you’ll see right at the
bottom of here, I’ve wired it up so that I have this
DRONE.Gamepad. So I abstracted the gamepad a
little bit further and have this updateButton
and updateAxis. So every button on the gamepad
and every axis for the sticks, the sticks over here, they get
sent through to me through this update button and– PETE LEPAGE: So you’re listening
for each of those. PAUL LEWIS: This is actually
done through polling. So there aren’t events
for the gamepad API. It’s a polling API. So yeah, you send a request from
the gamepad, OK, button-1 or button-0, what’s its
current status? So that gets sent through. Now that, curiously enough,
actually fits with our model because we’re going to be
sending data to the drone very often as well. We know we’re polling
the gamepad. We’re getting the latest value
from the gamepad, and we send that through to the drone. We pipe it through the
API, but we send that through to the drone. So let me just fire up. I believe it should be in
the drone’s gamepad API. So you can see in the
updateButton and updateAxis, we have a little bit going on. Let’s talk about the
updateButton. So updateButton, that gets
called whenever I press– or, in fact, it gets called
several times a second. All I’m looking for is whether
the value is 1, so press down. Now, if it’s the right shoulder
button, you’ll see I’m telling the drone
to take off. If it’s the left shoulder
button, land. And the select button on
here is the all stop. It’s the one that actually
says all the numbers, go back to zero. PETE LEPAGE: So one of the
things that, as you were talking about this and telling
me about this originally, the question I had is, so are you
using RequestAnimationFrame to do these loops, or are you
doing a setTimeout? PAUL LEWIS: So we are using
the setTimeout, because RequestAnimationFrame would drop
to one frame per second if the tab or window wasn’t
actually focused. In the Chrome apps
situation, it’s possibly slightly different. I would need to do a double
check, but we really want that data to be sent in any case. And it’s not visual
updates that we’re doing to the browser. So it’s probably a suitable
situation in which to use the setTimeout. I think at the bottom of the
loop there, you’ll see setTimeout is what we’re doing
for making sure that we call a loop whether or not we’re
actually in a minimize, maximized, or all the apps
on view, on screen. All right, so the gamepad. One of the interesting things
about the updateAxis, so the values here on the axes are
minus 1 to 1 in both the axes, which maps extraordinarily well
to our drone, which takes values of minus 1 to 1. So pretty much all we do is we
take whatever the value is on that particular axis, and you’ll
see if it’s stick-1, which is the left one, we just
pass it, tilt left and right, and tilt front to back. Stick-2 is going to be
used for rotation and raise and lower. And that’s it. That’s all that is involved
with the gamepad API. So there you go. That is pretty much it. Everything else is just icing
on the cake in terms of actually putting together
a standard Chrome app. What I should say, I have missed
something, which is the permission side of things. Socket permissions are required
if you’re going to actually open and use
socket connection. So I’ve got udp-bind send-to,
and tcp-connect, tcp-listen. Those are documented on the
developer.chrome.com/apps site, and you could actually
have a look and see what permissions you would need if
you were going to build something like this. So don’t forget to add those
socket permissions to your manifest if that’s what
you’re doing, OK? PETE LEPAGE: All right. Cool. Well, we seem to have a few
questions coming in. So let’s pop over to some
of those questions and see what we can do. So the first question is
“what’s the latency in milliseconds for controlling
and getting the center data from the drone? Is it similar to the Parrot app
on smartphones or is it worse?” What was your
experience on that? PAUL LEWIS: So we haven’t
actually tested this comparatively or anything. But what we have done is we’ve
made those socket APIs quite close to the metal. So they’re really quite
performant and really fast. And certainly, I’ve had no
problems getting messages through to the drone
or getting messages back from the drone. So while that’s empirical,
it’s something that I can certainly say for sure
that it’s been no problem to work with. PETE LEPAGE: OK. And so we do know that it’s not
going to probably be like instantaneous, but it should
be pretty quick, and we can see how things go. That’s maybe something we can
have a look at and add to the documentation or something
like that. PAUL LEWIS: There is worth
bearing in mind that the drone creates its own Wi-Fi network. I’m not sure if I said
this at the start. It creates it’s own Wi-Fi
network when you switch it on. PETE LEPAGE: Oh, interesting. That’s right. So it’s not connecting to your
personal Wi-Fi network or anything like that, which would
be really cool, because it would mean like here at work,
we could connect it to the Google wireless. I could be at one end the
building or I could have it here, and you could
fly it in London. PAUL LEWIS: I’m terrified of
you having a drone army, remote drone army. That’s the stuff
of nightmares. PETE LEPAGE: Yeah. It would be kind of fun,
though, I gotta say. PAUL LEWIS: Yeah, it would. So because of that, it’s
not going through any routers or switches. I mean, I’m no networking
hardware expert, but that certainly gives you
every chance. PETE LEPAGE: Cool. And you do have those multiple
channels, so that way, you can get stuff back. If you’re sending a bunch of
commands out to one, you’ve got that emergency channel that
you can get something in. Obviously, it’s not going to
be perfect for getting the stuff back, but it at least
gives you a well thought-out API that you can play with. PAUL LEWIS: Definitely. I mean, this is UDP. Like I said, UDP is not
guaranteed delivery by the very nature of the protocol. But there is a lot of traffic. So the other thing to say is all
the messages back from the drone are sequenced. So if you did manage to get
something out of order, you can always check the sequence
number and make sure it’s greater than the last
one you received. PETE LEPAGE: Oh, perfect. PAUL LEWIS: Which is as you’re
sending an increasing sequence number, so is the drone. They don’t relate, but they
both go up over time. PETE LEPAGE: OK. Cool. So Devon wanted to know how he
could get started with Chrome apps or get pointed in
the right direction. And Devon, I think that’s
a great question. And there’s a lot of good
resources and watching events like this is certainly one place
as we dive into a bunch of the APIs and some of the
things that you can do. But the best place you can go
is to the Chrome Developer documentation. So if you go
developer.chrome.com and have a look on the right-hand side,
there’s a link there that says Chrome Apps. Click that. There’s some really great stuff
on how to get started. The other good one that’s really
interesting and really useful is to check out the I/O
talk that was done by Erik and Mihai, two of the engineers
on Chrome apps. So if you go to google.com/io
and look for the session that they did, Eric Kay, Mihai, and
I’m going to mispronounce his last name but it starts
with a P. PAUL LEWIS: I’m leaving
you hanging here. I don’t know how to
spell Mihai’s name either, I’m afraid. PETE LEPAGE: Awesome. All right. PAUL LEWIS: The other thing,
Devon, it’s worth watching previous sessions
that we’ve run. The first couple of weeks, in
particular, we talked about the Hello World and what the
APIs are and CSP, Content Security Policy, and all
those kinds of things. So definitely worth watching
those as well if you have time PETE LEPAGE: Yeah. And you can find those
all if you go to developers.google.com/live, and
look at the Chrome events. We’ve done now– I think this is our fifth or
sixth Hangout that we’ve done. And we’re doing them
as a weekly event. So next week, we’ll do
a different topic. We’ll dive into some new stuff,
show you guys some pretty neat things that
are going on. So the next question, I think,
Paul, this one’s pretty much for you. “What sort of line theme
that you are using?” PAUL LEWIS: It’s Coda doc,
and it’s Monokai is the color theme. I had to double check
that just then. I wasn’t sure. It’s been a while since I’ve
changed it, but yeah, it’s sort of dark and Monokai
is the color scheme. OK. PETE LEPAGE: So now, you’ve
taken this code, you put this code up on GitHub. Is that right? PAUL LEWIS: Yeah, so it’s
GitHub.com/googl echrome/chrome-app-samples. We talked about this over
the last few weeks. It’s the normal GitHub report
that we mention each week. So take a look at that. It’s under there as
Parrot AR.Drone. And the code is commented. As I said, it’s not going to
cover every angle, but if you want to see about how you can
get started with socket programming, it should be one
of several good examples. PETE LEPAGE: Yeah. It’s a good, easy way to sort
of way to look at some of those things. There’s lots of devices out
there that do have IP and socket-based stuff. In that set of samples, there’s
ones that will do– I think there’s a telnet one
if I’m not mistaken, and there’s a couple others so that
you can go and play with those kinds of things. And there are other hardware
devices that you can pick up. The one that I’ve been playing
with recently, because I want to figure out a way to control
my air conditioners. I’ve got a window air
conditioner here in New York City, and it gets a
little hot, and I forget to turn it off. Got my first electric bill the
other day and oh, yeah. Don’t forget to turn your
expensive appliances off, because they, um– not pretty. In any event, I want a Chrome
app that will allow me to turn this on and off. And so there’s an IP to infrared
controller that I found that will allow me to go
and do that kind of stuff. So that’s just another example
of some of the hardware control that you can do
with Chrome apps. So with that, I think that’s
about the end of our questions for this week. We’re going to be back next
week with the polls, with Renardo, myself. And we’re going to be diving
into some more stuff about Chrome apps. So with that, thanks,
everybody. I hope you have a wonderful
week, and we’ll talk to you all soon. PAUL LEWIS: Thanks. PETE LEPAGE: All righty. Bye, everybody. PAUL LEWIS: Bye. [MUSIC PLAYING]

Eugene Islam

Leave a Reply

Your email address will not be published. Required fields are marked *