Nice!! Last night we were wandering around downtown and stumbled upon the Taste of Arts festival. It was ok, lots of food, some decent live bands, and pop-up tents with pottery, paintings, and knick-knacks. But I was a little bored. Bored until we came to the Maker tent! It looks like we finally have made the big time. We will have a Make Faire at Headwaters Park pavilion this 01-02 October.
A friend in Chicago says that all Fort Wayne has is Cow Tipping. He may be right but now we can build cow-tip-bots.
From the TekVenture website:
Fort Wayne Regional Maker Faire is a family-friendly event to MAKE, create, learn, invent, CRAFT, recycle, think, play and be inspired by celebrating arts, crafts, engineering, food, music, science and technology.
October 1st & 2nd under the pavilion at beautiful Headwaters Park.
Fort Wayne Regional Maker Faire celebrates things people create themselves — from James Bond-worthy electronic gizmos to Martha Stewart-quality "slow made" foods and homemade clothes. Inspiration is ubiquitous at the festival and there are surprises around every corner for people of all ages.
Fort Wayne Regional Maker Faire 2011 - Powered by TekVenture
Saturday, October 01, 2011 at 9:00 AM - Sunday, October 02, 2011 at 6:00 PM (ET)
Fort Wayne, IN
28 August 2011
30 June 2011
Format JSON for JQuery Grids
Yet another wasted evening. I can just be zooming along, writing code and making major progress on my squirrel of the moment project. And then Screech! All progress halts while I struggle with something stupid. Here's the story.
My service returns JSON. Nicely formatted JSON, courtesy of Google's GSON.
I wanted to display it in a grid and I remembered seeing a few JQuery grids that looked easy and claimed they ate JSON. Some of the more popular grids are jqGrid or Flexigrid.
Unfortunately, they don't eat my JSON.
Flexigrid requires JSON to be be in a muck format like this:
jqGrid's needs to be formatted into a similar muck like this.
Of course, neither flexigrid or jqGrid's samples or docs clearly state the format of the JSON. They just proudly claim that they eat JSON and then let me waste a good night staring at an empty grid that refuses to load my data. Like always, Mr Google didn't let me down and led me to the posts of similar idiots that struggled with the data format.
Flexigrid has a preProcess property that lets you receive the data and reformat it on the wire. This Stack Overflow post describes a few diff ways to do this which I tried and had success. It's actually a nice solution
Then a JSON Grid class. The main() method shows how to use. All it needs is the GSON jar which you can download here and then your own data class. In the main(), I use my own Runner class for example, replace with your own.
Here's my Runner class for reference
Here's a snippet from a servlet that grabs Runners from my Google App Engine Persistence Manager and returns JSON.
And finally, here's how I load the flexigrid in my client. Change the URL property to point to our own service that returns formatted JSON
...
$(".myGrid").flexigrid({
url : 'http://YOUR-SERVICE-URL/?query',
dataType : 'json',
method: 'GET',
colModel : [
{display: 'ID', name: 'id', width: 2, sortable: true, align: 'center', hide: true },
{display: 'Name', name: 'name',width: 200, sortable: true, align: 'left'},
{display: 'City', name: 'city', width: 150, sortable : true, align: 'left'},
{display: 'Age', name: 'age', width : 40, sortable: true, align: 'left'},
{display: 'Sex', name: 'sex', width : 40, sortable: true, align: 'right'}
],
buttons : [
{name: 'Add', bclass: 'add', onpress : test},
{name: 'Delete', bclass: 'delete', onpress : test},
{separator : true}
],
searchitems : [
{display: 'City', name: 'city'},
{display: 'Name', name : 'name', isdefault : true}
],
sortname : "name",
sortorder : "asc",
usepager : true,
title : 'Runners',
useRp : true,
rp : 50,
showTableToggleBtn : true,
width : 700,
height : 200
});
My service returns JSON. Nicely formatted JSON, courtesy of Google's GSON.
[{"id":"eda84f836c71","name":"Will","city":"Fuji","age":"23","sex":"M"},
{"id":"9740ef689ad3","name":"Dina","city":"Salla","age":"26","sex":"F"}]
I wanted to display it in a grid and I remembered seeing a few JQuery grids that looked easy and claimed they ate JSON. Some of the more popular grids are jqGrid or Flexigrid.
Unfortunately, they don't eat my JSON.
Flexigrid requires JSON to be be in a muck format like this:
{ "page": 1, "total": 100, "rows": [
{"id":"1", "cell":["content of column 1", "content of column 2",]},
{"id":"2", "cell":["content of column 1", "content of column 2",]}]}
jqGrid's needs to be formatted into a similar muck like this.
Of course, neither flexigrid or jqGrid's samples or docs clearly state the format of the JSON. They just proudly claim that they eat JSON and then let me waste a good night staring at an empty grid that refuses to load my data. Like always, Mr Google didn't let me down and led me to the posts of similar idiots that struggled with the data format.
Flexigrid has a preProcess property that lets you receive the data and reformat it on the wire. This Stack Overflow post describes a few diff ways to do this which I tried and had success. It's actually a nice solution
$("#gridContainer").flexigrid({
url: '/YourService.svc/..',
method: 'GET',
dataType: 'json',
preProcess: formatCustomerResults,
...
});
function formatCustomerResults(Customers){
var rows = Array();
for (i = 0; i < Customers.length; i++) {
var item = Customers[i];
rows.push({ cell: [item.DealId,
item.Created,
item.CurrentStatus,
item.LastNote] });
}
return {
total: Customers.length,
page: 1,
rows: rows
};
}But since I always have to do things my way, I decided that I 'd return formatted JSON from my service. So... First I create a Row class public class Row {
public Row(int id, Object cell) {
setId(id);
setCell(cell);
}
private int id;
private Object cell;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setCell(Object cell) {
this.cell = cell;
}
public Object getCell() {
return cell;
}
}Then a JSON Grid class. The main() method shows how to use. All it needs is the GSON jar which you can download here and then your own data class. In the main(), I use my own Runner class for example, replace with your own.
import java.util.ArrayList;
import java.util.List;
import com.google.gson.Gson;
public class JsonGrid {
private int page;
private int total;
private List rows;
public JsonGrid(int page, int total, List rows) {
setPage(page);
setTotal(total);
setRows(rows);
}
public static void main(String[] args) {
List runners = new ArrayList();
Runner will = new Runner("Will", "Fuji", "23", "M");
runners.add(will);
Runner dina = new Runner("Dina", "Sala", "22", "F");
runners.add(dina);
int i = 0;
List rows = new ArrayList();
for (Runner runner : runners) {
Row row = new Row(i++, runner);
rows.add(row);
}
JsonGrid grid = new JsonGrid(1, 1, rows);
Gson gson = new Gson();
System.out.println(gson.toJson(runners));
System.out.println();
System.out.println(gson.toJson(grid));
}
public void setPage(int page) {
this.page = page;
}
public int getPage() {
return page;
}
public void setTotal(int total) {
this.total = total;
}
public int getTotal() {
return total;
}
public void setRows(List rows) {
this.rows = rows;
}
public List getRows() {
return rows;
}
}
Here's my Runner class for reference
import java.util.UUID;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
@PersistenceCapable
public class Runner {
@PrimaryKey
@Persistent
private String id;
@Persistent
private String name;
@Persistent
private String city;
@Persistent
private String age;
@Persistent
private String sex;
public Runner() {
super();
}
public Runner(String name, String age, String sex, String city) {
super();
name = clean(name);
city = clean(city);
age = clean(age);
sex = clean(sex);
this.id = UUID.randomUUID().toString();
this.name = name;
this.city = city;
this.age = age;
this.sex = sex;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
private String clean(String dirty) {
String cleaned = dirty;
cleaned = cleaned.trim();
cleaned = cleaned.replace("'", "");
cleaned = cleaned.replace("?", "");
cleaned = cleaned.replace("*", "");
return cleaned;
}
public String getName() {
return name;
}
public void setName(String name) {
name = clean(name);
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
city = clean(city);
this.city = city;
}
public String getAge() {
return age;
}
public void setAge(String age) {
age = clean(age);
this.age = age;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getSex() {
return sex;
}
public String toString()
{
final String TAB = " ";
String retValue = "";
retValue = "Runner ( "
+ super.toString() + TAB
+ "name = " + this.name + TAB
+ "city = " + this.city + TAB
+ "age = " + this.age + TAB
+ "sex = " + this.sex + TAB
+ " )";
return retValue;
}
}Here's a snippet from a servlet that grabs Runners from my Google App Engine Persistence Manager and returns JSON.
import javax.jdo.PersistenceManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.Gson;
...
public void doGet(HttpServletRequest req, HttpServletResponse response) throws IOException {
...response.setContentType("application/json");
...
// build a query string
String query = "select from " + Runner.class.getName()
+ " where runnerCity=='" + runnerCity + "'";
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
List runners = (List)pm.newQuery(query).execute();
int i = 0;
List rows = new ArrayList();
for (Runner runner : runners) {
Row row = new Row(i++, runner);
rows.add(row);
}
JsonGrid grid = new JsonGrid(1, 1, rows);
Gson gson = new Gson();
response.getWriter().println(gson.toJson(grid));
...
And finally, here's how I load the flexigrid in my client. Change the URL property to point to our own service that returns formatted JSON
...
What do you think? Leave a comment.
30 January 2011
Apache ActiveMQ Startup Exception
I don't use ActiveMQ a lot but when I get back to a project where I was using it, I seem to get startup exceptions pretty often. The stack trace is really long and ugly.
java.io.EOFException: Chunk stream does not exist at page: 0
At first I wasn't sure what was going on, just deleted the activemq folder, unzipped the distro, and back running in minutes. The next time it happened, I spent a few minutes looking at what I may have done to cause this.
Out of just dumb luck, I found that if I deleted the activemq/data folder contents (not the data folder itself, just the contents - kahadb, localhost, etc), I could restart without error. Turns out that there's a bug in KahaDB, the default persistence store in ActiveMQ.
I've found no side effects from deleting the data folder contents, none of my deployed apps need to maintain message persistence between shutdowns.
YMMV.
java.io.EOFException: Chunk stream does not exist at page: 0
At first I wasn't sure what was going on, just deleted the activemq folder, unzipped the distro, and back running in minutes. The next time it happened, I spent a few minutes looking at what I may have done to cause this.
Out of just dumb luck, I found that if I deleted the activemq/data folder contents (not the data folder itself, just the contents - kahadb, localhost, etc), I could restart without error. Turns out that there's a bug in KahaDB, the default persistence store in ActiveMQ.
I've found no side effects from deleting the data folder contents, none of my deployed apps need to maintain message persistence between shutdowns.
YMMV.
What do you think? Leave a comment.
Android SMS XML Parsing
Using XML with SMS sounds kinda dumb. After all an SMS text is only 140 characters (or less ...) and XML is horribly bloated. But if the originating application is using XML and SMS is the convenient transport, then nothing's too stupid.
There's plenty of articles that describe the various Android options for parsing XML. SAX, DOM, and XML Pull. Actually, I'd prefer to use XStream for quick XML read/writing but with the XStream jar around 500k, it's not a good droid choice.
I'm going to quickly show you how I intercept incoming SMS messages and route them to an XML parser if the message starts with a tag (in my case <evt>). After parsing, I then look at fields in the message and then start other processing that I won't go into here.
I'll show you some quick screen shots of the code and attempt to explain. At the end of the article, you'll find a link to the entire Eclipse project. This has been tailored down quite a bit from how I'm using it. It simply sniffs incoming messages and then displays XML fields.
An example incoming XML SMS message looks like this. I'm receiving XML SMS messages from several sources such as email (like below) and from Twitter (like I blogged about here and here).
Even though my sample SMS XML message shows line breaks so the XML is nicely formated, you don't want to do this. Don't waste a precious character on a break. Run all the XML tags together. My XML Pull Parser class is expecting no line breaks.
In AndroidManifest.xml, add a receiver for the SMS_RECEIVED action to your application and add RECEIVE_SMS to your permissions:
In your receiver class (the one that you named in your manifest file), extend BroadcastReceiver and implement onReceive. After jumping thru a few hoops to get the message content, determine if this is a message you care about. My "special" messages all have the XML tag "" after a few header characters depending on the source (such as email or Twitter). If I find this tag, I display a quick toast and then send the message for XML parsing.
There's plenty of articles that describe the various Android options for parsing XML. SAX, DOM, and XML Pull. Actually, I'd prefer to use XStream for quick XML read/writing but with the XStream jar around 500k, it's not a good droid choice.
I'm going to quickly show you how I intercept incoming SMS messages and route them to an XML parser if the message starts with a tag (in my case <evt>). After parsing, I then look at fields in the message and then start other processing that I won't go into here.
I'll show you some quick screen shots of the code and attempt to explain. At the end of the article, you'll find a link to the entire Eclipse project. This has been tailored down quite a bit from how I'm using it. It simply sniffs incoming messages and then displays XML fields.
An example incoming XML SMS message looks like this. I'm receiving XML SMS messages from several sources such as email (like below) and from Twitter (like I blogged about here and here).
Even though my sample SMS XML message shows line breaks so the XML is nicely formated, you don't want to do this. Don't waste a precious character on a break. Run all the XML tags together. My XML Pull Parser class is expecting no line breaks.
In AndroidManifest.xml, add a receiver for the SMS_RECEIVED action to your application and add RECEIVE_SMS to your permissions:
...
In your receiver class (the one that you named in your manifest file), extend BroadcastReceiver and implement onReceive. After jumping thru a few hoops to get the message content, determine if this is a message you care about. My "special" messages all have the XML tag "
Here's an example Eclipse app that parses incoming SMS message and checks if they have the tage. If so, a toast message is displayed and the sent of for XML parsing. After parsing, the app simply display the contents of a few of the XML tag contents.
My deployed app is actually an Android service, not a simple app like this example.
Download the example.
What do you think? Leave a comment.
28 January 2011
HTC G1 adb "No Permissions"
Update: After I wrote this post, I had the No permissions and a device name of ???????? all over again. After spending yet more time on this, I found that the key is to kill and restart the server as root (sudo). See commands at end of this post.
--------------------------------------------------------
I bought a used HTC G1 from eBay so I could prototype a droid interface to a custom sensor. I didn't want to brick my daily use DroidX and heard that the G1 had a pretty decent serial interface ability.
I paid a little more than I wanted but those suckers are selling for about $125 which ain't bad (for the seller) for a 2+ year old phone. After a week or so of bidding, I ended up with a decent condition phone for $83 including shipping.
The phone is locked to T-Mobile and has no sim card but that's okay because I plan to use this as wifi only. Unfortunately I haven't been able to run the Android Debug Bridge (adb) or use the Android Development Tools (ADT) plugin for Eclipse.
At first I thought my problem with getting the adb "no permission error" was because my phone wasn't activated.
I read thru a few links on how to activate a no sim card phone and decided that it wasn't the issue and needed to keep investigating other causes.
Squirrel. Before I go into a little more detail, let me share a quick story. My shiny used G1 didn't come with a USB cable so I bought a cable (also from eBay) for about $1.78 including shipping. Unfortunately for that screaming deal, it was being shipped from a country far far away. A few days after I paid (mid January), I received this email:
And a week later, my package arrived. That was a fast 35 days, I guess they found "ebough" planes ... But the cable didn't work. I looked at the auction again to make sure that it said it was for a G1. Sure enough, it states:
But in small print, says:
Ok, so what's an HTC G1 that's not a cell phone?
I wasn't going to even waste my time for $1.78 to contact the seller, chalk it up as another buyer beware.
But I did what I should've done next. Use my leftover unused Blackberry cable. Fits perfect, charge light goes on and I can mount the G1's SD card.
Back to the main story.
Besides the "no permissions" error with adb, I can't communicate via the Eclipse plug-in.
I checked the devices android version to make sure that I had the corresponding SDK platform revision, which I did.
Mr Google yielded some ideas. One hit suggested that I use sudo with adb. I don't think that'll help but sure let's try.
Then came across a useful hit Using ADB in Linux that describes that we need to create a file to change permissions and ownership of a device node. Here's how:
Sweet!
--------------------------------------------------------
I bought a used HTC G1 from eBay so I could prototype a droid interface to a custom sensor. I didn't want to brick my daily use DroidX and heard that the G1 had a pretty decent serial interface ability.
I paid a little more than I wanted but those suckers are selling for about $125 which ain't bad (for the seller) for a 2+ year old phone. After a week or so of bidding, I ended up with a decent condition phone for $83 including shipping.
The phone is locked to T-Mobile and has no sim card but that's okay because I plan to use this as wifi only. Unfortunately I haven't been able to run the Android Debug Bridge (adb) or use the Android Development Tools (ADT) plugin for Eclipse.
At first I thought my problem with getting the adb "no permission error" was because my phone wasn't activated.
I read thru a few links on how to activate a no sim card phone and decided that it wasn't the issue and needed to keep investigating other causes.
Squirrel. Before I go into a little more detail, let me share a quick story. My shiny used G1 didn't come with a USB cable so I bought a cable (also from eBay) for about $1.78 including shipping. Unfortunately for that screaming deal, it was being shipped from a country far far away. A few days after I paid (mid January), I received this email:
"we have sent the item you ordered from us today.It would take you 25-35
working days to get it.because of near merry christmas,at the airport were
plied so many package ,plane is not ebough ,every package are slow,hopey
you can understanding ,If you haven't got it within 35 days,please let me
know.,And"
working days to get it.because of near merry christmas,at the airport were
plied so many package ,plane is not ebough ,every package are slow,hopey
you can understanding ,If you haven't got it within 35 days,please let me
know.,And"
And a week later, my package arrived. That was a fast 35 days, I guess they found "ebough" planes ... But the cable didn't work. I looked at the auction again to make sure that it said it was for a G1. Sure enough, it states:
USB Sync Data Cord Cable For GOOGLE HTC G1 Android
But in small print, says:
Compatible with: HTC G1(not include the cell phone)
Ok, so what's an HTC G1 that's not a cell phone?
I wasn't going to even waste my time for $1.78 to contact the seller, chalk it up as another buyer beware.
But I did what I should've done next. Use my leftover unused Blackberry cable. Fits perfect, charge light goes on and I can mount the G1's SD card.
Back to the main story.
Besides the "no permissions" error with adb, I can't communicate via the Eclipse plug-in.
I checked the devices android version to make sure that I had the corresponding SDK platform revision, which I did.
Mr Google yielded some ideas. One hit suggested that I use sudo with adb. I don't think that'll help but sure let's try.
Then came across a useful hit Using ADB in Linux that describes that we need to create a file to change permissions and ownership of a device node. Here's how:
- Create a file /etc/udev/rules.d/50-android.rules with this command:
sudo gedit /etc/udev/rules.d/51-android.rules
- Type in the contents of the file. The version of linux may cause the syntax to differ slightly. I'm using Ubuntu 11.04 Natty Narwhal and my contents are in the pic below.

I've also seen instructions to use this:
SUBSYSTEMS==”usb”, ATTRS{idVendor}==”0bb4″, ATTRS{idProduct}==”0c01″, MODE=”0666″
Note the diff between what I used SUBSYSTEM vs SUBSYSTEMS and ATTRS
Here's an interesting read on Writing udev Rules.
- Change permissions of the file
sudo chmod a+r /etc/udev/rules.d/51-android.rules
- Restart udev
sudo restart udev
- Stop and restart adb
sudo ./adb kill-server
sudo ./adb start-server
- List the devices
Sweet!
What do you think? Leave a comment.
18 December 2010
Can't SSH to Amazon Elastic Compute Cloud (EC2) Instance
I've decided that I'm going to learn about Amazon Elastic Compute Cloud (EC2) over this Holiday break. I've read a few articles, listened to a few podcasts so I have an idea what it's about, just haven't actually gone thru the motions myself.
What am I going to do with a virtual machine (VM) in the cloud? Not much quite yet. I have some ideas but first need to figure out how things work.
So on Friday night I signed up for an EC2 account and started to follow the Getting Started Guide on the Amazon site. As usual, things went smooth for the first few minutes but as usual, progress came to an immediate screeching.
I started an plain vanilla Basic 64-bit Amazon Linux Amazon Machine Image (AMI) just to get things going and verify that I could SSH into the thing per the getting started guide. But when I SSH'd, nothing, nada, zip. Timeout.
This darn thing acts like it's not running. I started, restarted, used different AMI, mucked with security group setting without any progress. I even edited the default security group to open the thing wide open:
Still nothing. Did the google thing to see what other people are doing and came across a few hits in the Amazon Web Services forums where people are claiming the the web services aren't starting up correctly in the US-East zone. Hey, that's me! Ok, I'm not stupid, its just some tech problem. I'll take a break and try it again in a few hours.
Few hours later: nothing, nada, zip. Ok, I am stupid. I can't even log into a stupid instance. I probably started/stopped an EC2 AMI 10 times but can't do anything with it. This new thing I've learned is frickin' amazing.
And as usual, as soon as I've convinced myself that all hope is lost, ding. Wait, doesn't my Westell DSL modem block SSH? Oh, frick of course it does. Damn it so, the last 3-4 hours of trouble was caused by my own firewall??
Of course it was. I really hate this Verizon provided modem and keep telling myself that I'm going to buy a different one. But this is free and I'm cheap. So I'll keep shooting myself in the foot and someday get smarter and dump this junk.
In the Firewall->Port Forwarding menu, I just added the SSH service to a dynamic host.
And now when I launch a new instance, I get this:
Amazing. Only hours and hours of work to launch and connect. Let the fun begin.
What am I going to do with a virtual machine (VM) in the cloud? Not much quite yet. I have some ideas but first need to figure out how things work.
So on Friday night I signed up for an EC2 account and started to follow the Getting Started Guide on the Amazon site. As usual, things went smooth for the first few minutes but as usual, progress came to an immediate screeching.
I started an plain vanilla Basic 64-bit Amazon Linux Amazon Machine Image (AMI) just to get things going and verify that I could SSH into the thing per the getting started guide. But when I SSH'd, nothing, nada, zip. Timeout.
This darn thing acts like it's not running. I started, restarted, used different AMI, mucked with security group setting without any progress. I even edited the default security group to open the thing wide open:
Still nothing. Did the google thing to see what other people are doing and came across a few hits in the Amazon Web Services forums where people are claiming the the web services aren't starting up correctly in the US-East zone. Hey, that's me! Ok, I'm not stupid, its just some tech problem. I'll take a break and try it again in a few hours.
Few hours later: nothing, nada, zip. Ok, I am stupid. I can't even log into a stupid instance. I probably started/stopped an EC2 AMI 10 times but can't do anything with it. This new thing I've learned is frickin' amazing.
And as usual, as soon as I've convinced myself that all hope is lost, ding. Wait, doesn't my Westell DSL modem block SSH? Oh, frick of course it does. Damn it so, the last 3-4 hours of trouble was caused by my own firewall??
Of course it was. I really hate this Verizon provided modem and keep telling myself that I'm going to buy a different one. But this is free and I'm cheap. So I'll keep shooting myself in the foot and someday get smarter and dump this junk.
In the Firewall->Port Forwarding menu, I just added the SSH service to a dynamic host.
And now when I launch a new instance, I get this:
Amazing. Only hours and hours of work to launch and connect. Let the fun begin.
What do you think? Leave a comment.
29 November 2010
Working with the 90 Character Limit of Twitter
What? Twitter has a 90 character limit? No, it's 140. Everyone knows that.
Mr Wikipedia says this about SMS length:
"... resources in the system could be used to transport messages at minimal cost. However, it was necessary to limit the length of the messages to 128 bytes (later improved to 140 bytes, or 160 seven-bit characters) so that the messages could fit into the existing signaling formats."
Using the Groovy code that I did the other day to send a text message via a twitter Direct Message, if the message length is greater than 140 characters, twitter complains with this error:
403:The request is understood, but it has been refused. An accompanying error message will explain why.
{"request":"\/1\/direct_messages\/new.json","error":"The text of your direct message is over 140 characters."}
TwitterException{exceptionCode=[6bcd7469-01bff100], statusCode=403, retryAfter=0, rateLimitStatus=null, version=2.1.7}
That kinda says that I can send 140 characters, so what's this nonsense about a 90 character limit?
Well, true, you can send 140 characters but if you're hacking the system for the purposes of having Twitter forward your message as a text message to a phone then different rules apply.
Take a look at what happens when you send a Direct Message of 140 characters to an account that is set up to send a txt:
For the app that I'm working on, I need my data in a single text message, I don't want the mess of re-assembling.
I think the message split is because a header of:
"Direct from" screen name:
and a footer of
"Reply with 'd" screen name "hi.'"
is added to each message.
I've found that the amount of data that you can actually send depends on the screen name. Since screen names can be up to 15 chars, you lose:
Header:
Direct from screenname:
= up to 28 characters (12 + screen name)
Footer:
Reply with 'd screenname hi.'
= up to 34 characters (19 + screen name)
140 - 28 - 34 = 78
Uh, 78 is not 90. What the heck? I guess my math has errors.
But check this out. By adjusting my direct message, I find that a 90 character message is the sweet spot for a 15 character screen name and the message is sent as a single text. 91 characters will cause the message to be split over 2 texts.
Maybe that header and footer isn't as big as I think it is.
140 - 90 = 50 characters for header/footer?
If a screen name is used twice (2 * 15 = 30), then maybe the bloat is only 20 characters?
What happens if I send messages to a different screen name, one that is smaller than 15 characters?
What is I use a screen name of 8 characters? Should I be able to send a message of
140 - 20 (bloat) - (2 * 8) = 104 characters?
After a quick reassignment of my phone to a different twitter account, I tried a test with a screen name that is 8 characters. Could I send 104? Durn right I could! And I could also send 109. But 110 would cause a message split. So I have an extra 5 characters unaccounted for.
What happens if I send to a ... No, this is going on too long.
The max screen name is 15 characters and that limits the max amount of data that can be sent in one message to 90 characters.
If the screen name is less than 15 characters, then you get 90 plus some extra. YMMV
Mr Wikipedia says this about SMS length:
"... resources in the system could be used to transport messages at minimal cost. However, it was necessary to limit the length of the messages to 128 bytes (later improved to 140 bytes, or 160 seven-bit characters) so that the messages could fit into the existing signaling formats."
Using the Groovy code that I did the other day to send a text message via a twitter Direct Message, if the message length is greater than 140 characters, twitter complains with this error:
403:The request is understood, but it has been refused. An accompanying error message will explain why.
{"request":"\/1\/direct_messages\/new.json","error":"The text of your direct message is over 140 characters."}
TwitterException{exceptionCode=[6bcd7469-01bff100], statusCode=403, retryAfter=0, rateLimitStatus=null, version=2.1.7}
That kinda says that I can send 140 characters, so what's this nonsense about a 90 character limit?
Well, true, you can send 140 characters but if you're hacking the system for the purposes of having Twitter forward your message as a text message to a phone then different rules apply.
Take a look at what happens when you send a Direct Message of 140 characters to an account that is set up to send a txt:
String message = "12345678911234567892123456789312345678941234567895" +
"12345678961234567897123456789812345678991234567891" +
"1234567891123456789212345678931234567894"
DirectMessage directMessage = twitter.sendDirectMessage(screenName, message)Twitter breaks the message into 2 separate texts (and my phone occasionally gets the 2nd text first).For the app that I'm working on, I need my data in a single text message, I don't want the mess of re-assembling.
I think the message split is because a header of:
"Direct from" screen name:
and a footer of
"Reply with 'd" screen name "hi.'"
is added to each message.
I've found that the amount of data that you can actually send depends on the screen name. Since screen names can be up to 15 chars, you lose:
Header:
Direct from screenname:
= up to 28 characters (12 + screen name)
Footer:
Reply with 'd screenname hi.'
= up to 34 characters (19 + screen name)
140 - 28 - 34 = 78
Uh, 78 is not 90. What the heck? I guess my math has errors.
But check this out. By adjusting my direct message, I find that a 90 character message is the sweet spot for a 15 character screen name and the message is sent as a single text. 91 characters will cause the message to be split over 2 texts.
Maybe that header and footer isn't as big as I think it is.
140 - 90 = 50 characters for header/footer?
If a screen name is used twice (2 * 15 = 30), then maybe the bloat is only 20 characters?
What happens if I send messages to a different screen name, one that is smaller than 15 characters?
What is I use a screen name of 8 characters? Should I be able to send a message of
140 - 20 (bloat) - (2 * 8) = 104 characters?
After a quick reassignment of my phone to a different twitter account, I tried a test with a screen name that is 8 characters. Could I send 104? Durn right I could! And I could also send 109. But 110 would cause a message split. So I have an extra 5 characters unaccounted for.
What happens if I send to a ... No, this is going on too long.
The max screen name is 15 characters and that limits the max amount of data that can be sent in one message to 90 characters.
If the screen name is less than 15 characters, then you get 90 plus some extra. YMMV
What do you think? Leave a comment.
27 November 2010
Send SMS Text Message from Java/Groovy - via Twitter
Writing code to send an SMS text message is fairly easy on a smart phone like an Android. But from a desktop, sending texts is still a mess, not always free, and/or requires a phone connected to your server.
I simply want to send a message to my phone when my app receives some data. I don't need a complex library with lots of setup nor do I want to sign up for a pay service.
Now this isn't the cleanest solution to text from an app but Twitter can send messages to your phone when people you follow update their status, when someone mentions or replies to you, or when you get a direct message.
My last two write-ups, "Send a Simple Tweet with OAuth and Groovy" and "Send a Direct Message Tweet with Groovy" showed how easy it is to use Java/Groovy and the Twitter4J library to send messages to your own Twitter account or a message to anyone else.
By sending a tweet to an account that you follow or a Direct Message to your own account, Twitter can be setup to forward that message to a phone that you associate with your account.
Simply go to your Twitter account, Settings, Mobile and follow the easy instruction. Then use one of the sample apps from my previous posts and tweet-text away!
Note:
I simply want to send a message to my phone when my app receives some data. I don't need a complex library with lots of setup nor do I want to sign up for a pay service.
Now this isn't the cleanest solution to text from an app but Twitter can send messages to your phone when people you follow update their status, when someone mentions or replies to you, or when you get a direct message.
My last two write-ups, "Send a Simple Tweet with OAuth and Groovy" and "Send a Direct Message Tweet with Groovy" showed how easy it is to use Java/Groovy and the Twitter4J library to send messages to your own Twitter account or a message to anyone else.
By sending a tweet to an account that you follow or a Direct Message to your own account, Twitter can be setup to forward that message to a phone that you associate with your account.
Simply go to your Twitter account, Settings, Mobile and follow the easy instruction. Then use one of the sample apps from my previous posts and tweet-text away!
Note:
- This only allows you to tweet-text to phones that have been setup to follow accounts.
- This does not allow you to send a text to a cell phone not registered with Twitter.
- This works for what I need.
- Do you know a better/easier, free method? Write a comment!
What do you think? Leave a comment.
Send a Direct Message Tweet with Groovy
Alright. Using the Twitter4J library and Groovy, I've beaten down the OAuth beast and have a simple example app to send a "update status" tweet.
Now instead of sending a message to my own account, let's do a real easy mod to send a Direct Message to a specific user Using the same app as before, the only changes needed are:
Now instead of sending a message to my own account, let's do a real easy mod to send a Direct Message to a specific user Using the same app as before, the only changes needed are:
- import DirectMessage
- change from twitter.updateStatus(message) to twitter.sendDirectMessage(screenName, message)
import twitter4j.DirectMessage;
import twitter4j.Twitter
import twitter4j.TwitterFactory
import twitter4j.Status
import twitter4j.http.AccessToken
import twitter4j.http.RequestToken
import java.io.BufferedReader
import com.thoughtworks.xstream.XStream
try{
Twitter twitter = new TwitterFactory().getInstance();
// set key and secret that you get from Twitter app registeration at:
// http://dev.twitter.com/pages/auth#register
twitter.setOAuthConsumer("Your Consumer key", "Your Consumer secret");
// load access token if it exists
AccessToken accessToken = null
def tokenFile = new File("accessToken.xml")
if (tokenFile.exists()) {
def xstream = new XStream()
tokenFile.withInputStream { ins -> accessToken = xstream.fromXML(ins) }
twitter.setOAuthAccessToken(accessToken)
}
else {
// get the URL to request access to Twitter acct
RequestToken requestToken = twitter.getOAuthRequestToken();
String authUrl = requestToken.getAuthorizationURL()
System.out.println("Open the following URL and grant access to your account:");
System.out.println(authUrl);
// take the PIN and get access token
System.out.print("Enter the PIN:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String pin = ""
pin = br.readLine();
accessToken = twitter.getOAuthAccessToken(requestToken, pin);
// persist token
def xstream = new XStream()
xstream.classLoader = getClass().classLoader
new File("accessToken.xml").withOutputStream { out -> xstream.toXML(accessToken, out) }
}
String message = "from Groovy w/ token" + accessToken.getToken()
String screenName ="ScreenNameToSendTo"
DirectMessage directMessage = twitter.sendDirectMessage(screenName, message)
System.out.println("Direct message sent to " + directMessage.getRecipientScreenName());
} catch (Exception e) {
e.printStackTrace();
}What do you think? Leave a comment.
Sending a Simple Tweet with OAuth and Java/Groovy
Come on, man! What used to a be a simple task to send a tweet is now a OAuth nightmare.
A year or so ago, I built that tweet-a-w/e thing that sniffed XBee chirps and sent them to a twitter account that kindly routed them to my cell phone.
I have a need now to receive an XML stream, parse out a few tidbits and then send the results out as a SMS text message. Remembering that tweet-a-w/e app, I thought that I would again leverage Twitter to send the text message. All I need to do is send a tweet via a Twitter API and have my account set up to send the content to a phone number.
This time my XML receiver is in Java/Groovy, so I grabbed the latest Twitter4J, glanced at the UpdateStatus example and tried a quick test with Groovy.
What the heck? Basic Authentication is not supported? Darn it, what is this stupid OAuth thing about? Here's the Twitter page "Authenticating Requests with OAuth" that looks real interesting to read. Arghhhhh. I just want to send a flippin' tweet, I really don't have time to research this at Hueniverse.
After some more quick Googling, this isn't as bad as it first looks.It boils down to getting a key and secret pair. The steps are:
Ok, so that works. But every time you run the program, you need to go and fetch the darn token. According to Twitter, the token doesn't expire, so let's persist the thing.
I like using XStream to serialize Java/Groovy objects to/from XML. A quick update to the code above lets us save an XML file that we can reload as needed.
The serialized Access Token looks like this:
Notes:
For the above examples, I used:
A year or so ago, I built that tweet-a-w/e thing that sniffed XBee chirps and sent them to a twitter account that kindly routed them to my cell phone.
I have a need now to receive an XML stream, parse out a few tidbits and then send the results out as a SMS text message. Remembering that tweet-a-w/e app, I thought that I would again leverage Twitter to send the text message. All I need to do is send a tweet via a Twitter API and have my account set up to send the content to a phone number.
This time my XML receiver is in Java/Groovy, so I grabbed the latest Twitter4J, glanced at the UpdateStatus example and tried a quick test with Groovy.
import twitter4j.Twitter
import twitter4j.TwitterFactory
import twitter4j.Status
Twitter twitter = new TwitterFactory().getInstance("myAcct","myPassword");
Status status = twitter.updateStatus("from Groovy");
System.out.println("Successfully updated the status to [" + status.getText() + "].");
Did that work? Of course not. Authentication FAIL.Caught: 401:Authentication credentials were missing or incorrect.
{"errors":[{"code":53,"message":"Basic authentication is not supported"}]}
TwitterException{exceptionCode=[15bb6564-00e5bee0], statusCode=401, retryAfter=0, rateLimitStatus=null, version=2.1.7}
What the heck? Basic Authentication is not supported? Darn it, what is this stupid OAuth thing about? Here's the Twitter page "Authenticating Requests with OAuth" that looks real interesting to read. Arghhhhh. I just want to send a flippin' tweet, I really don't have time to research this at Hueniverse.
After some more quick Googling, this isn't as bad as it first looks.It boils down to getting a key and secret pair. The steps are:
- Goto Twitter and register your app.
- You'll get a consumer key and secret which are similar to the public and private keys used in protocols such as ssh.
- Use the key and secret to sign every request you make to the Twitter API
import twitter4j.Twitter
import twitter4j.Twitter
import twitter4j.TwitterFactory
import twitter4j.Status
import twitter4j.http.AccessToken
import twitter4j.http.RequestToken
import java.io.BufferedReader
try{
Twitter twitter = new TwitterFactory().getInstance();
// set key and secret that you get from Twitter app registeration at:
// http://dev.twitter.com/pages/auth#register
twitter.setOAuthConsumer("Your Consumer key", "Your Consumer secret");
// get the URL to request access to Twitter acct
RequestToken requestToken = twitter.getOAuthRequestToken();
String authUrl = requestToken.getAuthorizationURL()
System.out.println("Open the following URL and grant access to your account:");
System.out.println(authUrl);
// take the PIN and get access token
System.out.print("Enter the PIN:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String pin = ""
pin = br.readLine();
AccessToken accessToken = twitter.getOAuthAccessToken(requestToken, pin);
String message = "from Groovy w/ pin" + pin
Status status = twitter.updateStatus(message);
System.out.println("Successfully sent " + message);
} catch (Exception e) {
e.printStackTrace();
} Ok, so that works. But every time you run the program, you need to go and fetch the darn token. According to Twitter, the token doesn't expire, so let's persist the thing.
I like using XStream to serialize Java/Groovy objects to/from XML. A quick update to the code above lets us save an XML file that we can reload as needed.
import twitter4j.Twitter
import twitter4j.TwitterFactory
import twitter4j.Status
import twitter4j.http.AccessToken
import twitter4j.http.RequestToken
import java.io.BufferedReader
import com.thoughtworks.xstream.XStream
try{
Twitter twitter = new TwitterFactory().getInstance();
// set key and secret that you get from Twitter app registeration at:
// http://dev.twitter.com/pages/auth#register
twitter.setOAuthConsumer("Your Consumer key", "Your Consumer secret");
// load access token if it exists
AccessToken accessToken = null
def tokenFile = new File("accessToken.xml")
if (tokenFile.exists()) {
def xstream = new XStream()
tokenFile.withInputStream { ins -> accessToken = xstream.fromXML(ins) }
twitter.setOAuthAccessToken(accessToken)
}
else {
// get the URL to request access to Twitter acct
RequestToken requestToken = twitter.getOAuthRequestToken();
String authUrl = requestToken.getAuthorizationURL()
System.out.println("Open the following URL and grant access to your account:");
System.out.println(authUrl);
// take the PIN and get access token
System.out.print("Enter the PIN:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String pin = ""
pin = br.readLine();
accessToken = twitter.getOAuthAccessToken(requestToken, pin);
// persist token
def xstream = new XStream()
xstream.classLoader = getClass().classLoader
new File("accessToken.xml").withOutputStream { out -> xstream.toXML(accessToken, out) }
}
String message = "from Groovy w/ token" + accessToken.getToken()
Status status = twitter.updateStatus(message);
System.out.println("Successfully sent " + message);
} catch (Exception e) {
e.printStackTrace();
}The serialized Access Token looks like this:
5555555-AbCdEF 1oKiOlOlOlOl oauth_token=5555555-AbCdEF oauth_token_secret=1oKiOlOlOlOl user_id=007 screen_name=bond bond 007
Notes:
For the above examples, I used:
- Groovy Version: 1.7.0 JVM: 1.6.0_22
- Twitter4J 2.1.7 For this, I copied only the twitter4j-core-2.1.7.jar into the Groovy lib folder. On Linux, this is /usr/share/Groovy/lib
- XStream 1.3.1 For this, I copied the xstream-1.3.1.jar and xpp3_min-1.1.4c.jar into the Groovy lib
What do you think? Leave a comment.
13 August 2010
Sad Day for the Great White Boxster
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.
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.
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!
Subscribe to:
Posts (Atom)
































