web analytics

My Winter Vacation (what I did with IoT and ARTIK-5)

I don’t know about you, or what you did with your winter vacation (or if you even got one, and if you didn’t, I’m sorry) but one of the fun things I did with mine was to spend a little time with my Samsung ARTIK Dev Kit. If you read the Hardware Extravaganza Post, you’ll know that I got an ARTIK-0 and an ARTIK-5 developer kit not long ago. I’ve been up to my ears in MyNewt though and haven’t had time to do much with them, sadly. That is, until my winter break came along.

I didn’t want to spend the whole time playing in my office and annoy my family, so I decided to just try a quick project using some existing sensor hardware I have lying around. (Note: I have a vast amount of sensor hardware “just lying around”) I decided to try using the eTape Liquid Level Sensor that I’ve already been playing with for the MyNewt project. It’s a fairly simple Analog sensor for reading the water/liquid level in a container. Or, in my case, on my back patio which regularly floods! I also decided to pull out the ARTIK-5 first since it’s extremely easy to get going.

We’re going to use the sensor as a resistive sensor, and the setup is very simple. I’ll be using a breadboard to put this all together for illustrative purposes. First, attach a jumper-wire from 5v on the board to the breadboard.Next, attach a jumper wire from ADC0 on the board to the breadboard. This will be our ADC-in. The sensor should have come with a 560 ohm resistor, so plug that into the board between Vdd and ADC-in holes. Finally, attach a jumper from GND on the board to your breadboard. At this point, your ARTIK 5 should look like this:

ARTIK-5 ADC Sensor Wiring

 

And your breadboard should look like this:

Breadboard wiring

 

Now attach one of the middle 2 leads from the sensor to ground on the breadboad and the other middle lead to the ADC-in on the breadboard. That should complete the sensor hookup and your completed breadboard should look like the above.

I bought a 1000 ML graduated cylinder in which to put the eTape sensor for testing this project, and here’s what the final hookup of the sensor itself looks like:

eTape Sensor in cylinder

 

Now all I have to do is fill it with water and … oh, wait, I probably have to write some code, huh? Actually, it turns out I have to do surprisingly little of that! I decided to give the Node-Red a spin since I’ve been writing a lot of Node.js code this year anyway. I got my ARTIK-5 up and running using the Resin.io site which was really fast and easy to use. Once that was done, and I had a fully operational ARTIK 5 (Note: don’t use the slim profile, make sure you use the latest profile in your Docker setup. You’ll need it for installing Node-Red), I simply installed Node-Red using

# sudo npm install -g node-red

Once that completed, I installed the ARTIK library for Node-Red

# /root/.node-red
# npm install node-red-contrib-artik

Then, just to make things even easier, I installed the FRED module:

# npm install node-red-contrib-fred

You’ll see why FRED was a good idea in a minute. Once that was all done on the ARTIK 5 I simply started node-red:

# node-red

And then connected my browser to the ARTIK-5 Node-Red server and built an app. I dragged in an ARTIK ADC and configured it:

Node-RED ARTIK Sensors

ARTIK-5 Node-Red ADC

 

 

a Function

Node-red function definition

 

and a JSON module, and then hooked it all up to a FRED-input and a FRED-output:

ARTIK-5 Node-Red app

 

Oh, and then clicked the ‘Deploy’ button. Told you it was simple.

I then went over to my FRED service account at sensitec and logged in. I created a private ADC endpoint:

Create End-point in FRED

 

And then added a send ADC event, triggered by a timestamp:

Send Event to ARTIK-5 in FRED

 

And a receive event that takes the returned data and inserts it into a chart:

ARTIK Event in FRED

 

 

Once I started the whole thing, I had a nifty chart showing the water level in my graduated cylinder:

Water Level Chart

 

And I wrote essentially zero code.

Next I’ll try installing a MongoDB backend on the ARTIK-5 and sending all the data to that, and then serving that data out to a javascript front-end to chart it all. That will require writing some code, so look for that in the near future!

Also I’ll work on having the actual sensor connected to the ARTIK-0 and sending the data from that to the ARTIK-5 MongoDB instance for collection and analysis. I’m really looking forward to digging in to the ARTIK-0 a bit since that’s more hands-on with C code — something I’ve been neck-deep in lately with MyNewt anyway.

Warning: Creating default object from empty value in /home/davidgs/public_html/davidgs_blog/wp-includes/comment-template.php on line 1056

Solving a Traveling Salesman Problem

It’s not IoT, but still … Here’s the background on this project, and why I undertook it.

