After a little more than a year of ownership and the main reason that I haven't been updating my blog, I sold my Boxster (the Great White). She was a good car but after buying a 911 in early Spring, I just wasn't driving her much.
My family is much sadder than me though cause they liked the Boxster better than the 911.
I really love the mid-engine Boxster and will probably buy a Cayman S in the near future. After getting the Porsche bug, I wasn't happy until I had a 911. What a complete different experience. The Boxster is refined and hugs the curves like no other car I ever driven. The 911 is raw, loud and dares you to give it too much gas so it can swing its ass around and make you look like a noob driver. But it's so fast and the power is addicting.
13 August 2010
09 August 2010
Sanyo DP26648 White Screen of Death
Santa brought my game player son a Sanyo SP2664 26-inch Widescreen LCD HD Television last Christmas. A few months into the year, the TV started getting occasional white lines diagonally across the screen, the greens looked weird, and then the audio went in/out. I could've/should've hauled it back to Wally Mart but grumbled about it and did nothing.
We came home from our July 4th vacation and the darn TV is dead. White Screen of death. No sound, just a stupid looking white screen.
An interesting thread on the Electronics Repair Google Group led my son and I to think that we could fix this beast.
According to the thread, "it has been reported that there is a defective ribbon cable that causes this problem". And the possible fix is "Clean glue like material from spaced further apart trace of FFC ribbon or replace the ribbon wire P/N: N6CD FFC".
Well, I'm pleased to report that we hacked and smashed and tore that darn TV up, finally got to the elusive cable. And it looks nothing like that picture. Our cable looked fine, no glue, seemed like a good connection. And the TV remains broken and in 300-bazillion parts.
We had fun exploring the TV but it would have been a better story if the darn thing would have actually been easy to fix. I think our TV had more wrong with it than just the cable. But if your TV is showing the white screen of death, read the link and good luck.
We came home from our July 4th vacation and the darn TV is dead. White Screen of death. No sound, just a stupid looking white screen.
An interesting thread on the Electronics Repair Google Group led my son and I to think that we could fix this beast.
According to the thread, "it has been reported that there is a defective ribbon cable that causes this problem". And the possible fix is "Clean glue like material from spaced further apart trace of FFC ribbon or replace the ribbon wire P/N: N6CD FFC".
Well, I'm pleased to report that we hacked and smashed and tore that darn TV up, finally got to the elusive cable. And it looks nothing like that picture. Our cable looked fine, no glue, seemed like a good connection. And the TV remains broken and in 300-bazillion parts.
We had fun exploring the TV but it would have been a better story if the darn thing would have actually been easy to fix. I think our TV had more wrong with it than just the cable. But if your TV is showing the white screen of death, read the link and good luck.
25 December 2009
LG Washer LE Error
UPDATE: I've had quite a few hits on this posting and received lots of great comments - thanks very much.This post explains how to replace the hall sensor on your LG washer. Before you decide that you have to replace your hall sensor, please try unplugging your washer for 5-10 minutes and see if it will reset all on its own.
Also, even after replacing the sensor, sometimes these washers will display "LE" a week or month later and they just need a time-out (unplugged). Good luck!
I've also had a few questions on what the heck is a hall sensor. Here's a whitepaper with a good description, design notes and ideas on what else you can do with these things.
-------------------------------------------------------------------------
We had a really nice Maytag washer and dryer set. They were a billion years old (maybe 15 actually) but ran strong and had zero problems. Spring 2007 we decided to remodel our laundry room and of course we had to have the super duper LG WM2075CW 27" Front-Load Washer with 3.72 cu. ft. Capacity, 7 Cycles, 6 Options, SenseClean and 8 Hours Delay Wash.
About $800 delivered. Nothing but the best for my socks and undies (boxers btw).
Everything has been great except the week before Christmas 2009, Mr LG wouldn't work. It would grunt and click and then put "LE" on the display. A quick Google yields lots and lots and lots of hits with the Load Error (LE).
A number of things can cause an LE but the most common is a malfunctioning Hall Sensor. Seems that LG washers are pieces of crap and this is a well known problem. LG has extended the warranty on the part to 7 years but they won't ship the in-warranty part to consumers. They'll only ship to a certified service company. After several phone calls to LG and way too many minutes on hold, I finally just ordered the damn thing from MCM Electronics, part number 6501KW2002A for $18. Plus tax and shipping, at my door for $29.75.
Actually the LG washer and dryer have been great, I'm just very ticked that LG has a known problem but won't do a recall to fix the part with a more reliable piece. And even more ticked that they won't ship me an in-warranty part so I can do it myself. So for now on, I will refer to the washer as a piece of crap and LG as a seller of crap. My next washer will be a Bosch.
Read thru that FixYa article and make a decision if your problem is also the Hall Sensor. If so, follow along.
This is a pretty simple fix. If you can change a sparkplug than you can easily do this one. (I compared this to a sparkplug change cause you'll get a little dirty, gotta pull some cables, and work a socket wrench).
You'll need a phillips head screw driver, 17mm and 10mm sockets or wrenches.
A quick note: Even though the pictures are somehow dated 1/7/2006, they were actually taken in December 2009. Someone reset my camera date and I didn't notice until pics were all taken.
Ok, First step, UNPLUG the washer. And carefully move the washer so that you can access the back panel. If your washer and dryer are stacked, please be careful and make sure there is nothing on top that will fall and hit you in the head. Ask someone to help you, don't blame me if you hurt your self moving the thing. Be careful!
- Remove the 4 phillips head screws on the back panel
With a 17mm socket, remove the bolt that holds on the motor rotor. Turn the bolt to the left (counter clockwise) to remove. The drum will probably turn as you're trying to get the bolt loose so with your free hand, grab the rotor around 10 o'clock and hold tight while you turn the bolt. Be patient and it'll come right out.
Next,you need to pull the motor rotor off to expose the stator. This will be a little tough because of the magnets and a tight fit. Use both hands on opposite sides and gently tug one side, then the other, then both. Try your hands at 1 o'clock and 7 o'clock. Then switch to 5 and 11. Be patient and tug gently. Watch the white center and you'll see it slowly pull away from the shaft.
- Set the rotor to the side and remove the 10mm bolts holding the stator on. I wasn't sure what to expect when I started removing it and I wanted to make sure I put it on right side up so I made pencil marks to line things back up. These really aren't needed cause it'll be obvious as to which side is up.
When you remove the 6th bolt, use your free hand to hold on to the stator cause it will fall right off. There are two connectors at the bottom, one the goes to the motor windings, the other to the hall sensor that we're replacing. If you don't hold onto the stator, you might damage the wires or connectors. Go slow on the last bolt and hang on.
Here's what those connector look like from the bottom side. I didn't have any luck trying to get them free from the bottom though. I was kinda squeezed in between the wall and washer so I didn't have much room to wiggle. I let the stator lean towards me like the picture above and then gently pulled both connectors free. Don't go Rambo on these connectors, you don't need to replace extra stuff. Breathe deep and squeeze the little tabs, they'll come free.
Almost there. That shiny looking thing on the bottom right of the stator ring is the hall sensor. It's held on with 3 clips on the back side, 1 clip on the front. Simple pry up the 1 clip and it will pop free.
The new sensor snaps back on just like you'd expect. Hook up the 3 clips first and then snap it on to the 1 clip side.
- I don't have pictures of these next steps cause it's just the opposite of the above. Just look at the pictures in the reverse order and it'll all go right back together.
- Hook up the two connectors. Make sure they click all the way back on.
- Line the stator back up with the bolt holes and screw the bolts back in with a 10mm socket. Tighten them firm but don't over do it.
- Push the rotor back onto the shaft. Because of the magnets and the shaft grooves, it will feel like it's not going. It will, line it up and apply pressure at the edges.
- Tighten the big bolt with a 17mm socket. As it tightens, the drum will start to rotate. Grab the edge with your free hand and tighten firmly.
- Put the back panel back onand tighten down the 4 phillips head screws.
- Plug the washer back in and carefully push the washer back into place.
- Test.
- Your piece of crap washer is fixed.
What do you think? Leave a comment, buy me a beer!
15 May 2009
Porsche Boxster Cabriolet
It was hard, but I relented and came home with a Boxster. It's my combo birthday present and mid-life crisis consolation prize.
As my old age time bomb has been approaching over the last year, I've been thinking about the 40th anniversary Camaro.
I had a 1969 Camaro in my Senior year of high school. During the first semester, a girl in my first period class was driving her brother's 1965 Mustang to school and somehow drove her front bumper all the way into my backseat. And then tried to hit-n-run. Since the cars had become melded into one, she didn't get very far but she sure did try.
Anyway, I've been thinking a lot about the new Camaros. But with all the trouble GM has been having, I'm just not excited about paying $10K premium to a company that's on the verge of bankrupcy. And the last few years of Chevrolets really haven't seemed like quality cars. Probably not a good choice.
So I've been cruising Craigslist and eBay looking at other sports cars that I've wanted since I was 13. High on the list was a Datsun 280Z. Man, I wanted one of those so bad back then. When I look at them now, they're kinda cheesy. Not sure what was driving my desire back then. Maybe puberty.Last week, I thought I had found the car. A Porsche Boxster Cabriolet. Price was right. Bank said yes. And boss said yes. Yes! No. The owner said it had been in an accident and the hood was replaced. That's not bad really. I mean as long as nothing was seriously crunched, for the right price, that wouldn't bother me. The owner said unless he hadn't told me, I'd never know. Said it was a perfect match/fit and there was no lingering problems. Then the night before I was to drive to Chicago to see it, it was disclosed that the frame "was bent or had been bent". What? I talked to the guy a dozen times, emailed a dozen more. And the night before I see it, it's "disclosed"? No way, wasn't going to waste any more time on that dream.
One word to sum up the car. Wow.
I love it. It is so clean. Perfect interior and exterior. Looks brand new. Nice throaty rumble, comfy leather seats, decent audio. Drives so nice.
When I told the kids that I spent their college funds and they'd have to attend community colleges now, my daughter said. "That's okay. Will you drive me to school tomorrow?"
Update: Sad Day for the Great White Boxster
02 May 2009
Greasemonkey Index of /images
After I posted the Yahoo Baseball Greasemonkey script, I remembered another script that I have that's worth sharing. Not my Yahoo Football Greasemonkey script which does the same as the baseball (shows in-game stats on tab title) but another more Have you ever been searching for an image or been Stumbling around and came across a page like the one to the left?
I see them quite often actually because I'm nosy and like to poke around on web sites. If I see a picture of interest, I wonder if the web site owner has others that aren't being displayed.
But here's the rub. We have a nice list but we have to click each one to see it.
Greasemonkey to the rescue.
I wrote a quick script that replaces the little icon to the left of each link with the link src. And since loading these images may be time consuming, you don't want to do this on every "Index of /" page that you come across. So we wrap that function up in a "Show Images" link at the top of the page when it completes loading.I've uploaded the script to userscripts.org where you can check it out. Install it and go to a page where you can see for yourself how it works.
Google around for "index of /images" and see what treasures abound.
I find lots of pages like this by "going up" a level on a URL. For example (not real, this is not a valid location) if you are looking at a photo:
http://somewhere.good/images/138028.jpg
Then see what's at:
http://somewhere.good/images
Either by editing the URL in the address bar or use the "up one level on this web site" button in Firefox. What, you don't know about that button? Right-Click an empty spot the tool bar and select "Customize...". Drag the icon that looks like the one I've circled below to your tool bar. Use it and discover lots of stuff.

What do you think? Leave a comment.
Baseball Better - Yahoo Greasemonkey Script
I love baseball. But you gotta admit that it can be boring "watching" a game on the web. If not watching it in person or on tv, it's kinda slow. I'm sorta ADD when cruising the web. I usually have 6 or more Firefox tabs open at once. I'm reading something, writing something, searching for something all at the same time. It's a wonder that I get anything done at all, but amazingly it works out.So if a good game is on at the same time that I'm on-line, I like to have a tab tuned into the Yahoo Sport MLB game. But the problem is that I have to keep clicking to that tab to see what's going on. I have Greasemonkey installed and have written a few other scripts to customize my viewing pleasure so hacking the box score page should be pretty easy.
Here's what the regular game looks like. Usually there's an advertisement over on the right side above the "series at glance" table. I guess times are tough at Yahoo and advertising is slow because no ad is being displayed on this screen shot.
Notice a few other things. The Firefox tab says "MLB - Kansas City Royals/M...". I'd like this to display something useful like the current in-progress game stats. Also see the Inning Summary table at the bottom. Below that is a Scoring Summary that can't be seen unless you scroll down.
So my typical game "watching" experience is every 5-10 minutes, click the tab, look at the score. If different than last time I looked, grab the scroll bar and go way down to see what happened. Way too much work.After some quick Greasemonkey hacking, I've come up with a better experience. As the page loads, I grab the team names, current score, inning, ball-strike count, runners on-base, and last play. Sounds like a lot but really it's not. Yahoo has everything in nice tables and getting it is like butter. Not really but I just felt like using that term. Just like buddah.
I take all those stats and format them into the tab so I can see the game info without having to click the tab. This alone has probably saved years of wear and tear on my mouse button.
I then replaced the advertisement block (yahoo isn't currently using it anyway) with the scoring summary so no painful scrolling occurs.For those that also want to enjoy baseball a little better, I've uploaded the script to Greasemonkey script haven.
For those that don't trust me and want to see what I've done, here's a view in the sausage factory. It ain't pretty but it works.
It's just basically screen scraping by searching for classes and then parsing data. Every time Yahoo makes a tweak, it breaks the script. I don't mind, it's usually minor.
Here we go.
Yahoo sets the page to a fixed width of 974 pixels. I run in 1280 mode so this wastes lots of valuable screen space and causes unsightly white gutters. This must be changed:
function changeWidth() {
var node = document.evaluate('//table[@width="974"]',
document,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null);
node.snapshotItem(0).width="100%";
}Here's a big part of the magic. Find the table that wraps the team name and score and parse it out. The team names are long and we need shorten them so they fit it the tab nicely.function getScore() {
var scoreNode = document.evaluate(
'//td[@class="yspsctnhdln"]',
document,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null);
scoreNode = (scoreNode.snapshotItem(0));
// this is ugly but I want to shorten the team so all the info displays nice on the tab
var str = scoreNode.textContent;
str = str.replace(/\n/g, "");
str = str.replace(/ /g, "");
str = str.replace(/,/g, "");
str = str.replace("Arizona", "AZ");
str = str.replace("Atlanta", "Atl");
str = str.replace("Baltimore", "Bal");
str = str.replace("Boston", "Bos");
str = str.replace("Chi Cubs", "Cub");
str = str.replace("Chi White Sox", "CWS");
str = str.replace("Cincinnati", "Cin");
str = str.replace("Cleveland", "Cle");
str = str.replace("Colorado", "Col");
str = str.replace("Detroit", "Det");
str = str.replace("Florida", "FL");
str = str.replace("Houston", "Hou");
str = str.replace("Kansas City", "KC");
str = str.replace("Minnesota", "Min");
str = str.replace("Milwaukee", "Mil");
str = str.replace("LA Angels", "LAA");
str = str.replace("LA Dodgers", "LAD");
str = str.replace("NY Mets", "Met");
str = str.replace("NY Yankees", "NYY");
str = str.replace("Oakland", "Oak");
str = str.replace("Philadelphia", "Phi");
str = str.replace("Pittsburgh", "Pit");
str = str.replace("San Diego", "SD");
str = str.replace("San Francisco", "SF");
str = str.replace("Seattle", "Sea");
str = str.replace("St. Louis", "SL");
str = str.replace("Tampa Bay", "Tam");
str = str.replace("Toronto", "Tor");
str = str.replace("Texas", "Tex");
str = str.replace("Washington", "Was");
str = str.replace(/ /g, "");
// get inning and shorten
var inning = getInning();
inning = inning.replace(/\n/g, "");
inning = inning.replace(/ /g, "");
inning = inning.replace(/Bot /g, "B");
inning = inning.replace(/Top /g, "T");
inning = inning.replace(/End /g, "E");
document.title = str + ' ' + inning + ' ' + getOut();
}In the above code, I didn't put a comment on this line but this is where the Firefox tab gets the in-game stats:document.title = str + ' ' + inning + ' ' + getOut();And more parsing. And then some really ugly if-else code. Kinda embarrassing that I did this. But I did and I'm too lazy to re-write.
function getOut() {
var balls = document.evaluate("//*[contains(.,'O:')]/b",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
var count = "";
if (balls) {
var n= balls.nextSibling;
var strikes = n.nextSibling;
n = strikes.nextSibling;
var outs= n.nextSibling;
count = balls.innerHTML + '-' + strikes.innerHTML + ' O:'+ outs.innerHTML;
}
// find how many men are on base.
// do this by looking at what image is being displayed.
// yeah, I need to clean this up but it works and I don't have time. go for it
var men = document.evaluate("//img[contains(@src,'tr_empty.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "empty";
}
else {
men = document.evaluate("//img[contains(@src,'tr_1b.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "1b";
}
else {
men = document.evaluate("//img[contains(@src,'tr_2b.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "2b";
}
else {
men = document.evaluate("//img[contains(@src,'tr_3b.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "3b";
}
else {
men = document.evaluate("//img[contains(@src,'tr_1b2b.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "1b2b";
}
else {
men = document.evaluate("//img[contains(@src,'tr_1b3b.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "1b3b";
}
else {
men = document.evaluate("//img[contains(@src,'tr_2b3b.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "2b3b";
}
else {
men = document.evaluate("//img[contains(@src,'tr_full.gif')]",
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (men) {
men = "full";
}
else {
men = "";
}
}
}
}
}
}
}
}
return count + ' ' + men;
}And that's about it. Take a look at the file at userscripts.org and give it a try. Let me know if you've improved and found some bugs.What do you think? Leave a comment.
08 April 2009
XBee Series 2 - Reading Data in API Mode
After I finally got a ZNET 2.5 Coordinator AT associated with a ZNET 2.5 ROUTER / END DEVICE by figuring out that the default JV Channel Verification parameter was key, I stumbled again.I can send character data from end device to coordinator and see it come out of the UART.
But when I have an end device with the ADC enabled (ATD1=2) and the IO Sampling Rate (ATIR=4E20) set to 20 seconds, I see the coordinator's red LED flicker as data is being received. But nothing appears to come out of the coordinator's UART.
Back to drawing board with Mr Google. I searched websites, blogs, forums. Some are claiming it works great, others are having issues. I'm on the issue side.
Then came across this in the XBee ZNET 2.5 Product Manual, section 4.5.3. Periodic IO Sampling :
Periodic sampling allows an XBee / XBee-PRO module to take an IO sample and transmit it to a remote device at a periodic rate. The periodic sample rate is set by the IR command. If IR is set to 0, periodic sampling is disabled. For all other values of IR, data will be sampled after IR milliseconds have elapsed and transmitted to a remote device. The DH and DL commands determine the destination address of the IO samples. DH and DL can be set to 0 to transmit to the coordinator, or to the 64-bit address of the remote device (SH and SL). Only devices running API firmware can send IO data samples out their Uart. Devices running AT firmware will discard received IO data samples.
I swear that when I searched around, I found people claiming to receive IO data in AT mode. I surely can't so maybe the manual is on to something. I'll try API mode. Bet it's a boatload of fun.TIP: When writing API firmware to a device that currently has AT firmware on it (or visa-versa), after the write, X-CTU complains that it failed to enter command mode. This is because the "Enable API" setting on the PC Settings / Host Setup tabs need to be toggled.
After putting ZNET 2.5 COORDINATOR API on, I did start to seem to receive data. But not what I expected. With AT Transparent Mode, I could just read a string straight from the UART and parse away. Now in API Mode I'm getting some weird gook that sure doesn't print very nice. Probably that API Frame thing that I skimmed past in the manual. Darnit, I gotta just sit down and read that thing.
Section 6 API Operations goes into detail about how life has now changed and the free ride is over. It says "API operation requires that communication with the module be done through a structured interface (data is communicated in frames in a defined order)". Oh Joy.
I started hacking my Python app to see what kinda data I was getting myself into. The frame starts with a start byte of 0x7E and then followed by a two byte length. The IO data that I'm trying to get to is locked away in the Frame Data block that doesn't seem too bad.Luckily before I started to make a career out of writing a API Frame parsing mess, I went back to Google to see what the trail blazers have done for me. I found the xbee.py file that ladyada used for her tweet-a-watt. Too bad it's for Series 1 and not a lot of help. But the header notes the author as Amit Snyderman. Wonder if he has a Series 2 version. Woo Hoo, he's got some google code at http://code.google.com/p/python-xbee But wait. The page says: The XBee API code is incomplete, missing support for valid checksums and an implementation for working with the Series 2 API. Darn it. Another bad lead.
Well, I'm on the Python Xbee page, I might as well be nosey and poke around. Maybe I can use the Series 1 code as a starting point and hack it up enough to get my single channel ADC data. Let's look it the Subversion source. What's that under the trunk? An XBee 2.5 folder. Woo Hoo!
Grab the xbee_api.py file, save it to your project folder and then for a quick test, write a second file like this:
#!/usr/bin/env python
from xbee_api import *
# replace first param with your serial port
a=XbeeApi("/dev/tts/0",9600)
Save this in a file called coord.py, make it executable (chmod +x coord.py), and run it (./coord.py). Now when sampled IO data is received, this is printed. Do I hear a Woo Hoo?
onData() ->{'code': 146, 'data': {'asamples': [3, 255], 'dsamples': [[0, 0, 0, 0, 0, 0, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]], 'dmask': [[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]], 'mac': [0, 19, 162, 0, 64, 62, 33, 116], 'samples': [1], 'address': [60, 237], 'amask': [[0, 0, 0, 0, 0, 0, 1, 1]], 'options': [1]}}Now I need to figure out to interpret the data 'asamples'. But this is looking very promising. FYI, I'm going down this path to hook a thermistor to an XBee for my pool thermometer. More details to follow as I make more progress.
data {'asamples': [3, 255], 'dsamples': [[0, 0, 0, 0, 0, 0, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1]], 'dmask': [[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]], 'mac': [0, 19, 162, 0, 64, 62, 33, 116], 'samples': [1], 'address': [60, 237], 'amask': [[0, 0, 0, 0, 0, 0, 1, 1]], 'options': [1]}
More FYI. I'm running this with OpenWRT on a wl-520gu hacked for my tweet-a-w/e. The receiving XBee is named BLUE. The second XBee is name WHITE and is connected to my laptop with an adafruit XBee Adapter that has ADC pin 2 setup for 20 second periodic IO sampling.
I've saved the today's version of my X-CTU config files here:
BLUE with ZNET 2.5 COORDINATOR API
WHITE with ZNET 2.5 ROUTER / END DEVICE AT with ADC pin 1 enabled and 20 second IO sampling.What do you think? Leave a comment.
XBee Series 2 - JV Channel Verification
Damn it. Why do the simplest things always take hours to complete? I'm using XBee Series 2 cause I really didn't know what I was buying. Series 1 or Series 2? To a newb, sounds like 2 is the shiny. Why buy an out-dated series 1? Nobody wants last year's model.If I would've done my homework, the series 1 (also called 802.15.4) are the most reliable, easiest to use. So of course, I'm using Series 2.
I first attempted to use them as described in the ZNet 2.5 Modules Product Manual, one as a coordinator, one as an end device. No luck. I followed every instruction I could find on the web. Nada.
Just by dumb luck, I found that if I flashed two radios as ZNET 2.5 ROUTER / END DEVICE AT and then set the Destination Address of each to point to the other, it appeared to work. I could send data to and from the serial ports. I used them in this way for the tweet-a-w/e foundation and had good success.
For an end device called WHITE that will talk to another end device named PINK, use X-CTU and load the ZNET 2.5 Router / End Device AT firmware. Go to the X-CTU Terminal tab and type:+++Here's the X-CTU file for WHITE.
ATRE
ATNIWHITE
ATDNPINK
ATWR
But now I'm trying to send analog data from one to the other and I'm back to nada. The data receive light blinks and it appears to read data, but nada bit comes out of the UART.
I decided to go back to square one and reconfigure as coordinator and end device. Sounds easy? Right. Took me two nights to get the devices associated. What's associated? From page 14 of the 802.15.4 manual (and not in the series 2 manual):
Association is the establishment of membership between End Devices and a Coordinator. The establishment of membership is useful in scenarios that require a central unit (Coordinator) to relay messages to or gather data from several remote units (End Devices), assign channels or assign PAN ID.The series 2 manual seems pretty decent. I've read many sections and need to sit down and attempt to read more. Too bad though that it doesn't mention parameter JV Channel Verification. Which is the parameter that finally made a difference.
[update] maybe I was looking at the wrong manual. The one I ref'd above is the Series 2 Manual. The JV parameter is mentioned in the ZNET 2.5 manual.
When setting up a coordinator and associated end devices, there's a few things that you need to do:
- After writing the firmware, go to the terminal and do a ATRE to reset to factory values. I would've saved lots of time if I realized that previous values were not being overwritten between firmware loads.
- Make sure that the PAN ID is set the same on both devices. I suggest that while debugging, you have both devices connected to your computer via an adafruit XBee Adapter or SparkFun XBee Explorer and use X-CTU to monitor. You need to verify that the Operating PAN IDs are the same when they're trying to associate.
- Set each device to a unique Node ID
- The coordinator destination address should be set to DH=0, DL=FFFF
- The end device destination address should be set to DH=0, DL=0
And for basic communications, that should be it. No need to set destination address of the end device explicitly to the coordinator. The 0's do that for you.My problem though was my coordinator was on channel F and my end device was channel D. I could see this while watching them start up, but I could not figure out WTF.
Finally by going thru every parameter on both devices using X-CTU, I realized that JV Channel Verification was the ticket. This is described in the X-CTU tool as:
Set/read the channel verification setting. If enabled, a router will verify a coordinator exists on the same channel after joining or power cycling to ensure it is operating on a valid channel, and will leave if a coordinator cannot be found (if NJ=0xFF). If disabled, the router will remain on the same channel through power cycles.In English, this means that if your devices are on different channels and JV is disabled, you're fricked cause the router won't go to another channel to associate.
Change JV to enabled and reboot the device:
+++
ATJV1
ATWR
ATFR
I've uploaded the configuration to my coordinator named BLUE that has ZNET 2.5 COORDINATOR API firmware. And an end device named PINK that has ZNET 2.5 ROUTER / END DEVICE AT firmware.
What do you think? Leave a comment.
28 March 2009
XBee Adapter Kit PDQ
I'm a soldering novice. I've been burning my finger tips for some years now but in limited batches so I'm in no way claiming any skill. (Actually, I'm claiming a lack of skill) And I wasn't speeding, I was in no rush to build this thing.
I opened the mail and snapped that there picture over there. Plugged in my soldering iron and started to look through the adapter pieces as it warmed up.
I built one of these last year so I knew the routine. They're so dirt simple, I didn't even have to look over adafruit's instructions this time. I just glanced at my other adapter to see which resistor was which. Everything else is a no-brainer to fit onto the board.
So if I already have one of these (and a XBee Shield and a XBee Explorer), what the heck am I doing building another?
Now that I have a workable tweet-a-w/e, I need more XBees "whatevers".
I'm planning to have temperature sensor to tweet swimming pool data. So I need another XBee and an XBee Adapter.
I'm planning to use Sparkfun's Nike+ receiver in a Serial Adapter connected to an Arduino and start tweeting stalker data. So I need another XBee and an XBee Adapter.
I'm planning to hook up various ADC things to an Xbee and start tweeting real data. So I need another XBee and an XBee Adapter.
Get the point? I need more XBees and XBee adapter kits. Unfortunately the boss doesn't understand, so I will need to get these one or two at a time.
22 March 2009
tweet-a-whatever (tweet-a-w/e) foundation
My explanation of the tweet-a-w/e ran pretty long in my last post. I took an Asus wl-520gu wireless router, installed OpenWrt, Python, and an Xbee to build the foundation of a tweet-a-whatever (tweet-a-w/e). My 13 year-old texting obsessed daughter choose that name BTW. The last post ran so long that I cut it off after I talked about how to read the serial port with pySerial.This time, I'll explain a simple Python app that receives a string from a Xbee, decodes its header and then tweets the payload to a twitter account. I'm a complete Python newb so if you have suggestions on a better implementation, I'm all ears.
Here's basically what I've done. Heavily borrowed from mightyOhm and ladyada, this project receives data from Xbees in "the field". Using a unique header, the client app determines the payload destination which can be a tweet or a web service.Mr mightyOhm has written a great series on hacking the Asus wl-520gu wireless router to build an open source wireless streaming internet radio receiver. If you haven't read thru Jeff's work, stop right now and read it. Now.
Ladyada's award winning tweet-a-watt takes data from a kill-a-watt, sends it to Xbee embedded in a hacked wl-520gu and then tweets it for the world to see how green you are. I've copied the Xbee connection from her and the idea of using Python. She didn't post her Python source, so I've had to stumble thru this. I just read tonite, that the tweet-a-watt project will be a project in Make Magazine, volume 18. [update] ladyada did post her source, I just missed it. Check out her good stuff here.
My tweet-a-w/e's spin is that any data generating thing (a "whatever") can be hooked to an Xbee in the field. Either directly to the Xbee or via an Arduino. The Xbee transmits to a receiving Xbee that has been wired into the serial port of a hacked Asus wl-520gu. The Python app running on the router reads the data and based on a unique header code, the payload is either tweeted or sent to a web service.
So I ended last time by showing a small snippet of Python that read the incoming data and printed it. Now let's modify that snip so it reads the first few characters and makes a decision of what to do. This first revision is pretty hackish and we'll improve on it as "whatevers" are added in the field. My opinion is get it working, then optimize.
Last time we installed Python but I didn't tell about the python-twitter wrapper from DeWitt Clinton. Here's what I did:
- Install simple JSON dependency
- wget http://pypi.python.org/packages/source/s/simplejson/simplejson-2.0.9.tar.gz
- gunzip simplejson-2.0.9.tar.gz
- tar xvf simplejson-2.0.9.tar
- python setup.py install
Mr Google has no clue about this error. Plenty of problems, but I couldn't find anything. I mucked with my LD_LIBRARY_PATH and considered rebuilding Python. Finally, I actually started looking at the source referenced in the trace. Here's what I found. Install OpenSSL and problems are solved. I wrote about my fun here.
# opkg updateAnd finally install python-twitter:
# opkg install openssl-util
- wget http://python-twitter.googlecode.com/files/python-twitter-0.5.tar.gz
- gunzip python-twitter-0.5.tar.gz
- tar xvf python-twitter-0.5.tar
- python setup.py install
I'm currently planning 4 whatevers that will be talking to the router:
- Xbee connected to my laptop via a SparkFun Xbee Explorer USB
- Maxim DS18B20 1-wire temperature sensor connected to an Arduino and an Xbee
- Nike+ receiver in a Serial Adapter connected to an Arduino and an Xbee
- Xbee in ADC (Analog-to-digital conversion) and digital I/O line passing.
I created an array to hold the whatever name, the unique header, the action to perform, and username/password:
# tweet-a-w/e stuff array # "whatever", header string, action, user, password # WE_ARRAY = [ ['WE_TEST', '[0]', _tweet_it, 'username', 'password'], ['WE_TEMPERATURE', '[1]', _web_it, 'username2', 'password'], ['WE_NIKEPLUS', '[2]', _stalk_it, 'username3', 'password'], ['WE_XBEE', '0x7e', _tweet_it, 'username4', 'password'] ]The action array elements are functions to perform the tweet or web action. Here's what I defined:
# # define functions to do something with received data # # tweet data # def _tweet_it(data, twuser, twpass): # login to twitter print 'tweet w/' + twuser api = twitter.Api(username=twuser, password=twpass) api.PostUpdate(data) # web service data # def _web_it(data, twuser, twpass): # tbd print 'wrote to web service w/' + twuser # stalk the data # def _stalk_it(data, twuser, twpass): # tbd print 'watch it w/' + twuserOk, now let's read the data and determine what we got:
# open up the serial port on router # print 'opening serial port ' + SERIALPORT ser = serial.Serial(SERIALPORT, BAUDRATE, timeout=TIMEOUT) ser.open() # read data # try: print 'entering read loop' # loop forever while 1: # read it from serial port data = ser.read(NUMCHARS) if len(data) > 0: print 'Read: ' + data # loop thru our whatever array and see if we recognize the header for i in range(0, len(WE_ARRAY)-1): if data.startswith(WE_ARRAY[i][1]): print WE_ARRAY[i][0] + " action " + WE_ARRAY[i][2].__name__ WE_ARRAY[i][2](data, WE_ARRAY[i][3], WE_ARRAY[i][4]) break finally: print 'closing serial port' ser.closeThe only tricky thing in that code is the action call. Once we have a header match, the 2nd array element is one of the action functions that we defined. Simply call it and pass the data, username/password as arguments.
My Python client file is here.
Get your file on the router and start it:
root@OpenWrt:/opt/project# python XbeeReader.pyAnd send it something. For me, a quick test is to use another Xbee in the SparkFun Xbee Explorer. When I plug this in to my laptop, it shows up as /dev/ttyUSB0 so to write a quick string is as simple as:
d@hopper:~/projects/wl-520gu$ echo "[0] Testing " + `date` > /dev/ttyUSB0And on the router telnet window, I see:
opening serial port /dev/tts/0I'm using a test twitter account and viola, the string "[0] Testing" shows up like magic.
entering read loop
Read: [0] Testing + Thu Mar 26 23:30:47 EDT 2009
WE_TEST action _tweet_it
tweet w/skibicki
How are the Xbees configured? Real easy. I put ZNET 2.5 Router / End Device AT firmware version 1244 on both. I use Linux so using X-CTU was a little tricky until I figured out how to use it with Wine. I wrote about it here.
The Xbee in the router is named PINK. Last year, I built the NKC Xbee Shield Kit and goofed something up. When I installed the Xbee, it got really hot and the white Xbee label turned pink. It still works but is discolored. Here's the X-CTU file for PINK.
The Xbee connected to my laptop via the Xbee Explorer is named WHITE. Because it's not discolored. The config is EXACTLY same as PINK except for the name and destination. After loading the ZNET 2.5 Router / End Device AT firmware, I went to the X-CTU Terminal tab and typed:
+++Here's the X-CTU file for WHITE.
ATNI WHITE
ATDN PINK
ATWR
Plans for next time. Clean up the client so only the data is written to twitter and not the unique header. Then hook up the DS18B20 temperature sensor and start tweeting real data.
What do you think? Leave a comment.
21 March 2009
tweet-a-w/e using Asus wl-520gu and Xbee
---------------------------------------------------------------------------------------------
A few of the geeks that I
Mr mightyOhm is also the admin of the Asus Wireless Router Hacks Flickr Pool. Check out a few of the cool things he and others have done with the wl-520gu.
I've been thinking about a tweet-a-temperature project that would monitor my pool temperature and tweet it every so often during the summer months. While I'm toiling away in the office, I could get SMS spam telling how great life is outside work.
Let's lay down the foundation for a tweet-a-whatever (tweet-a-w/e) project by hooking an Xbee to the router and installing a Python client that tweets whatever is received.
Yes, this seems to be very similar to ladyada's tweet-a-watt port. I'm shamelessly copying the hard work of mightyOhm and adafruit to set this up. What's my value-add? I'll ramble a lot and tell you about all my dead-ends.
So I ordered a wl-520gu from newegg and eventually pretty much followed mightyOhm's instruction for installing header pins on the serial port and installing OpenWrt.
If you've read any of my other ramblings on this blog, you know already that I'm not very original and sometimes not very smart. But I'm decent at
Let's first talk about the stupid things I did so you can avoid the mistakes in life that I have made.
- Both mightyOhm and ladyada used OpenWrt by first flashing dd-wrt and then OpenWrt. Me? I choose to use tomato firmware instead because I wanted built-in USB support and the description of its feature sounded great. And because I wanted to waste 3 nights trying to configure it in wireless client mode. I'm not saying tomato is bad, I'm just saying that I struggled big time and I couldn't find many online tips. I finally said "uncle" and followed the mightyOhm's way and installed openWrt. And had it working in under a half-hour.
- Installing a four-pin header isn't a hard thing. All I had to do was remove 4 blobs of solder and then solder in a header. So ... Why did I somehow brick my router? I was super duper careful removing the blobs (without a de-solder-er iron or a bulb) and then was careful soldering in the pins. I only applied heat for a max of 5 seconds and let it cool for about 5-10 seconds before re-attempting. Yet I did it. After I finished the header, the darn thing wouldn't boot. Nothing, dead to the world. No reset, no LED action, nada. I cussed for a day or two and then ordered a new one from newegg. Before I de-blobbed the new one, I ran down to Rat Shack and bought a desoldering bulb. 20 minutes later, I had a working router - with header pins. Lesson? If at first you don't succeed, spend more money.
- With the default Asus firmware still installed, I found that logging in via telnet, the user/password was root/admin. Via the browser at 192.168.1.1:80, the user/password was admin/admin. Kinda odd, but maybe this tip will save you some hair.
On the 1st router that I bricked, I installed new firmware first, then tried to install the headers. On my working router, I did headers first, then firmware. I don't think it really matters what order you do this. But I ruined a $59 router, so you trusting me?
So do your own thing and follow mightyOhm's excellent instructions. Get headers on the serial port, install openWrt, and meet me back here in a few.
Yeah, I know the picture over there is kinda blurry but it's the best camera I have (donations accepted). If the picture was clear, you would see that I'm using a USB TTL-232 cable to talk to the router from a USB port to the router's shiny new headers. mightyOhm's picture on this page was very helpful for the pin-outs.
As is, the OpenWrt's filesystem is pretty cramped. There's not much space available to install extras such as Python. I had an extra Sandisk Cruzer laying around so I setup the router to automount the USB stick on /opt.
From either the serial line or a wireless telnet (my preference),
- Edit opkg config file to use kamikazi 8.09 packages.
- # vi /etc/opkg.conf
- Set the first line to this:
- src/gz snapshots http://downloads.openwrt.org/kamikaze/8.09/brcm-2.4/packages
- # opkg update
- # opkg install kmod-usb-core
- # opkg install kmod-usb-ohci
- # opkg install kmod-usb-storage
- # opkg install kmod-fs-vfat
- # opkg install kmod-fs-ext3
I want to install Python libraries and other extras on the USB drive so we'll need this auto-mounted at boot time. I couldn't locate clear instructions on this but here's what worked for me. Using tips from this place, I did:
- Create a mount point
- # mkdir /opt
- Create an /etc/rc.d/S11mount file with macsat.com contents from this page.
- NOTE: macsat's page references this as /etc/init.d/S11mount. For my version to work, I did not put it in init.d but instead put it in rc.d
- # vi /etc/rc.d/S11mount
- Paste in macsat's example S11mount content. My file version can be found here.
- change the MOUNT_DEVICE0 statement to match your device. My USB stick was exactly the same as his example.
- Edit opkg config file to create an alternative destination for packages
- # vi /etc/opkg.conf
- Add this line:
- dest opt /opt
- My copy of the opkg.conf file is here.
- export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/opt/bin:/opt/sbin:/opt/usr/bin:/opt/usr/sbin
- export LD_LIBRARY_PATH=/lib:/usr/lib:/opt/usr/lib:/opt/lib
At this point, we have a flashed wl-520gu router with OpenWrt, headers soldered to serial port, and configured to mount a USB stick to opt at bootup. Let's keep mushing on.
The line that we added to the top of our opkg.conf file
- src/gz snapshots http://downloads.openwrt.org/kamikaze/8.09/brcm-2.4/packages
- # opkg update
- # opkg -d opt install python
- # python -V
Python 2.5.4
Since OpenWrt uses the serial port /dev/tts for console login, we need to modify the /etc/inittab file. All this takes is to comment out the tts line:
- wl-520gu GND -> Xbee GND
- wl-520gu 3V -> Xbee 3V
- wl-520gu TX -> Xbee RX
- wl-520gu RX -> Xbee TX
#tts/0::askfirst:/bin/ash --login
I'm using Python for the client app, so we need to install the pySerial module from SourceForge. Create a temp folder on /opt, CD to it, download pySerial, unzip, untar, and install
- # mkdir /opt/temp
- # cd /opt/temp
- # wget http://downloads.sourceforge.net/pyserial/pyserial-2.4.tar.gz
- # gunzip pyserial-2.4.tar.gz
- # tar xvf pyserial-2.4.tar
- # python setup.py install
reader.py
I've modified the reader.py quite a bit so that it tweets the received data, but the version above simply echoes the data to the terminal.
#!/usr/bin/env python import serial, time SERIALPORT = "/dev/tts/0" # the com/serial port the XBee is connected to BAUDRATE = 9600 # the baud rate we talk to the xbee TIMEOUT = 0.5 # the timeout to wait for buffer fill NUMCHARS = 140 # the number of characters to attempt to read at once # open up the FTDI serial port to get data transmitted to xbee print 'opening serial port ' + SERIALPORT ser = serial.Serial(SERIALPORT, BAUDRATE, timeout=TIMEOUT) ser.open() try: print 'entering read loop' while 1 > 0: data = ser.read(NUMCHARS) if len(data) > 0: print "Read " + data finally: print 'closing serial port' ser.close
Run it like this:
# python reader.pySend the Xbee data from another Xbee and watch it print.
Alright, I'm stopping and will pick up the story in my next entry. Look at this picture to see where we're going.

- Update: I've wrapped up this story in tweet-a-w/e foundation
What do you think? Leave a comment.
Format USB Flash Drive with ext3
Using Ubuntu 8.04 Hardy Heron, I figured it would be easy to format a thumb drive to ext3. Seems for me that nutin is easy. My plans for the USB stick is to use it with an embedded Linux box that could expectantly shutdown.Wikipedia says this about ext3:
The ext3 or third extended filesystem is a journaled file system that is commonly used by the Linux kernel. It is the default file system for many popular Linux distributions.After a few struggles with attempting to use the Partition Editior, I ended up reformatting the stick by following these instructions:
...
Its main advantage over ext2 is journaling which improves reliability and eliminates the need to check the file system after an unclean shutdown.
- mount your USB stick. With Ubuntu, most automount so this is as simple as sticking it in
- do a "$ df" and determine your drive's partition name. Mine is /dev/sdb1
- unmount the drive
- Be very careful and double-dog sure that you have the right partition name.
- Use your USB's partition name in-place of my example/dev/sdb1
- Don't ruin your hard drive by using the wrong partition. Be careful !
- $ sudo mkfs.ext3 /dev/sdb1
- Give your drive a name
- $ sudo e2label /dev/sdb1 usb-mydrive
What do you think? Leave a comment.
Subscribe to:
Posts (Atom)



