Shell Script To Control Belkin WeMo’s

It’s no surprise I’m a huge fan of home automation and tech toys, and I recently picked up a pair of Belkin WeMo’s.

You **have** to set them up with the app they supply for smartphones, but after that I hoped I could find a way to control them directly. Belkin has collected quite a few negative reviews for these devices, and it’s a shame, because the hardware seems real solid.  It’s their current apps that leave a LOT to be desired.  Clearly the issues they’re having getting the app side right are driving down the reviews.  Fortunately, I could care less how the app experience is, since I only needed it to initially deploy the devices, and planned from the get-go to write my own code to control them.

Numerous folks have written tools to control some of the functions of these, but everything I came across was dependent on other libraries, was incomplete, or didn’t work when I tested it.  I like plain-old vanilla shell scripts that I can just run from any local machine, and I’ve hacked up various XML snippets I’ve found and just rely on curl for the following script that I put together:

#!/bin/sh
#
# WeMo Control Script
#
# Usage: ./wemo_control IP_ADDRESS ON/OFF/GETSTATE/GETSIGNALSTRENGTH/GETFRIENDLYNAME
#
#

IP=$1
COMMAND=$2

PORTTEST=$(curl -s $IP:49152 | grep “404″)

if [ "$PORTTEST" = "" ]
then
PORT=49153
else
PORT=49152
fi

if [ "$1" = "" ]
then
echo “Usage: ./wemo_control IP_ADDRESS ON/OFF/GETSTATE/GETSIGNALSTRENGTH/GETFRIENDLYNAME”
else

if [ "$2" = "GETSTATE" ]

then

curl -0 -A ” -X POST -H ‘Accept: ‘ -H ‘Content-type: text/xml; charset=”utf-8″‘ -H “SOAPACTION: \”urn:Belkin:service:basicevent:1#GetBinaryState\”" –data ‘<?xml version=”1.0″ encoding=”utf-8″?><s:Envelope xmlns:s=”http://schemas.xmlsoap.org/soap/envelope/” s:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”><s:Body><u:GetBinaryState xmlns:u=”urn:Belkin:service:basicevent:1″><BinaryState>1</BinaryState></u:GetBinaryState></s:Body></s:Envelope>’ -s http://$IP:$PORT/upnp/control/basicevent1 |
grep “<BinaryState”  | cut -d”>” -f2 | cut -d “<” -f1 | sed ’s/0/OFF/g’ | sed ’s/1/ON/g’

elif [ "$2" = "ON" ]

then

curl -0 -A ” -X POST -H ‘Accept: ‘ -H ‘Content-type: text/xml; charset=”utf-8″‘ -H “SOAPACTION: \”urn:Belkin:service:basicevent:1#SetBinaryState\”" –data ‘<?xml version=”1.0″ encoding=”utf-8″?><s:Envelope xmlns:s=”http://schemas.xmlsoap.org/soap/envelope/” s:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”><s:Body><u:SetBinaryState xmlns:u=”urn:Belkin:service:basicevent:1″><BinaryState>1</BinaryState></u:SetBinaryState></s:Body></s:Envelope>’ -s http://$IP:$PORT/upnp/control/basicevent1 |
grep “<BinaryState”  | cut -d”>” -f2 | cut -d “<” -f1

elif [ "$2" = "OFF" ]

then

curl -0 -A ” -X POST -H ‘Accept: ‘ -H ‘Content-type: text/xml; charset=”utf-8″‘ -H “SOAPACTION: \”urn:Belkin:service:basicevent:1#SetBinaryState\”" –data ‘<?xml version=”1.0″ encoding=”utf-8″?><s:Envelope xmlns:s=”http://schemas.xmlsoap.org/soap/envelope/” s:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”><s:Body><u:SetBinaryState xmlns:u=”urn:Belkin:service:basicevent:1″><BinaryState>0</BinaryState></u:SetBinaryState></s:Body></s:Envelope>’ -s http://$IP:$PORT/upnp/control/basicevent1 |
grep “<BinaryState”  | cut -d”>” -f2 | cut -d “<” -f1

