Homebrew contest 1st place: Packet Radio Go-Kit with node.js Packet to Twitter bridge

Super excited (and rather surprised!) to win the 1st place prize in the Homebrew Contest at this month’s River City Amateur Radio Communications Society club meeting last night!

My entry was something I’ve been working on over the past few months on and off to get ready in time for this month’s contest. There were two parts to my entry:

1. A self-contained, portable 2m Packet Radio Go-Kit. I put this together using:

  • 10″ waterproof gear case (from MCM)
  • 2m HT radio
  • Raspberry Pi 3
  • 7″ touchscreen
  • a TNC-PI packet add-on board for the Pi, from Coastal Chipworks (which I assembled as a kit)
  • ax25 apps (for axlisten and axcall)

2. A Packet Radio to Twitter bridge (implemented using JavaScript on node.js). While the goals and benefits of a portable Packet radio kit are somewhat more obvious, writing an app that receives Packet Radio transmissions and then retransmits them as Tweets on Twitter doesn’t have many practical applications. The main motivation for this part of the project was that I thought it would be an interesting blend of old tech and new tech. The popularity of Packet Radio declined with the arrival of easy access dial-up information services and BBSes in the 80s and then access to the internet in the early 90s, so linking the two together seemed an interesting idea. Plus, it’s an interesting stepping stone and talking point from common-place tech used on our wireless devices today, with data communications enabled via Amateur Radio.

I put together a number of articles as I was assembling my project and working on the Packet to Twitter interface. If you’d like to read more, here’s links to my previous posts:

Building an Amateur Radio packet to Twitter bridge: Part 2 – Understanding Twitter’s API rate limits

Quick update on my project to build an Amateur Radio Packet to Twitter bridge (see here for the first post).

I’ve moved the node.js code to a Raspberry Pi 3. So far I have up and running:

Twitter provides an incredibly useful REST based API to integrate with their service, but understandably your usage is ‘rate limited’ so you’re not retrieving vast amounts of data or flooding the service with spam Tweets.

To understand their rate limit approach, see this article: https://dev.twitter.com/rest/public/rate-limiting

For limits on POSTs, for example for creating new Tweets: https://support.twitter.com/articles/15364

Per above article, POSTs are limited 2,400 per day, or 100/hour. This means if you’re app could potentially use the POST apis more than 100 per hour, you need to build in some limiting logic in your app so you don’t exceed this threshold.

The rate limits for the /GET REST apis are here, although for my application I’m not relying heavily on GETs, the majority of the calls are POSTS:

https://dev.twitter.com/rest/public/rate-limits

Twitter’s api prevents you from posting duplicate Tweets (see here), although they don’t publish how much time needs to elapse before an identical post is no longer consider a duplicate (see here). This wasn’t something I was planning on handling, but given the repetitive nature of some packet transmissions, for example BEACON packets, and packets sent for ID, this has to be a necessary feature of my app, otherwise in the worst case it would be attempting to tweet a stations BEACON packet every minute continuously.

To handle this I’m storing each Tweet sent, with additional tracking stats, like time last Tweet sent. Using this time stamp I can then calculate the elapsed time between now and the time last sent to make sure enough time has elapsed before I attempt to Tweet the packet again.

This is still a work in progress and there’s still some tweeking to do on the duplicate post detection and rate limiting, but while testing you can see the Tweets sent from my Twitter account @KK6DCT_Packet.

Here’s an example of the packets currently being Tweeted:

Calling Twitter REST api from JavaScript with OAUTH

I’ve started on a project where I need to call Twitter’s REST apis from a Node.js JavaScript app. I’ve built a Java app before that integrated with Twitter, but used a library to help with the OAUTH authentication. Looking around for a JavaScript library, it looks like node-oauth does what I need to do, so gave it a go.

Twitter’s API docs are pretty good, but I ran into an issue with node-oauth with an error coming back from:

POST /statuses/update.json

which returned this message:

{ statusCode: 401,
 data: '{"errors":[{"code":32,"message":"Could not authenticate you."}]}' }

which is odd because using the node-oauth library to authenticate and then call any of the GET apis with node-oauth was working fine. If you Google this error there’s numerous posts about this error for all number of reasons, so I’m not sure it’s a particularly specific message.

Here’s a working example for a GET:

First, use node-oauth to authenticate with your Twitter key, secret, and app access token and secret (which you can set up here):

var oauth = new OAuth.OAuth(
    'https://api.twitter.com/oauth/request_token',
    'https://api.twitter.com/oauth/access_token',
    config.twitterConsumerKey,
    config.twitterSecretKey,
    '1.0A',
    null,
    'HMAC-SHA1'
);

Next, using the returned value from this call, make the GET request (it builds the request including the OAUTH headers for you):

//GET /search/tweets.json
oauth.get(
    'https://api.twitter.com/1.1/search/tweets.json?q=%40twitterapi',
    config.accessToken,
    config.accessTokenSecret,
    function (e, data, res){
        if (e) console.error(e);
        console.log(data);
    });

Attempting a POST to update the status for this account using the similar api:

var status = "{'status':'test 3 from nodejs'}";

oauth.post('https://api.twitter.com/1.1/statuses/update.json',
    config.accessToken,
    config.accessTokenSecret,
    status,
    function(error, data) {
        console.log('\nPOST status:\n');
        console.log(error || data);
});

And this is the call that returned the error about “could not authenticate”.

Looking through a few other tickets for the node-oauth project, this one gave a clue – this particular issue was about special chars in the body content to the POST, but it gave an example of the body formed like this:

var status = ({'status':'test from nodejs'});

I would have thought passing a String would have worked, but I guess the api is expecting an object? Anyway, this is working, and looks good so far.