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:

Updating/installing node.js on the Raspberry Pi

The latest versions of Raspbian (e.g. Jessie) come with an older version of node.js preinstalled. If you search around for how to install node.js on the Pi you’ll find a number of different approaches, as it seems there’s not an official ARM compiled version of the latest releases in the Debian repos.

This approach provided by this project has later versions compiled for ARM. Follow the instructions on their site to download and install from the .deb file.

Before you start, if you already have an older version installed (check ‘node -v’), uninstall it first. The version I had on my fresh Jessie install was from nodejs-legacy, so ‘sudo apt-get remove nodejs-legacy’ did the trick.

Amateur Radio homebrew: Raspberry Pi + Packet Radio + social networking integration

I’m putting something together for our River City Amateur Radio Comms Society homebrew show n tell later this year. Here’s my ingredients so far:

I’m thinking of building a bridge between Amateur Radio Packet and social networking, like Twitter.

So far I’ve roughed out node.js to Twitter integration using node-oauth, and I I’ve put together a simple prototype using the node-ax25 library to connect to the KISS virtual TNC on Direwolf. It receives packets and writes callsigns and messages to the console.

Right now I’m testing this on a PC running Debian, with a Rigblaster Plug n Play connected to an Icom 880h. Later when my TNC-Pi arrives I’ll migrate this to the Pi.

So far using the node-ax25 library looks pretty easy. Here’s some code so far to dump received callsigns to the console:

var ax25 = require("ax25");

var tnc = new ax25.kissTNC(
    {   serialPort : "/dev/pts/1",
        baudRate : 9600
    }
);

tnc.on("frame",
    function(frame) {
        //console.log("Received AX.25 frame: " + frame);
        var packet = new ax25.Packet({ 'frame' : frame });
        console.log(new Date() + "From "
            + formatCallsign(packet.sourceCallsign, packet.sourceSSID)
            + " to "
            + formatCallsign(packet.destinationCallsign, packet.destinationSSID));

        if(packet.infoString !=""){
            console.log(">  " + packet.infoString);
        }
    }
);

/**
 * Formats a callsign optionally including the ssid if present
 */
function formatCallsign(callsign, ssid){
    var formattedCallsign = "";
    if(ssid == "" || ssid == "0"){
         formattedCallsign = callsign;
    }
    else{
        formattedCallsign = callsign + "-" + ssid;
    }

   return formattedCallsign;
}

The output for  received messages so far looks like this:

Wed Apr 19 2017 23:10:00 GMT-0700 (PDT)From KBERR  to KJ6NKR

Wed Apr 19 2017 23:12:05 GMT-0700 (PDT)From AE6OR  to BEACON

>  Š¤¤@à–¤ˆŽ@@`–„Š¤¤@`®žžˆ²@`–„Š¨@`¨‚žŠ@aðHello from 5W Garage packet node AUBURN 73's Steli !

Wed Apr 19 2017 23:12:08 GMT-0700 (PDT)From AE6OR  to BEACON

>  Š¤¤@à–¤ˆŽ@@à–„Š¤¤@ஞžˆ²@`–„Š¨@`¨‚žŠ@aðHello from 5W Garage packet node AUBURN 73's Steli !

Wed Apr 19 2017 23:16:49 GMT-0700 (PDT)From K6JAC -6 to ID    

>  K6JAC-6/R BBOX/B KBERR/N

Wed Apr 19 2017 23:19:31 GMT-0700 (PDT)From K6WLS -4 to ID    

>  Network Node (KWDLD)

Wed Apr 19 2017 23:19:50 GMT-0700 (PDT)From NM3S   to BEACON

>  Mike in South Sac.  Please feel free to leave a message. 73's

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.