elif [ "$2" = "GETSIGNALSTRENGTH" ]

then

curl -0 -A ” -X POST -H ‘Accept: ‘ -H ‘Content-type: text/xml; charset=”utf-8″‘ -H “SOAPACTION: \”urn:Belkin:service:basicevent:1#GetSignalStrength\”" –data ‘<?xml version=”1.0″ encoding=”utf-8″?><s:Envelope xmlns:s=”http://schemas.xmlsoap.org/soap/envelope/” s:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”><s:Body><u:GetSignalStrength xmlns:u=”urn:Belkin:service:basicevent:1″><GetSignalStrength>0</GetSignalStrength></u:GetSignalStrength></s:Body></s:Envelope>’ -s http://$IP:$PORT/upnp/control/basicevent1 |
grep “<SignalStrength”  | cut -d”>” -f2 | cut -d “<” -f1

elif [ "$2" = "GETFRIENDLYNAME" ]

then

curl -0 -A ” -X POST -H ‘Accept: ‘ -H ‘Content-type: text/xml; charset=”utf-8″‘ -H “SOAPACTION: \”urn:Belkin:service:basicevent:1#ChangeFriendlyName\”" –data ‘<?xml version=”1.0″ encoding=”utf-8″?><s:Envelope xmlns:s=”http://schemas.xmlsoap.org/soap/envelope/” s:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”><s:Body><u:ChangeFriendlyName xmlns:u=”urn:Belkin:service:basicevent:1″><FriendlyName>Pool Filter</FriendlyName></u:ChangeFriendlyName></s:Body></s:Envelope>’ -s http://$IP:$PORT/upnp/control/basicevent1 |
grep “<FriendlyName”  | cut -d”>” -f2 | cut -d “<” -f1

else

echo “COMMAND NOT RECOGNIZED”
echo “”
echo “Usage: ./wemo_control IP_ADDRESS ON/OFF/GETSTATE/GETSIGNALSTRENGTH/GETFRIENDLYNAME”
echo “”

fi

fi

Copy/Paste or download here: wemo_control.sh

Usage is:   ./wemo_control IP_ADDRESS ON/OFF/GETSTATE/GETSIGNALSTRENGTH/GETFRIENDLYNAME and the functions are pretty self-explanatory.

The usual disclaimer applies.  I don’t write code for a living and there’s probably gross inefficiencies and poor syntax, but it WORKS.

Enjoy :P

AcuRite Acu-Link Internet Bridge (09150TRX): Accessing Local Data

AcuRite has been threatening the release of this product for well over a year, and it’s finally out.  Being a bit obsessive about data in and around my home, (check-out my IP Thermostat install and custom interface) I *HAD* to have one of these.

The “idea” is that you buy the Internet Bridge from AcuRite, and either with your existing sensors from their other products (many are compatible), or with the purchase of additional sensors, live data is transmitted to their “MyBackyardWeather” web site and you can view the data while you’re away and track trends etc.  They even offer a “forecasting” widget.

To get started, I ordered the internet bridge, a tower sensor, and a floating pool sensor.   The bridge is 80 bucks, and the sensors are very reasonably priced at ~ $8 for the tower sensor and $20 for the floating sensor.  They’re shipping is a bit slow, but everything arrived well packed and the build quality of all the devices is quite good.  The tower sensor supplies both temperature and humidity data, and honestly 8 bucks for one of these is a great price.   You’d be hard-pressed to buy just the sensors for an arduino or pi build for that money.

