Creating a new AWS Lambda using the AWS CLI

It’s pretty easy to set up and configure a new AWS Lambda with the AWS Console, but if you’re iterating on some changes and need to redeploy a few times, the AWS CLI makes it pretty easy.

To create a new Lambda, assuming you have a .zip packaged up and ready to go:

aws lambda create-function --function-name example-lambda --zip-file fileb://example-lambda.zip --handler index.handler --runtime nodejs8.10 --role arn:aws:iam::role-id-here:role/lambda-role

AWS IoT and Node.js on the Raspberry Pi

There are many approaches for installing node.js on the Raspberry Pi (Google and you’ll find lots of guides), presumably because for a while there didn’t seem to be any official binaries in the official apt repos so people were building and sharing their own.

I installed a version from somewhere (can’t actually remember where as it was a while back) and it doesn’t support ES6 class syntax used by some of the dependent libraries in the AWS IoT SDK:

$ node index.js
/home/pi/aws-iot-nodejs-pi-lights/node_modules/aws-iot-device-sdk/node_modules/mqtt/node_modules/websocket-stream/server.js:6
class Server extends WebSocketServer{
^^^^^
SyntaxError: Unexpected reserved word
    at Module._compile (module.js:439:25)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object.<anonymous> (/home/pi/aws-iot-nodejs-pi-lights/node_modules/aws-iot-device-sdk/node_modules/mqtt/node_modules/websocket-stream/index.js:2:14)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)

The version I currently have installed is:

pi@raspberrypi:~ $ node -v
v0.10.29

Since I’m not sure where this version came from originally, (and apt-get upgrade is not finding any updates), I uninstalled:

sudo apt-get remove nodejs
sudo apt-get remove npm

Then I followed the steps in the AWS IoT SDK guide here to install using the version provided from Adafruit’s repo  (official node.js binaries for ARM are also available from nodejs.org here).

With version provided from Adafruit, this gives v 0.12.6 but unfortunately this still gives the same error with the ES6 class keyword.

$ node -v
v0.12.6

Next, lets try the ARM version from nodejs.org. There’s step by step instructions here showing how to download the tar, extract and copy to /usr/local/

Now we have:

$ node -v
v8.9.1

And now trying to run my AWS IoT node.js based app, success!

 

 

Building an Amateur Radio Packet to Twitter bridge: Part 3 – preventing duplicate tweets

In my last post (part 2, also see part 1 here), I talked about Twitter’s API rate limits. Since many Packet Radio transmissions are duplicates by their nature, for example, beacon packets and ID packets, it’s important to have some kind of mechanism to prevent sending these through to Twitter.

The approach I used was to insert each received packet into a MongoDB database, storing the received packet data, who the packet was from and who to, and additional metadata about the packet, for example, when last sent, and when it was last received.

Here’s an example of what each document stored looks like:

{
 "_id" : ObjectId("5909828e5a2f130fc8039882"),
 "firstHeard" : ISODate("2017-05-03T07:11:10.051Z"),
 "from" : "AE6OR ",
 "heardTimes" : 1,
 "infoString" : "Š¤¤@à–¤ˆŽ@@à–„Š¤¤@ஞžˆ²@`–„Š¨@`¨‚žŠ@a\u0003ðHello from 5W Garage packet node AUBURN 73's Steli !\r",
 "lastHeard" : ISODate("2017-05-03T07:11:10.051Z"),
 "lastTweet" : ISODate("2017-05-03T07:11:10.051Z"),
 "to" : "BEACON",
 "tweet" : "Received station: AE6OR  sending to: BEACON : Š¤¤@à–¤ˆŽ@@à–„Š¤¤@ஞžˆ²@`–„Š¨@`¨‚žŠ@a\u0003ðHello from 5W Garage packet node AUBURN 73's Steli !\r"
}

My current logic to check for duplicates and record when a tweet is last sent is:

    1. search for a matching document (tweet details) with a $lt condition that lastTweet is before ‘now – 12 hours’:
      document.lastTweet = {'$lt' : moment().utc().subtract(12, 'hours').toDate() };
    2. This is executed as a findOne() query:
      db.collection('tweets').findOne(document).then(function (olderResult) {
         ...
      }
    3. If an existing document older than 12 hours is found, then update properties to record that this same packet was seen now, and the time is was resent was also now (we’ll resend it to the Twitter api after the db updates):
      if (olderResult != null) {
          sendTweet = true;
          updateProperties = {
              lastHeard: now,
              lastTweet: now
          };
      }
      else {
          updateProperties = {
              lastHeard: now
          };
      }

      If not older than 12 hours, set properties to be updated to indicate just the lastHeard property

    4. To either update the existing document or insert a new document if this was the first time this packet was heard, do an ‘upsert’:
      db.collection('tweets').update(
          document,
          {
              $set: updateProperties,
              $inc: {heardTimes: 1},
              $setOnInsert: {
                  firstHeard: now,
                  lastTweet: now
              }
          },
          {upsert: true}
      ).then(function (response) {
      ...
      }
    5. Depending on the result indicating if we inserted or updated, set a property so on return we know whether to send a new Tweet or not:
      if(response.upserted != null || sendTweet) {
          response.sendTweet = true;
      }
      else{
          response.sendTweet = false;
      }

The approach is not yet completely foolproof, but it is stopping the majority of duplicate Tweets sent to Twitter so far.

For the full source check the project on github here: https://github.com/kevinhooke/PacketRadioToTwitter .

angular-seed and node.js http-server for local development

Angular-seed is a skeleton AngularJS project with a recommended folder structure and configuration including all the recommended development tools, jasmine and karma for unit tests, Protractor for end-to-end tests, and node.js for your dev server. Check out the project here.

If you’ve already installed node.js then you may notice in the readme for angular-seed it mentions that they have configured a test webserver using node, but you can also install this as a global module and use it elsewhere. This is a useful and quick way to spin up a test server in a given directory to support development testing. Install the server globally with:

sudo npm install -g http-server

and then start it up in a directory that you want to be the root, with:

http-server