For the past 3 years or so my wife and I have been volunteering with the blind in our community. Every month our church organizes a dinner for the blind in the area and we drive around and pick up participants, take them to the church where we serve everyone dinner, and the drive them all home. It’s great fun, and something both we, and the people we drive, thoroughly enjoy. It gives them a chance to get together with friends and share a meal, some music and a great evening.

Logistically, though, it’s a bit of a nightmare. Every month there is a call for volunteers to drive, amassing the list of people that want to come, and then the arduous task of figuring out routes for everyone that minimizes travel time and maximizes efficiency. For the first few years this process was fairly opaque. Each month we would volunteer to drive, and then a week before the event we’d get an email with who we would pick up and their addresses, etc. Behind the scenes, however, one volunteer was spending hours mapping out the routes and assigning passengers to drivers in what was hoped would be an efficient manner. It wasn’t always.

This is exactly the kind of problem computers were designed to solve! So I volunteered to solve it once and for all. Ok, so computers can’t solve the problem, but a well-designed computer program could. I just had to write it.

The basic parameters are:

  • About 30 volunteer drivers, each with their own ‘restrictions’ on how far they’re willing to drive, how many passengers they can take, etc.
  • About 75 attendees. Some with dogs, some in wheelchairs, some with physical disabilities of various sorts, etc.
  • The drivers and attendees change every month — there are regulars, like us, but not everyone can come/drive every month

Clearly Google Maps was going to be part of the solution. Also, a backend database of some sort would be required to store the information about the drivers and attendees so we wouldn’t have to re-enter it every month. I had just completed a consulting project for StrongLoop applying their API creation and management framework to IoT, and it seemed a perfect solution to this problem as well. Here were the end requirements I set for myself:

  • Web based application that would run in any browser
  • Backing datastore for driver and attendee information
  • Easy and intuitive to use, since not everyone is technology-savvy
  • Automate as much of the process as possible
  • Optimize the routes for the drivers
  • Provide the drivers with a google map with their optimized route and turn-by-turn directions

Seemed simple enough. I already knew how to geolocate things on a google map via the google maps API. I had (newly acquired) knowledge of using JavaScript and Node.js and loopback and MongoDB — and connecting them all together — to manage the data and the APIs. But how to actually build it? I mean, how to present the data and the interface in a simple UI that anyone could figure out.

Here’s where I ended up. After this, I’ll briefly go through how I did it. I’ll walk through the work-flow a bit too. We start here, with a blank page, a Google Map, and some empty tables.

Safari034

You can click on “Add Driver” and add a new driver to the Database. You get the same form if you click “Add Attendee”. All Drivers and Attendees are persisted in a MongoDB database.

Safari035

There is a Drop-down list of all the drivers in the database, so you just have to select the ones that are driving this month:

Safari036

Once you select a Driver, they end up in the Drivers Table, with their own ‘mini-map’. A Blue Pin is also added to the main map. As you add more drivers, you’ll see more and more Blue Pins for drivers on the main map.

Safari037

Next you select Attendees from the Attendees Drop Down list.

Safari038

As you add Attendees they are added to the Attendees Table, and a Red Pin is added to the Main Map. As you select more and more Attendees, you’ll see more and more Red Pins on the Main Map.

Safari039

When you click on an Attendee’s pin, you get a pop-up with their information (name, address, phone number) and another pull-down list that contains all the drivers available. Just select a Driver for that Attendee. You may notice a potential problem here. What if I add more drivers to the map later? Will they show up in the pull downs of the attendees? Of course they will! I simply added a JavaScript onmousedown() handler to the <select> for the driver’s list, and in there I walk the Table of Drivers to build the Select List:

for (var i = 1, row; row = dTable.rows[i]; i++) {
    //iterate through rows
    //rows would be accessed using the "row" variable assigned in the for loop
    for (var j = 0, col; col = row.cells[j]; j++) {
        if(j == 0){
            id = col.childNodes[0].value;
        }
        if(j == 1){
            selContent += "<option value=\'" + id + ":" + popup.split('-').pop() + "\'>" + col.innerHTML + "<\/option>";
            sel.innerHTML = selContent;
        }
    } 
 }

It is a little more complicated than you might think is necessary because I reference everything by the id from the MongoDB database so that I can look it up later more easily. I don’t keep track of the Driver’s address, phone number, etc. from the tables because a lookup by id is very fast, so as long as I have the id handy, I can get any other information quickly.

Safari040

Once you assign a Driver to an Attendee, their Red Pin is moved from the Main Map to the Driver’s mini-map on which you can Show/Hide the actual driving route. Yes, it’s small, and hard to see the actual route. Also, the Attendee’s entry in the Attendee table is turned green and a Driver Name is filled in for them. This is so that it is easy to tell when everyone has a driver and you’re done) No more red pins on the main map and all the Attendees are green.