The bridge has a flip-up antenna and two connections, one RJ-45 for a network cable, and one jack for the power plug.  Since the protocol and any real info about how the bridge “talks” to their web site is unpublished and unknown, I figured I’d give it the full packet capture and analysis treatment.   To do this, I added a static DHCP IP mapping for the MAC address of the Internet Bridge to my router/firewall so as soon as it came online, I’d know the IP address.  The MAC address of the Internet Bridge can be found right on the bottom of the unit.  This MAC address is also the “ID” that AcuRite uses to associate your data sources with your account on MyBackyardWeather, but I’ll get to that later.  After setting up the static IP mapping, I enabled packet capture for any TCP/UDP connections from that IP out to the net.  Time to plug it in!

Once connected, the Internet Bridge did two things:

1) started sending sensor data to the Acu-Link web app

2) started downloading new firmware line-by-line with a POST for each new line as one completed

I pulled the connection before the firmware update could complete (just in case), and started to take a closer look at the data sent to the Acu-Link web app via the packet capture.  To my surprise, it looked like the sensor data was being sent  cleartext in a simple HTTP POST, one POST for each sensor in range of your Internet Bridge.  Next, I tried reconnecting the bridge, but this time with WAN access blocked, and ran a full port scan.  Only port 80 was open, and a visit to the Bridge’s local IP in a browser yielded a simple status page informing me that a firmware update was in process.   In the hope that more useful data would be presented when not in the “firmware-update” state, I permitted WAN access and let the firmware update complete.

Once the firmware update completed, the simple status page showed the sensors in range, their signal, and the option to send a POST to the bridge to toggle the LED’s on and off, but no actual sensor data was shown, and there’s nothing to click on, save for the LED toggle.  I tried forcing an error that might yield useful information with various POST’s and GET’s to the simple web interface on the Internet Bridge, but never got more than a 404 or the same status page.

Since querying the data directly from the Internet Bridge seemed unlikely without new information, I returned to looking at the data the Internet Bridge POST’s to Acu-Link, which was a little different now after the update.  The actual variables had additional digits and letters, but the values were still cleartext within this group of digits.  Here’s what the HTTP POST looks like when my Internet Bridge sends data for my tower sensor:

id=############&sensor=11423&mt=tower&humidity=A0590&temperature=A018000000&battery=normal&rssi=4

. . . . . let’s break it down and look at each piece:

id=############

I obfuscated the actual value here, but this is the MAC address of your Internet Bridge

sensor=11423

This is the sensor identifier, and appears to be unique for each sensor, though I only have one tower sensor, so I can’t be sure

mt=tower

This is the type of sensor, probably stands for “model type” if I had to guess

humidity=A0590

The 3rd-5th digits are the relevant ones here, with a decimal point required between the 4th and 5th digits, yielding a value of 59.0 for humidity

temperature=A018000000

Again, the 3rd-5th digits are the important ones here, but the 2nd digit serves the role of  denoting a positive or negative reading as well.  If the reading is positive, it’s a “0″, if it’s negative, it’s a “-”.  This value is also in Celsius, so if you want Fahrenheit, you’ll need to convert it.

battery=normal

This one seems fairly obvious, but I didn’t try inserting an older set of batteries to see what it reports when not “normal”

rssi=4

This denotes the received signal level for the specific sensor, and varies from 0-4

All of this data is super-easy to parse in just about any language.  I’m no programmer, but I’m “dangerous” with BASH scripting, so I figured I could probably whip something up, but how do we get the data if you can’t request it?  TCP dumps are nice for post-analysis. but a pain to do anything with real-time.  An HTTP proxy server with some customization would be an option to intercept the data, as well as IDS with some custom rules that took actions like parsing the data and writing out values that could be sucked up from something else, but I had something even “dirtier” in mind.

Let’s dig into what happens for data to get from the Internet Bridge to Acu-Link’s site from power-on to data.

1) The Internet Bridge powers up and gets an IP, gateway and DNS servers via DHCP (your router typically hands out this info)

2) The Internet Bridge resolves “http://www.acu-link.com” using DNS

3) The Internet Bridge starts making regular HTTP POST’s to the Acu-Link web service at: “http://www.acu-link.com/messages”

