GPS Tracker Example - botletics/SIM7000-LTE-Shield GitHub Wiki

UPDATE (7/22/19): Please see the SIM7000_MQTT_Demo sketch for an example on how to implement the newly-added dedicated MQTT functions for the SIM7000. Tested on SIM7000A running 1351B03SIM7000A firmware and also on 1351B04SIM7000A firmware.

HTTPS NOTE (12/3/22): For more info on HTTPS commands, please check out this page

Intro

A great way to use the SIM7000 shield is for asset tracking. This can be used in many situations for things like fleet management (like seeing where pizza delivery vehicles are) and is a great way to test the GPS and remote capabilities of your device!

In this tutorial we'll be going over the IoT_Example sketch which you can find on Github. This example allows you to send GPS, temperature, and supply voltage data to the cloud with HTTP GET and POST requests as well as via MQTT. If you're only interested in sending to Adafruit IO via MQTT then please take a look at the AdafruitIO_MQTT_Demo example sketch.

Prerequisite

If you haven't already, please see the previous tutorials to get your shield set up with the LTE_Demo sketch and make sure it's connecting to the network and successfully sending data to the cloud using the "2" command!

Defining Transfer Protocol

Before we move on, let's briefly talk about the different methods of sending data. Currently there are three main methods of sending data to the cloud with the example sketch:

  • HTTP GET request
  • HTTP POST request
  • MQTT publish

The main differences between these methods is that HTTP GET puts all the info (for example, sensor data, device ID, etc.) all in the query string, whereas HTTP POST requests put the important stuff in a message body. Typically both of these types of HTTP requests allow sending data but are not well-suited for two-way communication. For more info about HTTP GET vs POST I'd recommend checking out this article.

MQTT is a slightly different animal; it's a much more "lightweight" protocol using less bandwidth and allows you to send data back and forth. Both of these advantages make it a great option for IoT devices!

The first thing you need to do in the IoT_Example sketch is to define which protocol you want by un-commenting out the line for the desired protocol and leaving the other ones commented out:

https://github.com/botletics/SIM7000-LTE-Shield/blob/master/Media/IoT%20Example%20Choose%20Protocol.PNG