Safari041

So what’s missing?

Well, you see the ‘Send’ button, which, in an ideal world, would gather all the information about each Attendee and send an email to the driver with all that information, etc. But this isn’t an ideal world, and using JavaScript in a browser, you can’t really do all that. Instead you get a pop-up window with a nicely formatted email message, complete with the list of the Attendees and all their information as well as a link to a google map with turn-by-turn directions. All you have to do it copy the whole text, close the dialog box, click on the driver’s email link, paste in the text and send. I wish there were a better way, but a) I don’t want to do any server-side code to send the email and b) it’s not possible to send a fully formatted (either HTML or RTF) from a ‘mailto’ link, so I’m stuck with this.

So how is this implemented? It’s all in JavaScript! I used StrongLoop, as I said, to build the Node.js/Loopback framework which gave me all the ReST APIs I needed into the MongoDB backend, plus the Node.js server to serve it all up. That part is incredibly powerful, actually. If you’re trying to put REST APIs onto your database I highly recommend giving StrongLoop a whirl. Especially the ARC where you can use a browser to design your data models, etc. As I said earlier, I really only keep the database ID in the browser. So everything — and I do mean everything — is referenced by that ID. How does that work? Well, let’s take the example of adding an Attendee to a Driver’s list of passengers. I have a function that is called when you select a driver from the drop-down list (remember we talked about building that list on the fly earlier). Once a Driver is selected, we have to add that Attendee to that Driver’s list. So selecting a driver calls the driverSelected() function with a tuple of the driver’s ID and the Attendee’s ID. Here’s how that works:

// everything is referenced by ID!
var selRow = document.getElementById(ids[1]);
selRow.style.background=routed; // set Attendees background green
var driverCell = document.getElementById(ids[1]).cells[3];
var url = dbServerURL + "Attendees/" + ids[1];
jQuery.getJSON(url, function(data) { // look up the Attendee's info in the DB
    var tbl = document.getElementById("pList-" + ids[0] + "-Table");
    var row = tbl.insertRow(-1);
    row.id = data.id; // everything referenced by ID
    var cell = row.insertCell(0);
    cell.innerHTML = "• " + data.Name;
    driverCell.innerHTML = driverName;
    cell = row.insertCell(1);
    cell.innerHTML = "<button id=\"" + data.id + "\" onclick=\"clearCell(this.id, this.value)\" value=\"" + ids[0] + "\" name=\"Remove\">Remove<\/button>"
    for(var x = 0; x < driverList.length; x++){
        if(driverList[x].id == ids[0]){
            addToMap(data.id, "Attendees", driverList[x].map); // add the the Driver's map
            break;
        }
    }
});

As you can see, I really do use the ID for everything. I insert elements into the DOM using the ID. Each Driver gets a Table, and in that table is another table of Attendees for that driver, and it’s named pList-ID-Table so it’s easy to find. And alter. I keep a list of the maps for each driver, again referenced by the Driver’s ID, so that I can add pins to it (or remove pins from it). The entire application is about 1,000 lines of JavaScript in the browser to properly fetch and display and manipulate all the data from the backend. But thanks to loopback, I could make very fast queries to the database and get back easily manipulated JSON objects to work with. To make this application easy to move from server to server, I simply added an initialization variable in the browser code to set the server:

var dbServerURL= "http://" + location.host + "/api/";

To look up Attendee data, I just append the Attendees database name to the end, and to look up Drivers data, I append the Drivers database name to the end. To look up a specific driver, I just append the driver’s ID to the end of that.

var url = dbServerURL + "Drivers/" + id
jQuery.getJSON(url, function(data){ ... }

And I get back a nice JSON object with all the Driver’s information in it. Extracting information from JSON is dead-simple, of course, using something along the lines of:

var id = data.id;
var driverName = data.Name;

etc. It’s really that simple.

It turns out that hosting Node.js apps is harder than one would think. I tried for days to get it running on OpenShift, but to no avail. The documentation from StrongLoop on how to do that is both old and incomplete and I so far have not figured out how to make it work. The docs from OpenShift simply don’t work. What I finally found was a simple, free way to deploy this on AWS. Pretty straight forward, and when I have time, I can write up how to do that as well.

I’ve sent the basic instructions and address to the coordinator who handles the routing and she has now successfully done the routing for a couple of dinners. Her comment to me was “that sure is a lot easier and faster than the way I used to do it!” The whole thing is wrapped in bootstrap code, so in theory it should also be usable from a mobile device, but in my tests on an iPhone, it tends not to do so well with the maps, making it not very useful.