4) The Acu-Link web service responds back to each POST from the Internet Bridge with a SUCCESS, and the current firmware version.  (presumably if the FW version is higher than installed on the Internet Bridge, this is what initiates the downloading and install of new firmware).

Knowing the above, I figured the easiest way to get sensor data locally would be to “trick” the Internet Bridge into sending it to me instead of Acu-Link.  To do this, I configured my router/firewall (I use pfSense) to “override” www.acu-link.com by having the local DNS service resolve the hostname to a local IP on my network instead of the “real” IP on Acu-Link’s network.   If you can’t override hostnames or zones on your router/firewall with the local DNS service, or your router/firewall doesn’t offer a local DNS services, there’s several freeware DHCP/DNS software pkgs that you could run on a PC on your network to accomplish that same thing.

Now that I have my Internet Bridge sending it’s data to an IP on my network, I needed something to receive it.  I wrote a simple BASH script to replace the functionality of the “messages” web service at Acu-Link:

#!/bin/sh
echo “Content-type: text/html”
echo

echo “SUCCESS”

POSTDATA=$(cat | tr -d ‘ ‘)

FIELD=1
while [ $FIELD -le 15 ]
do

DATA=$(echo $POSTDATA | cut -d”&” -f$FIELD)
VARIABLE=$(echo $DATA | cut -d”=” -f1)
VALUE=$(echo $DATA | cut -d”=” -f2)

if [ $VARIABLE = id ]
then
ID=$VALUE

elif [ $VARIABLE = sensor ]
then
SENSOR=$VALUE
echo “$VARIABLE=$VALUE” > ../weather_data/”$ID”_$SENSOR.txt

elif [ $VARIABLE = temperature ]
then
WHOLE=$(echo $VALUE | cut -c 2-4)
DECIMAL=$(echo $VALUE | cut -c 5)
CELSIUS=$(echo $WHOLE.$DECIMAL)
VALUE=$(echo “$CELSIUS * 1.8 + 32″ | bc -l)
echo “$VARIABLE=$VALUE” >> ../weather_data/”$ID”_$SENSOR.txt

elif [ $VARIABLE = humidity ]
then
WHOLE=$(echo $VALUE | cut -c 3-4)
DECIMAL=$(echo $VALUE | cut -c 5)
VALUE=$(echo $WHOLE.$DECIMAL)
echo “$VARIABLE=$VALUE” >> ../weather_data/”$ID”_$SENSOR.txt

elif [ $VARIABLE = battery ]
then
echo “$VARIABLE=$VALUE” >> ../weather_data/”$ID”_$SENSOR.txt

elif [ $VARIABLE = rssi ]
then
echo “$VARIABLE=$VALUE” >> ../weather_data/”$ID”_$SENSOR.txt

else
sleep 0
fi

(( FIELD++ ))

done

This reads the raw POST data, then steps through “if” handlers I kludged together to look for each data type.  Grabbing additional data from other sensors would be done just be adding additional handlers for each data type (wind speed, rainfall, etc.).  The script then dumps the data out to files named based on the MAC address and sensor ID’s to a writable directory. I can then query this data from other scripts, or POST it elsewhere (like weather underground, etc.).  Personally, I have a whole web app I’ve written for my IP thermostat that I WAS using external data for the display of outdoor temp/humidity.  Now I’m using ACTUAL data from my AcuLink sensors.   The above script returns just a simple SUCCESS to the Internet Bridge, but the bridge doesn’t seem to care, it just keeps on truckin’ sending more data.  A side-effect to this setup is that your bridge won’t update it’s firmware (possibly breaking any reliance you have on the current behavior) unless you remove your custom DNS entries and let it talk to the “real” Acu-Link web service.

Now, you could stop there and call it a day, but the obvious con to this setup is that Acu-Link’s MyBackyardWeather no longer gets your weather data, and the out-of-the-box graphing, weather forecast’s, mobile apps, etc. are pretty cool.   With a SIMPLE addition to my script, I added the original functionality back in by using curl to POST the data to the “real” web service (in addition to stepping through it locally).  Here’s the addiiton:

