Geeks In Residence

Make dumb speakers smart: “Internet Of things”

Written by Dhash, Camp K12’s 18-year old Geek in Residence. Enjoy!

The internet of things is a generic term, coined by multiple companies to address a very complex set of problems, that of interconnection between various devices to automate certain parts of your everyday life. The important word there is interconnection, as that’s (for the most part), what these systems do. They expose something that’s called an API, which (very simply) is just a way for other programs to either set attributes about the device, like

  • Brightness / color of a smart light bulb
  • Volume of a speaker (What we did)
  • On / off state of a device (Useful for a smart home) or to get info about attributes the device possesses, such as
  • Current power draw
  • State of the device (Read)

 

With the possible API endpoints that are exposed by a smart device, and a way to generate clients that can access these endpoints (e.g. A smartphone app), as well as a network stack to transit this data (We used the TCP/IP stack, and HTTP POST requests on top of it), we can map arbitrary inputs to smart device outputs, since we know exactly what each devices I/O is composed of.

How did we make dumb speakers smart?

Components

  • 2 USB chargers and 1 wall wart 12v power, for the Speakers, Raspberry Pi, and Router respectively
  • 1 Router, consumer grade, with wifi and ethernet
  • A pair of speakers (USB powered)
  • 1 Raspberry Pi B+
  • A bit of ethernet cable (Pi has no native wifi chip)
  • A smartphone

Raspberry Pi?

The only thing that might be unknown on that list is the Raspberry Pi, a credit-card sized computer. We’re using it here only as an embedded chip, but it allows us enormous flexibility in terms of what we can do later, since we can just treat it like a box that runs our code, easily and fast enough. The longer explanation of what it actually does can be found in this video, produced by the Raspberry Pi team.

Wiring Setup

 

Camp K12 IOT Demo Wiring Diagram

Understanding the code

So now that we know what the internet of things is at a low level, we can build something that uses what we know. We built out a small deployment out of a smartphone, a Raspberry Pi, some speakers, and assorted networking gear. We wanted to control the volume of a file playing locally on the Pi with a phone, so we first figured out what sensors we could tap into from the phone, and what commands we could use to modulate the Pi’s volume out of its TRRS jack (3.5 mm jack, aux cable, etc).

We used a somewhat modern smartphone, so it had the sensors we’ve all come to know and use in a smart device, nameley an acceleromenter, a gyroscope, a proximity sensor and a compass. We settled on the idea of tilting your phone to set the volume, but you can use any sensor input at your disposal to do so.

Now we had to figure out how to transit information about the phone’s sensors to the Pi to modulate its volume. The easy way out was just to transit over consumer-grade network hardware, using HTTP. Very simple and dead easy to setup. In an actual large scale deployment this may not be the best way to go about it, and in that case a mesh network made out of XBEE’s or any other device that doesn’t use the congested 2.4GHz bands may be better.

Lastly, we have to write a very small amount of code to publish a server that can handle the HTTP GETs and POSTs generated by the other endpoint, the phone. A small Flask server will suffice, as we’re more concerned with speed and ease of getting this up and running. The main component of this server is the views.py file, which defines route information, and what to do when a route is accessed. In this case we accepted an HTTP POST at the/vol/<int:lvl> route, which taken an integer from the POST route that the phone would output, bind that to a local variable, and run the amixer set PCM {lvl}% command. This may seem insecure, but flask handles all the sanitation for us, so it’s fine.

from flask import flask, request
from app import app
from subprocess import call

@app.route('/')
@app.route('/index')
def index():
    return "IoT demo!"

@app.route('/vol/<int:lvl>', methods=['GET', 'POST'])
def volume(lvl):
    if request.method == "POST":
        call(["amixer", "set", "PCM", "{}%".format(lvl)])
        return "Set volume to {}%".format(lvl)
    else:
        return("POST the volume!")

Now let’s see what exactly happens in the lifetime of a request to change volume. We take the average of the gyro values in a time period, to eliminate jitter, and map that from a value from 1 to 100, being the volume level we wish to set. The phone then makes an HTTP POST to the /vol route, which then pulls the associated reading out of the request, and sets the volume on the Pi.

 

diagram

Conclusion

It’s really easy to set stuff like this up, since the tooling exisits to do it in a very user friendly and accessible way (Raspberry Pi’s are cheap, web servers and smartphone apps are super simple to write) and it’s very extensible, since you can do pretty much what you want with the level of I/O the Pi provides, (HDMP, Ethernet, USB, GPIO) especially since it’s just an ARM computer running linux. This is just one simple application of it.

Go forth and hack cool stuff together!

One Comment

Leave a Reply