Ambient music pinwheel

Nicholas's picture

 

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()
 
2011-10-11 19.56.45.jpg
2011-10-11 19.55.42.jpg
0
Your rating: None