curl -d “$POSTDATA” http://acu-link.com/messages/ > /dev/null

Notice I used “acu-link.com” instead of “www.acu-link.com”.  This means our override of the www hostname won’t affect our scripts ability to reach the “real” web service.  A quick visit to MyBackyardWeather confirmed it was again getting fresh data.

In summary, AcuRite makes some great weather hardware, and their Internet Bridge and associated sensor’s are no exception.  I wish they would have built this system a bit more “open” and permitted a simple GET request to the bridge for sensor data, but this product is also very new, and they are very encouraging to their users to suggest new features, etc.  There is even mention that they may offer the ability to query this data directly in the future, but in the meantime: hack-on :P

Sennheiser takes a stab at simple, quality.

Check these out!  Sennheiser is showing off their new Momentum headphones at IFA, and wow, they are sweet!

I’m a sucker for simple, industrial, well-crafted design with a touch of style and class and these look like all that and more.  Brushed stainless, real leather, adjustable. .

I do love my Dre beats, but I’m generally tired of  plastic creaky crap “cans” that look like you’re wearing disposable ear protection.

The real proof lies in how they sound, but I’m keeping my finger’s crossed Sennheiser wouldn’t go to this much trouble to have them sound like crap.

Lehigh Valley Chipotle = OPEN!!!

The day has finally come, Chipotle’s location at the Lehigh Valley Mall in Whitehall, PA is open for business!

If you’ve eaten at a Chipotle before, you’re probably not even still reading and already on your way there, but for those that haven’t, Chipotle offers the very best burritos, tacos, bowls, and salads.

Chipotle strives to serve what they call “food with integrity”, which I’ll use their own words to describe:

“It means serving the very best sustainably raised food possible with an eye to great taste, great nutrition and great value.

It means that we support and sustain family farmers who respect the land and the animals in their care.

It means that whenever possible we use meat from animals raised without the use of antibiotics or added hormones.

And it means that we source organic and local produce when practical. And that we use dairy from cows raised without the use of synthetic hormones.

Food With Integrity is a journey that started more than a decade ago and one that will never end.”

I appreciate/respect all that, but what I care about most is that their food is DELICIOUS/FAST/REASONABLY PRICED.  If you live in the Lehigh Valley, stop reading and start eating:

Chipotle Mexican Grill
837 Lehigh Lifestyle Center
Whitehall, PA 18052

Phone     610.465.9526
Fax     610.264.2560

Open:  Mon-Sun  11am-10pm

You can even order online.

I went around noon today, and the line was approx. 10 minutes long.  They’ve got seating for around 30 people inside with more seating outside.  And yes, it was delicious :)

Cheap LCD Humidity/Hygrometer and Thermometer Mod’d To Show Fahrenheit

I bought 2 of  these little digital gems from DealExtreme for $5.90/ea to keep an eye on temp and humidity in my house, basement, and root cellar.

Several reviews clearly said it only displays Celsius and is not mod’able to display Fahrenheit, but I do enjoy a challenge.  Especially  a challenge where something is dirt cheap :)

The unit arrives pre-assembled from DealExtreme.  You need only open the battery cover, remove the insulator from the battery and it powers right up.  There are indeed no buttons or controls at all, but there’s (4) tiny screws holding it together.  If you remove these (4) screws, carefully pull the LCD off the board (it’s kind of “stuck” on there), and then remove the little black foam piece, you’ll see this:

[Click the image to see the full-size]

Follow my arrows and you see R7 is labeled “C” and R9 “F”.   The resistor on R7 is marked “0″, meaning zero ohms.  It’s just connecting those two solder dots, that’s it.  I carefully pried that off with a utility knife, and soldered a tiny copper wire between the two dots on R9.

Bam!  Fahrenheit instead of Celsius :)

