Easy Code Share > Cordova > How MQTT Plus Cordova GPS APP Track My Family

How MQTT Plus Cordova GPS APP Track My Family


Cordova APPs using MQTT can share data with each other. Moreover, shared Geo locations and GPS positions can track your family and friends. This example use Google Maps to mark where your family and friends are.

More topics about Cordova Plugin Geolocation getting latitude and longitude, objected programming upon WebSQL async API, and MQTT javaScript client programming are introduced.

All codes here are not complicated, so you can easily understand even though you are still students in school. To benefit your learning, we will provide you download link to a zip file thus you can get all source codes for future usage.

Estimated reading time: 9 minutes

 

 

BONUS
Source Code Download

We have released it under the MIT license, so feel free to use it in your own project or your school homework.

 

Download Guideline

  • Prepare HTTP server such as XAMPP or WAMP in your windows environment.
  • Download and unzip into a folder that http server can access.
 DOWNLOAD SOURCE

 

SECTION 1
GPS Track Family

Finding where your family are is a popular topic around GPS tracking. We use MQTT protocol in the example based on referring to all mobile phones as IoT devices.

 

IoT on Free MQTT Broker

For IoT to operate, you need a MQTT server. We recommend a free MQTT host for beginners to develop as mentioned in our previous post.

 

Grouping by MQTT Topics

MQTT topics are of multiple-level representation. That feature allows us to group your family by specifying a group topic. For example, if you subscribe or publish to MQTT topic geotrack/bighouse/#, it means a given family name of bighouse denotes your family, and anyone publishing information to topics such as geotrack/bighouse/john will be classified into the given family.

In addition, family members publish individual GPS positions periodically for others to track, and always receive positions from all family.

Cordova GPS Track Family

 

Storing Local Data in WEBSQL

Exactly, what mobile phones publish are phone-owner name(userid), GPS latitude, GPS longitude, and timestamp.

When MQTT subscribers get messages arrived, WEBSQL saves them locally as permanent data, however, which will be still removed if coordinates timeout expired.

 

Geo Location and Google Maps

But how to get and share accurate GPS positions to track family? You can find the article Cordova Geolocation Plugin and Google Maps which tells you how to make Geo information visual on maps.

Distinguished Markers on Google Maps

 

SECTION 2
MQTT Share Positions

Exchanging GPS data through MQTT protocol can track family and friends as well. MQTT hierarchical topics help us for categories.

 

Connect and Re-Connect

Before exchange MQTT data, clients should connect to MQTT broker. The free MQTT broker used here is test.mosquitto.org with secure port 8081 for encrypted MQTT over Websockets.

For high availability, issues for link lost and recovered should be considered. In Javascript codes, setTimeout() repeatedly checks flags such as mqttConnected to determine whether connecting tries begin or not.

index.html
<script src="js/paho-mqtt.js"></script>
.....
function retryMQTT() {
    if ( dbLocal.getItem("group-name") != "" && dbLocal.getItem("your-name") !="" && mqttConnected == false ) {
        console.log("attempting to connect...")
        client.connect({onSuccess:onConnect, useSSL: true});
    }
    setTimeout(retryMQTT, 30000); // milliseconds
}

 

Subscribe and Publish If Connected

If connected, the mobile phone immediately subscribes the topic geotrack/group-name/#. We always convert topic string into lowercase to prevent from conflicts.

index.html
function onConnect() {
    // Once a connection has been made, make a subscription and send a message.
    mqttConnected = true;
    console.log("onConnect");
    t = topic_top+"/"+dbLocal.getItem("group-name")+"/#";
    t = t.toLowerCase();
    client.subscribe(t);
    console.log("subscribed topic: " + t);
    repeatPublish();
}

Publishing GPS locations to track your family should be a repeating action, because latitude and longitude could be changing. Another data item timestamp represents the time when last coordinate reports. If there is no reports during 3 hours for a mobile phone, its existing coordinate becomes invalid as the project designs.

index.html
function repeatPublish() {
    setTimeout(repeatPublish, 30000); // milliseconds
    if ( dbLocal.getItem("group-name") == "" || dbLocal.getItem("your-name") == "" ) return;
    t = topic_top+"/"+dbLocal.getItem("group-name")+"/"+dbLocal.getItem("your-name");
    t = t.toLowerCase();
    timestamp = getTimeStamp();
    pos = { userid: dbLocal.getItem("your-name"), lat: latitude, lon: longitude, timestamp: timestamp };
    client.publish(t, JSON.stringify(pos), 1, true); // retained message is true
    publish_cnt++;
    console.log("Sending message: "+publish_cnt+"  topic:"+t);
}

 

Messages Arrived on Subscribers

The APP always sends self positions and receives all. When a message arrived, the APP updates database or inserts a new record if not existed. In Section 4, More details about WEBSQL operations are written.

index.js
function onMessageArrived(message) {
    console.log("onMessageArrived: "+message.payloadString);
    console.log("your name: " + dbLocal.getItem("your-name"));
    gObj = JSON.parse(message.payloadString);
    sql="SELECT * FROM trackgroup WHERE userid=?";
    dbInst.execute(sql, [ gObj.userid ], onSelectSuccess);
}

 

SECTION 3
Cordova Geo Plugin

This Plugin provides an interface for Cordova and GPS components to communicate with each other and bindings to standard device APIs. Thus, you can control devices by JavaScript.

 

Cordova Plugin for GPS

Cordova Geolocation Plugin read GPS chip on mobile phones to report latitude and longitude, and even altitude and speed if objects are moving.

 

Start Getting Geo on Device Ready

On device ready, Cordova APP tries to get GPS coordinates per 60 seconds so as to track movements of your family. If networking status is available to successfully locate new positions, Cordova saves new GPS latitude and longitude as global variables for other modules to use.

index.js
function onDeviceReady() {
    console.log('Running cordova-' + cordova.platformId + '@' + cordova.version);
    getCoordinates();
}
function getCoordinates() {
    navigator.geolocation.getCurrentPosition(onSuccess, onError);
    setTimeout(getCoordinates, 60000); // milliseconds
}
var onSuccess = function(pos) {
    // Update global variables
    latitude = pos.coords.latitude;
    longitude = pos.coords.longitude;
    console.log('Latitude: '+ pos.coords.latitude + ' ' +
                'Longitude: '+ pos.coords.longitude);
};

 

SECTION 4
WEBSQL Storage

For small storage, WEBSQL is enough. To overcome its async API features, we give the object-oriented approach to save half time for you.

 

Using Database Class for WEBSQL

Here is WEBSQL class in JavaScript. You can derive objects from it to be database instances. Include the JavaScript file dbclass.js to start this database class.

index.html
<script src="js/dbclass.js"></script>
.....
<script>
var dbInst, dbLocal, client;
$(document).ready(function() {
    dbInst = new dbClass("trackgroup_db", "Geo Track", InitDB);
    dbLocal = window.localStorage;
    if(dbLocal.getItem("group-name") == null) dbLocal.setItem("group-name", "")
    if(dbLocal.getItem("your-name") == null) dbLocal.setItem("your-name", "")
    $("#group-name").val( dbLocal.getItem("group-name") );
    $("#your-name").val( dbLocal.getItem("your-name") );
    // Create a client instance
    client = new Paho.Client(mqtt.hostname, Number(mqtt.port),
                             "client-id-"+dbLocal.getItem("your-name"));
    // set callback handlers
    client.onConnectionLost = onConnectionLost;
    client.onMessageArrived = onMessageArrived;
    // try to connect
    retryMQTT();
    gMap();
});
</script>

When database instance is created, callback function InitDB() create a table if not existed.

index.js
function InitDB() {
    sql="CREATE TABLE IF NOT EXISTS trackgroup (userid, lat REAL, lon REAL, self, timestamp INTEGER, UNIQUE(userid))";
    dbInst.execute(sql);
    removeExpired();
}

 

Update Records or Insert New

When a MQTT message arrived, update latitude, longitude, and timstamp for existing members, or insert a new record if a new member comes.

index.js
function onSelectSuccess(rows, n, rowsAffected) {
    if(n == 0) {
        // insert
        sql="INSERT INTO trackgroup (userid, lat, lon, self, timestamp) VALUES (?, ?, ?, ?, ?)";
        if(gObj.userid == dbLocal.getItem("your-name")) self_flag = 1; else self_flag = 0;
        dbInst.execute(sql, [ gObj.userid, gObj.lat, gObj.lon, self_flag, gObj.timestamp ], refreshAll);
    } else {
        // update
        sql="UPDATE trackgroup SET lat=?, lon=?, timestamp=? WHERE userid=?";
        dbInst.execute(sql, [ gObj.lat, gObj.lon, gObj.timestamp, gObj.userid ], refreshAll);
    }
}

 

