Description
I built a small pinwheel device that spins when a remote person is listening to music. The idea is to communicate presence at a distance, or to enable someone to have an ambient indicator of another's actions (in this case, listening to music). This can help strengthen a personal connection, for example in a long-distance relationship.
The device requires that the monitored person use Last.fm's scrobbling service. A python script runs on the host computer that polls for whether a user is currently listening to a track; if so, it sends an "on" signal to the device. When the user is no longer listening to a track, it sends an "off" signal. Due to the information Last.fm's API makes available, the device activates within 10 seconds of a user listening to a track, but takes around 5 minutes to shut off after a user stops listening to the track.
Materials
Hardware
-
1 Arduino
-
1 TIP120 transistor
-
1 1N404 diode
-
1 100k resistor
-
1 potentiometer
-
1 3V battery pack
-
1 DC motor
-
Tissue paper
-
Styrofoam peanuts
-
Origami paper
Software
Code
Arduino:
/*
* INFO262 - S6: DC motors
*
* Program that scans the serial port and spins a motor
* if a '2' is sent across. Designed to operate with the
* last.fm bot.
*
* Author: Nicholas Kong
* Date: October 11, 2011
*/
int potPin = 0; // select the input pin for the potentiometer
int motorPin = 9; // select the pin for the Motor
int val = 0;
char serInString[100];
boolean spinning = false;
void setup() {
Serial.begin(9600);
}
void loop() {
readSerialString(serInString);
// Application expects a '1' when the target user is no longer listening
// to a song, and a '2' when the user is listening to a song. The motor
// only turns on when the user is listening to a song.
if(serInString[0] == '2') {
spinning = true;
} else if(serInString[0] == '1') {
spinning = false;
val = 0;
}
if(spinning) {
val = analogRead(potPin); // read the value from the sensor, between 0 - 1024
}
memset(serInString, 0, 100);
analogWrite(motorPin, val/4); // analogWrite can be between 0-255
}
//read a string from the serial and store it in an array
void readSerialString (char *strArray) {
int i = 0;
if(!Serial.available()) {
return;
}
while (Serial.available()) {
strArray[i] = Serial.read();
i++;
}
}
Python:
'''
INFO262 - S6: DC motor
Pings last.fm every 5 seconds to check if a user-specified user
is listening to music. If so, sends a '2' across the serial port.
Defaults to 'quasiphoton' (author's username) if no username is
given. Requires the PySerial library.
Usage:
python lastfm_checker.py [username]
Author: Nicholas Kong
Date: October 11, 2011
'''
import serial
import sys
import httplib
import urllib
import calendar
import time
from xml.dom.minidom import parse, parseString
class LastFMParser():
def __init__(self,user):
self.key = REDACTED
self.curDom = []
self.recentLimit = 600
self.lastfmurl = 'http://ws.audioscrobbler.com/2.0/?'
self.parameters = {
'method': '',
'limit': 1,
'user': user,
'api_key': self.key
}
def fetchCurrentlyPlaying(self):
self.parameters['method'] = 'user.getrecenttracks'
result_xmlstr = urllib.urlopen(self.lastfmurl, urllib.urlencode(self.parameters)).read()
print result_xmlstr
self.curDom = parseString(result_xmlstr)
tracks = self.curDom.getElementsByTagName("track")
for track in tracks:
if track.getAttribute('nowplaying'):
print 'nowplaying'
return True
return False
if __name__ == "__main__":
user = 'quasiphoton'
if len(sys.argv) > 1:
user = sys.argv[1]
ser = serial.Serial('/dev/tty.usbserial-A7006vDV')
lfmp = LastFMParser(user)
try:
while True:
playing = lfmp.fetchCurrentlyPlaying()
if playing:
print 'playing'
ser.write('2')
else:
print 'not playing'
ser.write('1')
time.sleep(5)
except (KeyboardInterrupt, SystemExit):
print "Closing serial port"
ser.close()