Hackaday unleashes a Troll sniffing rat
posted Dec 19th 2010 2:00pm by Mike Szczysfiled under: HackIt

Sometimes we like to take a few minutes away from Hackaday to spend time with our families. But just when you take your eyes off of the incoming comments, Trolls are bound to strike. Well, [Caleb] and I found a solution to the problem in the form of a troll sniffing rat. This beady-eyed vermin sits on my desk and waits. When a trolling comment is detected its eyes glow red and an alarm is sounded. Join us after the break for more about this silly project.
Software
To pull this off I need a few things to happen. First, a way to parse our incoming comments. That’s easy, we use WordPress as our content management system and that means there’s already an RSS feed for global comments. I just need to grab that data and traverse the comment authors for known trolls (who haven’t been banned). That’s not hard to do with a Python script, especially if you take advantage of the Beautiful Soup module which sanitizes and navigates HTML and XML. My script checks the feed every two minutes, stores the number that identifies each comment so as not to have duplicate alarms, and makes decisions based on the author of that comment. A simple list of usernames is used to search for trolls, but it could be used just to notify whenever one of your favorite readers leaves a comment. The script then records a message on the standard output, and sends a coded command via a serial connection.
Here’s what the terminal output looks like:

And here’s the Python script:
#!/usr/bin/python
trolls = [ 'Mike Szczys' , 'Caleb Kraft' ]
signalAllComments = True
signalAllAudibly = False
import urllib2, time, serial
from BeautifulSoup import BeautifulSoup
#start a list of comments to prevent duplicate alerts
dupe = []
#setup Arduino communications
ser = serial.Serial('/dev/ttyUSB0', 9600)
time.sleep(5)
#get list of comment identifiers
while True:
#Reset Arduino from the last trigger
ser.write('z');
#Get the comments
html = urllib2.urlopen("http://hackaday.com/comments/feed").read()
soup = BeautifulSoup(html)
#Check each one
for item in soup('item'):
thisID = item('guid')[0].string.split('comment-')[1]
if thisID not in dupe:
#Add to the duplicate list for next time
dupe.append(thisID)
#Convert post time to local time
postT = item('pubdate')[0].string
parsedT = time.strptime(postT, "%a, %d %b %Y %H:%M:%S +0000")
offsetT = time.mktime(parsedT) - time.timezone
localPostTime = time.strftime("%m/%d/%y %H:%M:%S", time.localtime(offsetT))
#Check if this is a post we're watching
author = item('dc:creator')[0].string
if author in trolls:
print "(" + localPostTime + ") Troll Alert: " + author + " just posted a comment"
print " " + item('guid')[0].string
print
ser.write('a')
time.sleep(1)
elif signalAllComments:
print "(" + localPostTime + ") New Comment from: " + author
print " " + item('guid')[0].string
print
#audible signal?
if (signalAllAudibly):
ser.write('b')
time.sleep(1)
time.sleep(120)
Hardware
Next, I needed a way to sound the alarm when the parsing script identifies a troll. In my mind the easiest/quickest way to develop hardware connected to a computer is to use an Arduino connected via USB. I have an Arduino that I’ve never actually used for a project so I thought this would be a great start. I dug up a piezo buzzer and some LEDs and started looking around to see what code examples I could repurpose.

I found a post on making music using a piezo buzzer, so I altered that code to make the sounds I desired. I also looked at the serial communication examples that come with the Arduino IDE to get communications up and running. Like I mentioned above, I’m sending an ASCII char via serial connection from my Python script. The sketch below just looks for those chars and acts accordingly. I can make the hardware light the LEDs and play a bad sound when ‘A’ is received. It plays a good sound and does nothing with the LEDs when ‘B’ comes through. Any other letter turns the LEDs off, which is what the Python script uses to reset the LEDs two minutes after the last troll alert.
//Piezo code from:
//http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1241248988
void setup() {
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
Serial.begin(9600);
}
#define PIEZO_PIN 8
// defines for the frequency of the notes (.5 x freq of mid C)
#define AN 220 // 440 Hz
#define AS 233 // 466 Hz
#define BN 247 // 493 Hz
#define CN 261 // 523 Hz
#define CS 277 // 554 Hz
#define DN 294 // 588 Hz
#define DS 311 // 622 Hz
#define EN 330 // 658 Hz
#define FN 349 // 698 Hz
#define FS 370 // 740 Hz
#define GN 392 // 784 Hz
#define GS 415 // 830 Hz
// defines for the duration of the notes (in ms)
#define wh 1024
#define h 512
#define dq 448
#define q 256
#define qt 170
#define de 192
#define e 128
#define et 85
#define oo7 1 // 007 jingle
/////////////////////////////////////////////////////////////
void play_tune(int tune){ // play a tune . . .
switch (tune) { // a case for each tune
case 1:
for (unsigned char i=0; i<4; i++)
{
ToneOut(FS*4,et);
ToneOut(CN*4,et);
}
break;
case 2:
ToneOut(CN*8,e);
delay(16);
ToneOut(CN*8,e);
}
}
void ToneOut(int pitch, int duration){ // pitch in Hz, duration in ms
int delayPeriod;
long cycles, i;
//pinMode(PIEZO_PIN, OUTPUT); // turn on output pin
delayPeriod = (500000 / pitch) - 7; // calc 1/2 period in us -7 for overhead
cycles = ((long)pitch * (long)duration) / 1000; // calc. number of cycles for loop
for (i=0; i<= cycles; i++){ // play note for duration ms
digitalWrite(PIEZO_PIN, HIGH);
delayMicroseconds(delayPeriod);
digitalWrite(PIEZO_PIN, LOW);
delayMicroseconds(delayPeriod - 1); // - 1 to make up for digitaWrite overhead
}
//pinMode(PIEZO_PIN, INPUT); // shut off pin to avoid noise from other operations
}
void loop() {
if (Serial.available() > 0) {
int inByte = Serial.read();
// do something different depending on the character received.
// The switch statement expects single number values for each case;
// in this exmaple, though, you're using single quotes to tell
// the controller to get the ASCII value for the character. For
// example 'a' = 97, 'b' = 98, and so forth:
switch (inByte) {
case 'a':
digitalWrite(7, HIGH);
play_tune(1);
break;
case 'b':
play_tune(2);
break;
default:
digitalWrite(7, LOW);
}
}
}
The final piece of the puzzle was to put two red LEDs inside of a plush rat that we had lying around the house. The eyes were embroidered so I clipped the LED leads at an angle to make then sharp enough to pierce through to the inside. I used a Dremel sanding drum to make the clear LED package cloudy and to shave off most of the extra plastic. I then used a couple of KK connector patch wires I had around to attach to the leads on the inside of the rat head. After removing the stuffing from the body I pushed the connector all the way on and then bent the leads over the connectors. There’s picture of this below, but without the leads bent.

I restuffed the rat and stapled up the seam that I cut open to do the work. I love the outcome. It’s clearly audible throughout the house, and I had fun along the way.
It turns out that an $8 webcam and an Ubuntu box don’t make up a great video setup. But if you must see a demonstration, here it is:






awesome! :D