Doing this is crucial because this sets which blocks of code will run in the program. Later when you upload the program, feel free to try each method! Note that there are two platforms used for MQTT: Adafruit IO (which I'll classify as proprietary) and CloudMQTT (which can be seamlessly expanded to most other non-proprietary MQTT protocols simply by changing the credentials)

The next thing you need to do is make sure the right APN is set in the setup() function. By default it is set for the Hologram global SIM card but if you're using a different SIM card please change the APN accordingly.

fona.setGPRSNetworkSettings(F("hologram")); // For Hologram developer SIM card

Sampling Rate

In the sketch you will also see a line that sets a variable called "samplingRate". This defines how often you want the GPS tracker to send data to the cloud. For example, if you set "samplingRate" to 10 (default), the device will post data to the cloud, pause for 10s, then post again, etc. Note that if you only want the device to post once until you push the button again (maybe you're afraid you'll burn too much data lol?) then you can simply comment out the "samplingRate" line altogether.

https://github.com/botletics/SIM7000-LTE-Shield/blob/master/Media/IoT%20Example%20Sampling%20Rate.PNG

Also notice that there's a "turnOffShield" variable which is actually commented out by default. This variable sets whether or not the SIM7000 turns off after posting data or remains completely on and active. Note that if you uncomment this line it will take a bit longer for it to get GPS location data than if it were left on. However, you might want to turn it off to save energy if your're not sampling very often and don't care about a little latency in readings.

HTTP Protocol

The default test cloud API used in the example sketch is dweet.io, a super easy-to-use and free API that allows you to test GET and POST methods.

GET Method

Using the GET method is really simple. All you have to do is reference the API documentation for whatever API you're using (in this case dweet.io) and plug in the values in the "sprintf" function:

https://github.com/botletics/SIM7000-LTE-Shield/blob/master/Media/IoT%20Example%20GET%20Request.PNG

Note that in general, for GET requests since everything's in the query string it usually looks like this:

http://your_api.io/postdata/deviceID?foo=bar&hello=world

and you can just fill in the data. However, this differs from API to API and you should check the exact format of the one you're using. However, the example works perfectly for dweet!

POST Method

Using the POST method in the example code is very similar to GET except that now you'll have to define a message body and include this body as an input to the "postData" function:

https://github.com/botletics/SIM7000-LTE-Shield/blob/master/Media/IoT%20Example%20POST%20Request.PNG

Testing if it Worked

So how do you know it actually posted? At least for dweet it's super simple. Just go to "dweet.io/get/latest/dweet/for/{IMEI}" where you should fill in your device's IMEI number in the URL and you can find it printed during the initialization process near the beginning of the serial monitor when the code runs. If you see "{"this":"failed","with":404,"because":"we couldn't find this"}" then yea, it probably didn't work, but if you see "success" and a bunch of data, then good for you!

IoT Dashboards

Maybe you're a helicopter mom and want to track exactly where your teen is driving to? No problem! Just follow this GPS tracker tutorial I made on how to use freeboard.io and thingsboard.io to create some killer-awesome dashboards in a jiffy!

MQTT Protocol

MQTT Setup

If you aren't using MQTT you can skip this step. However, if you are using MQTT then listen up! In this example we will be sending data to either Adafruit IO or CloudMQTT. As such, the obvious thing to do is to login or create an account on Adafruit IO or CloudMQTT or both. It should be noted that the Adafruit MQTT implementation should theoretically work with any compatible MQTT broker, not just AdafruitIO.

You'll also have to make sure to uncomment the "PROTOCOL_MQTT_AIO" line if you're using Adafruit IO and if you're using CloudMQTT then you should uncomment "PROTOCOL_MQTT_CLOUDMQTT" as described in a previous section.

Adafruit IO

In Adafruit IO you should then see a "View AIO Key" tab on the left hand menu. Click that and it will give you your username and key to use the example code.

Now look near the top of the code and find the MQTT setup section. Change the gap-filler username and key to your own:

https://github.com/botletics/SIM7000-LTE-Shield/blob/master/Media/IoT%20Example%20MQTT%20Setup.PNG

In the next section you will see a bunch of "feeds" being initialized for Adafruit IO. If you're using CloudMQTT then you don't have to worry about this:

https://github.com/botletics/SIM7000-LTE-Shield/blob/master/Media/IoT%20Example%20MQTT%20Publish%20Feeds.PNG

These are essentially the MQTT "topics" that the device can publish to but since Adafruit wants to have their own deal it's not set up exactly the same as other MQTT brokers. Here we set up the actual names of the feeds as well as their corresponding names in the code. For example, the device can send info to the "latitude" feed but this feed is referred to as "feed_lat" in the code to make it distinct. In order for you to see the values appear in Adafruit IO, however, you must first create these feeds. You can do this in Adafruit IO by going to the "Feeds" tab and clicking the "Actions" dropdown menu then clicking "Create a new feed". Make sure that you name the feeds exactly how they appear in the code otherwise you will be staring at them wondering why the data isn't going through! After you create all the feeds it should look like this:

https://github.com/botletics/SIM7000-LTE-Shield/blob/master/Media/Adafruit%20IO%20Feeds.PNG

After uploading and running the code your device should send all the data to whichever platform you're using and you should see the values appear in real time under each feed!

With Adafruit IO you can also set up cool dashboards that grab data from the feeds and display them in what's called "blocks" (widgets basically). For example, gauges, maps, etc. You can make a GPS logger using the IoT_Example code and creating a dashboard, adding a map, and selecting the feed that the map pulls data from. In our case this feed has to be a combined csv feed with a sensor value (in this case speed), longitude, latitude, and altitude. From this combined data feed the map plots the location.

CloudMQTT

In CloudMQTT you have to go to the "Details" tab where you will see the server, username, password, and port number:

https://github.com/botletics/SIM7000-LTE-Shield/blob/master/Media/CloudMQTT%20Details%20Page.PNG

Enter these values in the CloudMQTT setup section:

https://github.com/botletics/SIM7000-LTE-Shield/blob/master/Media/IoT%20Example%20CloudMQTT%20Setup.PNG

Upload and run the Arduino sketch and for CloudMQTT you have to go to the Websocket UI in order to see the values:

https://github.com/botletics/SIM7000-LTE-Shield/blob/master/Media/CloudMQTT%20Websocket%20UI.PNG

Simply refresh the page to clear the values. Note that the latest values are on the bottom, not the top.

Another cool thing you can do with CloudMQTT is to link it to an IoT dashboard like freeboard.io by simply entering the CloudMQTT server name, port, topic, and login credentials as a new datasource in freeboard. Since CloudMQTT is a generic MQTT broker service you can link it to pretty much any other IoT dashboard or platform you want!

Other MQTT Brokers

You can also publish to pretty much any other basic MQTT service that does or does not support username and password. In this case you can just change the CloudMQTT settings such as the server name, port number, username, and password. To actually connect to the broker just follow the CloudMQTT example in the sketch. The main steps in using MQTT are the following:

  • Use "fona.TCPconnect(MQTT_SERVER, MQTT_SERVERPORT)" to first connect to the server via TCP connection
  • Use "fona.MQTTconnect(PROTOCOL_NAME, MQTT_CLIENT, MQTT_USERNAME, MQTT_KEY)" to send an MQTT connect packet to the server to actually connect to the broker. Note that the "PROTOCOL_NAME" field varies depending on the service. For example, CloudMQTT requires "MQIsdp" but most others require "MQTT". Note that the username and key parameters are optional in case the MQTT service does not require them.
  • Use "fona.MQTTpublish("topic_name", message_content)" to actually send (publish) data to a "topic". Topics are just as they sound and can be thought of as different "rooms" or "threads" in an instant messaging app that hold the message content. You can publish to as many topics as you'd like!
  • Finally, use "fona.TCPclose()" to close the TCP connection entirely!

Note: there are some other features (like subscribe, etc.) that aren't yet implemented.

MQTT Subscriptions

In addition to publishing data to MQTT topics you can also subscribe to topics. This is very useful because all subscribers listening in on that topic can receive data. For example, let's say you had five shields, each one doing their own thing but also subscribed to a topic called "command". By simply publishing a message "ON" or "OFF" to the "command" topic we can make all subscribers turn on and off LED's. Let's see how this can be used with Adafruit IO feeds in the same IoT_Example sketch. Somewhat near the beginning of the code you'll see the following line in the Adafruit IO MQTT setup section:

Adafruit_MQTT_Subscribe feed_command = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/command");

This line initializes "feed_command" as a subscription to the feed/topic named "command" in Adafruit IO. As you probably guessed, we'll have to create this "command" feed in AIO as we did previously with the other feeds. Once you have that set up let's look at the rest of the code. At the end of the setup() function you'll see the following line:

mqtt.subscribe(&feed_command);

This line sets up the subscription to the feed to that we can use it later on. Now, in the loop() function inside the PROTOCOL_MQTT_AIO section you'll see the code that grabs the data from the feed we're subscribing to and print it out and process it to do things based on that command. In this example we'll be reading commands from the feed to turn an LED on and off based on whether we send "ON" or "OFF" from Adafruit IO. At this point just upload the code, open the serial monitor, let it run, and you should see the data appear in the feeds on Adafruit IO. Now the fun begins! Click your newly-created "command" feed and using the "Actions" dropdown click "Add Data" and type in "ON" and press Enter. You should see this data appear in the log below:

https://github.com/botletics/SIM7000-LTE-Shield/blob/master/Media/Adafruit%20IO%20Command%20Feed.PNG

Switching to the serial monitor you should see the data appear after the module publishes data:

https://github.com/botletics/SIM7000-LTE-Shield/blob/master/Media/AIO%20MQTT%20Command%20Message.PNG

Later down in the serial monitor you should also see "*** Commanded to turn on LED!" and your LED should be on! Try the same thing but type "OFF" to the feed instead, and your LED should now turn off!

It should be noted that it takes more than 10s by default to get the data from the subscribed feed in the IoT_Example sketch. This is because there is a delay set by the "samplingRate" variable near the top of the sketch that defines the time in between posts. During that delay it's not doing anything nor checking for commands from. This example is more or less "blocking" code in that it runs in a sequence and doesn't really allow other things to run simultaneously. However, if you want to increase the responsiveness you can either reduce the time in between posts or just write your own sketch that constantly loops through the subscription section. You can make code that does this using the millis() function to periodically run the publish code to send data, then you could have the subscribe loop always being run at all other times. Anyway, have fun with it and share if you make anything cool with it!