This page describes how we turned some electronic junk we found in a spare parts bin into a twittering waching machine and dryer.
PICDEM.net PIC Ethernet demo board by iosoft.
Marvell plug computer
Relays from RadioShack
Since we don't have source code for the PICDEM.net board, we were forced to use it as-is.
Therefore, the topology of our twitter system looks like this:
The sheevaplug runs a script which periodically contacts the PICDEM.net board. The PICDEM.net board, by default, comes with a web page that reports on the state of the analog input pins AN0 and AN1:
The washer and dry are connected to the analog pins of the PICDEM.net board using one relay each. We located a point in the wiring for both the washer and dryer that become 120V when the machines are activated. The relay, which has a large internal impedance, is wired between this point and ground. When the machine turns on, the relay trips, setting the cooresponding analog pin of the PICDEM.net board from 0V to 5V.
My landlord and friend Adam Wilson wired the relays in to the washer and dryer. You can see the steps here:

The unmodified washer and dryer.

Safety first! Turn off the fuse to the washer and dryer before working on them.

Opening the instrument panel of the dryer. The green paper is the wiring diagram, which we used to determine where to put the relay.

The dryer wiring diagram. We'll put the relay at the tip of this screwdriver.

This is the 120V relay (from RadioShack). The wires were first soldered to the contacts of the relay, and then sealed with hot glue for safety.

The relay is spliced in to the correct location in the dryer circuit. This is an image of the back side of the instrument panel.

The relay is now sliced in to the circuit. The gray wire goes out to the PICDEM.net board.

Adam has updated the dryer's wiring diagram in case any hapless repairmen come along to fix our dryer.

Opening up the washer instrument panel.

The wiring diagram for the washer.

Here, Adam is splicing the relay in to the correct location in the washer's control circuitry, also determined by checking the included wiring diagram. It's great that these appliances are open source!

The updated washer wiring diagram.

This image shows the relays successfully spliced into the washer and dryer control circuits. They're now ready to be hooked in to the PICDEM.net board (shown above).
I've updated the code for the tweeting laundry to be a single python script, which supports oauth authentication to twitter. The code is shown below. It is run in a screen session. You would have to replace the hashes with your own oauth secrets.
The project uses python-twitter. To get your keys set up, check out the example in python-oauth2 under Twitter Three-legged OAuth Example
#!/usr/bin/python
import urllib
import HTMLParser
import sys
import twitter
import time
board_address = '192.168.1.16'
ck = '############'
cs = '############'
washer_access_token_key = "#####################";
washer_access_token_secret = "#####################";
dryer_access_token_key = "#####################";
dryer_access_token_secret = "#####################";
past_washer_value = -1
past_dryer_value = -1
voltage_threshold = 3.0
sleeptime = 5
logfile = "/home/mhirsch/washerdryertweet/decode_tweet.log"
class WasherHTMLParser(HTMLParser.HTMLParser):
def __init__(self):
HTMLParser.HTMLParser.__init__(self)
self.reset_vals()
def handle_starttag(self, tag, attrs):
#print "starttag: ", tag, attrs
#print len(attrs)
if(tag == 'td' and len(attrs) == 2 and attrs[0] == ('colspan','2') and attrs[1] == ('align','center')):
self.getval = True
def handle_data(self, data):
#print "data: ", data
if(self.getval):
#print 'getval True'
self.vals.append(data)
self.getval = False
def reset_vals(self):
self.vals = []
self.getval = False
def get_vals(self):
return [float(self.vals[0]),float(self.vals[1])]
washerapi = twitter.Api(consumer_key = ck, consumer_secret = cs, access_token_key = washer_access_token_key, access_token_secret = washer_access_token_secret)
dryerapi = twitter.Api(consumer_key = ck, consumer_secret = cs, access_token_key = dryer_access_token_key, access_token_secret = dryer_access_token_secret)
parser = WasherHTMLParser()
try:
while True:
changed = False
f = urllib.urlopen('http://' + board_address + '/stat1.egi')
s = f.read()
f.close()
parser.feed(s)
vals = parser.get_vals()
if(len(vals) != 2):
print >> sys.stderr, 'Did not get two values out: ', vals
parser.reset_vals()
try:
timestring = time.strftime('%a %b %d %H:%M:%S %Z %Y')
if(vals[0] > voltage_threshold and past_washer_value <= voltage_threshold):
if(past_washer_value >= 0):
print "washer turned on"
message = timestring + ': I\'ve begun my darlings'
status = washerapi.PostUpdate(message)
print status.text
changed = True
elif(vals[0] <= voltage_threshold and past_washer_value > voltage_threshold):
print "washer turned off"
message = timestring + ': Our journey is at an end, my darlings.'
status = washerapi.PostUpdate(message)
print status.text
changed = True
elif(past_washer_value == -1):
past_washer_value = vals[0]
if(vals[1] > voltage_threshold and past_dryer_value <= voltage_threshold):
if(past_dryer_value >= 0):
print "dryer turned on"
message = timestring + ': RARGH DRYER GO'
status = dryerapi.PostUpdate(message)
print status.text
changed = True
elif(vals[1] <= voltage_threshold and past_dryer_value > voltage_threshold):
print "dryer turned off"
message = timestring + ': DRYER END'
status = dryerapi.PostUpdate(message)
print status.text
changed = True
elif(past_dryer_value == -1):
past_dryer_value = vals[1]
except Exception, e:
print 'Exception occured: ', e
raise
if(changed):
print 'change detected: ', vals[0], past_washer_value, vals[1], past_dryer_value
past_washer_value = vals[0]
past_dryer_value = vals[1]
if(vals[0] > voltage_threshold):
d1 = '1'
else:
d1 = '0'
if(vals[1] > voltage_threshold):
d2 = '1'
else:
d2 = '0'
ctrlurl = 'http://' + board_address + '/digout' + d1 + d2 + '.htm'
f = urllib.urlopen(ctrlurl)
f.read()
f.close()
time.sleep(5)
except KeyboardInterrupt:
print 'Got keyboard interrupt: Quitting.'
You can see the ongoing results on the twitter pages of our washer and dryer: