Building a Smart Boat

Last year, we bought a boat. She’s old, and she’s slow, but she floats and sails and that’s pretty cool. There’s not much to ole Mariah, but the guy that sold her to us included a solar panel to charge cell phones and power a small lamp, and that idea of owning something and making it your own to solve a problem put a little tickle in the back of my head. I knew that I wanted to make this boat my own, but I wasn’t sure how.

I think most people would take an old boat and gut the interior, give her some fresh varnish, or do some other cosmetic project. Mariah needs all of that, but I wanted to do something that I hadn’t seen anyone else do before. I was going to give her a brain.

Building a Smart Boat: Location Services

The first thing a smart boat should do is let you know where it is.

Materials

Code

Architecture

The base architecture of the project is pretty simple.

  1. A daemon will run on the Raspberry Pi, which will collect data from the different sensors (GPS only at this time).
  2. The Pi will be registered as an AWS IoT device, and will send data to the IoT service on a given interval.
  3. Using the IoT Rules Engine, the data will be replicated to DynamoDB

Use GPS with Raspberry Pi

The first thing you’ll want to do (after basic Raspberry Pi installation) is to hook up the GPS board. You can find pretty good instructions on the Adafruit GPS guide

Before you begin- make sure that you solder the contacts to the GPS Breakout! The board won’t work otherwise.

Go ahead and follow the guide’s instructions to download the GPS daemon packages:

sudo apt-get install gpsd gpsd-clients python-gps

Once installed, you can start the daemon with

sudo gpsd /dev/ttyUSB0 -F /var/run/gpsd.sock

and test that you’ve got GPS fix with

cgps -s

Raspberry Pi GPS with NodeJS

I’m a big NodeJS fan, so I’ve written my application with JS. Luckily, someone’s already done the heavy lifting and has created node-gpsd.

Install the package in your working directory with:

npm install --save node-gpsd

Here’s how you configure a GPS Daemon/Listener in NodeJS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// app.js

const gpsd = require('node-gpsd');

const daemon = new gpsd.Daemon({
program: 'gpsd',
device: '/dev/ttyUSB0',
port: 2947,
pid: '/tmp/gpsd.pid',
readOnly: false,
logger: {
info: function() {},
warn: console.warn,
error: console.error
}
});

const listener = new gpsd.Listener({
port: 2947,
hostname: 'localhost',
logger: {
info: function() {},
warn: console.lwarn,
error: console.error
},
parse: true
});

daemon.start(() => {
console.log('GPS Daemon started');

listener.connect(() => {
console.log('GPS Listener connected');

listener.watch();

listener.on('TPV', (e) => {
console.log('event:', e);
});

});
});

There are two objects being used here:

GPS Daemon - The daemon is what is actually interacting with the device, and polling it for changes. These changes get published to a local port.

GPS Listener - The listener is subscribed to events on that port, and trigger JavaScript events. This allows us to react to these new events.

Test It Out

Run the GPS service with node app. You should start to see different events logged to the console. Congratulations!

AWS IoT with Raspberry Pi

Now that we’re pulling GPS data, we should put it somewhere. AWS IoT offers many different services that we can tap into.

Register an IoT Device

Navigate to the Onboard dashboard of the AWS IoT console and click ‘Get Started’. From here, follow the steps to download a package of certificates for your device. Copy the certs to your Raspberry Pi- I’ve got mine in my application folder (mariah/certs).

Next, we’ll add some code to connect to the IoT Cloud. Install the AWS IoT SDK for node:

npm install --save aws-iot-device-sdk

And change your app.js to look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// app.js

const config = require('./config.js');

const gpsd = require('node-gpsd');
const deviceModule = require('aws-iot-device-sdk').device;

const daemon = new gpsd.Daemon({
program: 'gpsd',
device: '/dev/ttyUSB0',
port: 2947,
pid: '/tmp/gpsd.pid',
readOnly: false,
logger: {
info: function() {},
warn: console.warn,
error: console.error
}
});

const listener = new gpsd.Listener({
port: 2947,
hostname: 'localhost',
logger: {
info: function() {},
warn: console.lwarn,
error: console.error
},
parse: true
});

const device = deviceModule({
keyPath: config.iot.keyPath,
certPath: config.iot.certPath,
caPath: config.iot.caPath,
region: config.aws.region,
host: config.iot.host
});

daemon.start(() => {
console.log('GPS Daemon started');

listener.connect(() => {
console.log('GPS Listener connected');

listener.watch();

listener.on('TPV', (e) => {
e.trip_id = 'trip_1';
console.log('event:', e);
device.publish('gps', JSON.stringify(e));
});
});
});

All I’ve done here is declare a ‘device’, which requires the location of the certs that we transferred over to the Pi earlier. Once declared, we can use it to publish to the cloud: that’s what this line is:

device.publish('gps', JSON.stringify(e));

where gps is a topic that we can act on once we get into the AWS IoT Rules Engine, and we’re publishing our JSON from the GPS module as a string.

Test it Out

To test that this is working, go to the Test tab of the AWS IoT console and subscribe to the gps topic.

Go back to your Pi, and run node app again. If everything is configured correctly, you should see data start to stream in.

Using the IoT Rules Engine

Data is flowing to the cloud like a firehose- now you need to put it somewhere. The AWS IoT Rules Engine allows you to use a SQL-like language to parse messages on the fly and act on them. Before we jump in though, we’re going to need somewhere to dump them.

Configure a DynamoDB Table

Configure a DynamoDB table to hold the data. Setup is simple:

  • Table name: mariah-gps
  • Partition key: trip_id String
  • Sort key: time String
  • Table settings: use default settings

Configuring IoT Rules Engine

Now, go back to the IoT Rules console and create a new rule.

  • Name: mariah_gps_rule
  • Message source:
    • Attribute: *
    • Topic filter: gps
    • Condition: blank
  • Actions:
    • Split message into multiple columns of a database
      • Table name: mariah-gps
      • Iam role name: Create a new role

Test it Out

Go back to your app and run it again with node app. Open up your DynamoDB table, and you should see it populated with data.

Next Steps

Now that you’ve got location data up into the Cloud, you’re free to do whatever you want with it. I’m writing a Lambda function to gather data by trip ID and mash it together into geoJSON- a format that will allow me to plot the trip out onto a map.