Refresh TimeStamps

Each time database operations for messages arrived are complete, the APP refreshes timestamps. If timestamps are not up to date, it means your family has not reported locations for long time. Thus, the coordinates could be not correct.

index.js
function refreshAll() {
    sql="SELECT * FROM trackgroup";
    dbInst.execute(sql, [], refreshData);
}
function refreshData(rows, n, rowsAffected) {
    html = "";
    for(var i=0; i<n; i++) {
        console.log(rows[i].userid + " / " + rows[i].lat + " / " + rows[i].lon + " / " + rows[i].self + " / " + rows[i].timestamp );
        html += "<tr><td width='50%'>"+rows[i].userid+"</td>";
        html += "<td width='20%'>"+convertTimeStamp(rows[i].timestamp)+"</td></tr>";
    }
    // List group people
    $("#listview").html(html);
    .....
}

 

SECTION 5
Google Maps Markers

The last steps are putting markers on Google Maps to indicate Geographic locations. Moreover, centering view point on maps allows you always be focused.

 

Create a Google Map

On document ready, the APP creates a Google Map with API key YOUR_KEY. The callback function centers the view point upon your coordinates.

index.html
$(document).ready(function() {
    .....
    gMap();
});
index.js
function gMap() {
    $.getScript("https://maps.googleapis.com/maps/api/js?key="+YOUR_KEY+"&callback=gMapCallback");
}
function gMapCallback() {
	center = new google.maps.LatLng(latitude, longitude);
	config = {center: center, zoom: 10,};
	theMap = new google.maps.Map(document.getElementById("googleMap"), config);
	console.log( "Map Created" );
	refreshAll()
}

 

Refresh GPS Positions

Draw all markers on Google Maps again to refresh new status. This function theMap.setCenter() continuously focus your self location on center position by moving maps.

index.js
function refreshData(rows, n, rowsAffected) {
    .....
    // Remove all markers on Google Maps
    for (var i = 0; i < markers.length; i++ ) {
        markers[i].setMap(null);
    }
    markers.length = 0;
    // Add all markers on Google Maps
    for(var i=0; i<n; i++) {
        center = new google.maps.LatLng(rows[i].lat, rows[i].lon);
        if(rows[i].self == 1)
            url_png = "img/red-dot.png";
        else
            url_png = "img/purple-dot.png"
        marker = new google.maps.Marker({
            position: center, icon: url_png,
            label: { text: rows[i].userid, color: "white", fontSize:"20px" }
            });
        marker.setMap(theMap);
        if(rows[i].self == 1) theMap.setCenter(marker.getPosition());
        markers.push(marker);
    }
}

 

FINAL
Conclusion

In short, we list building steps as below. If you are new to Cordova, follow Cordova building process for practices.

Thank you for reading, and we have suggested more helpful articles here. If you want to share anything, please feel free to comment below. Good luck and happy coding!

 

Brief Cordova Building Steps

Cordova CLI command lines fulfill the building process.

c:\>cordova create geotrack com.easycodeshare.geotrack GeoTrack
c:\>cd geotrack
c:\geotrack>cordova platform add android
c:\geotrack>cordova plugin add cordova-plugin-geolocation

Replace content of the folder geotrack/www with all downloaded source codes, and then issue the final command to build an APP.

c:\geotrack>cordova build android
Checking Java JDK and Android SDK versions
ANDROID_SDK_ROOT=undefined (recommended setting)
ANDROID_HOME=undefined (DEPRECATED)
Using Android SDK: C:\Users\user\AppData\Local\Android\sdk
Subproject Path: CordovaLib
Subproject Path: app
Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.5/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 2s
40 actionable tasks: 40 up-to-date
Built the following apk(s):
        c:\geotrack\platforms\android\app\build\outputs\apk\debug\app-debug.apk

 

Learning Tips

Let us suggest a excellent way to learn HTML scripts here. Using Google Chrome F12 Inspect or Inspect Element will help you study the codes.

In Google Chrome, there are two ways to inspect a web page using the browser built-in Chrome DevTools:

  • Right-click an element on the page or in a blank area, then select Inspect.
  • Go to the Chrome menu, then select More Tools > Developer Tools.

 

Suggested Reading

 

TRY IT
Quick Experience

That is all for this project, and here is the link that let you experience the program. Please kindly leave your comments for our enhancement.

 

Try It Yourself

Click here to execute the source code, thus before studying the downloaded codes, you can check whether it is worthy.

Leave a Comment