Note: When you put it back together, be careful to line up the LCD with the PCB so that when you apply pressure the display is complete/correct.  Once lined up, re-assemble with the (4) screws.  The pressure of the case is what keeps the LCD pressing on that PCB to maintain the display.

The Return of Steam

Ok, time for me to crawl out of my hole and post something.  I’ve been really busy doing some pretty major work on a new house, but this story caught my eye:

The future of rail could be this 75 year old steam locomotive

http://dvice.com/archives/2012/05/the-future-of-r-1.php

Ever since I was a small boy, I’ve loved steam engines.  While diesel engines sound like an off balance washing machine on spin cycle, steam engines huff, puff, chug, and drip with industrial sexiness.

Steam engines were historically powered by burning dirty coal, and lots of it, but The University of Minnesota and Sustainable Rail International plan on modernizing and converting old No. 3463 from the Sante Fe Railroad to burn biocoal.  Unlike regular coal, biocoal is clean-burning and carbon neutral.

I really hope these guys make a dent in bringing back steam.  When I was younger, growing up in the northeast, you could go 25 miles in any direction and find steam exhibition rides or even tourist railroads running steam, but nowadays finding a running steam engine is next to impossible.  The generation of folks that worked the railroads when these beasts ran freight and passenger service is almost gone, and younger generations just don’t care to get involved.  This could change that.

I rode the Reading 2102 when she ran exhibitions in the early 90’s in Pennsylvania.  If you’ve never seen a running steam engine, here’s video I shot with my dad’s camcorder wayyyy back in 1991:

Yeh, I’m addicted.

Back my friend Tom: “The World in a Bubble Project”

Follow this link to the KICKSTARTER campaign:

http://www.kickstarter.com/projects/1507789251/the-world-in-a-bubble-project

SpamAssassin: Whitelist your friends!

SpamAssassin is an invaluable tool for keeping spam out of your Inbox, but let’s face it, sometimes our friends look like spammers too.

Whether they forward junk mail with a real message on top that you *do* want to read, or if their outlook “stationary” screams of vintage blinking 1995ish internet, there’s two ways to solve this:

1) Get new friends

2) Whitelist them

Since canceling our friendships isn’t generally a good life-move, let’s whitelist them in SpamAssassin.

The first step is locating and opening your user prefs or configuration file.  If you’re the server administrator, and want the whitelist entries to be global, you’ll want to edit:

/etc/mail/spamassassin/local.cf

To edit the prefs for just a single user, you’ll want to look here:

~/.spamassassin/user_prefs

For each sender you want to to whitelist, add the following entry into the config or prefs file:

whitelist_from  user@domain.com

You can also whitelist every sender from an entire domain with the following entry:

whitelist_from  *@domain.com

For even more information and options, checkout the SpamAssassin doc page for whitelisting:

http://wiki.apache.org/spamassassin/ManualWhitelist

MapQuest: Free talking turn-by-turn directions for your iPhone

If you’re an iPhone user with friends on Android devices, you’ve probably seen their super-slick google maps with turn-by-turn directions.  Since the google maps app on iPhone will probably *NEVER* get updated to work the same as it does on android for obvious reasons, you have to look elsewhere for turn-by-turn directions.

I’ve gone down this road in the past, and not found anything free worth using in the app store, but that changed recently.

Remember MapQuest?. .  . you know, that site you went to for directions online before google maps existed?  Well, MapQuest has an iPhone app out called “MapQuest 4 Mobile”.  It’s 100% free, gives turn-by-turn directions both on screen and via voice, and recalculates when you miss a turn.

I tried it on my way home a few days ago, and it worked perfectly.  It *does* like to eat the battery, as any GPS app does.  I left work with ~45% battery, and got home with ~30%.   My drive is 35 miles and usually takes just under an hour, so 15% loss isn’t terrible I suppose.

If you have an iPhone, I strongly suggest you give it a try.

Get it here:

http://itunes.apple.com/us/app/mapquest-4-mobile/id316126557?mt=8&ls=1