Signed in as:
filler@godaddy.com
Signed in as:
filler@godaddy.com
You will need four things to send data over cellular communications with the Panther Logger:
1. Cell Modem
A variety of modems from Nimbelink fit the Panther Logger's 2 x 10 pin header format and pin outs. For this tutorial we will use Nimbelink's Quectel BG96 modem (specifically NL-SW-LTE-QBG96-B or revision C) which can be purchased from Digi Key (here) and other distributors. See the Nimbelink site for this modem here. Please note that model revision "B" of this modem or later should be used as this comes with the correct firmware. The BG96 modem is a narrow band LTE-M and NB-IoT modem that operates at lower power. It is used in many different low power IoT applications. Nimbelink also provides a variety of other interchangeable modems that work with the Panther Logger including wide band modems (see here).
2. SIM Card
For cell service we will use a Hologram.io SIM card that works globally or just within the United States. See Hologram's website for more details.
Do not leave the board running code that sends data needlessly using up your purchased data or running up a bill with your service provider! If you load code to the Panther Logger that sends data using the cellular and SIM card then be sure to unplug the cell modem when not using.
So keep in mind how often you send data and how much you send with each transmission. There are ways to decrease data usage and costs significantly. First, Hologram (and probably other service providers) allows you to limit the amount of data for any SIM. For example, any SIM that supports machine to machine transmissions and there are many competing companies.
Hologram provides roaming service mainly on ATT, US Cellular and T-Mobile. Soracom is another option for SIM cards. Whatever the SIM card you choose, it needs to be activated according to the instructions provided by the service provider. Go to the providers website, setup an account and enter the SIM card number to activate it (for Hologram see here). The dashboard provided by Hologram and Soracom provide useful monitoring information about your device's connectivity.
The SIM card should be inserted as a microSIM (see here) into the back of the Nimbelink cell modem and then the modem should be inserted into the 2x10 pin header on the Panther Logger board. Please insert the modem into the headers with the power switch on the Panther Logger off and no battery plugged in. The Nimbelink modem should be orientated on the 2x10 pin headers such that the antenna connections on the top of the cell modem are closest to the on/off switch at the top of the Panther Logger board (see photo to the right). Powering the Panther Logger with the cell modem inserted into the header pins in the opposite direction will damage the modem, short the battery, and could possibly damage the Panther Logger.
3. Battery
You will need a battery plugged into the Panther Logger board in order to use a cell modem as the cell modem is only powered by the battery, not by any of the power rails on the board. This is because current draw by cellular modems often needs to spike, briefly, to a high level during data transmissions. In order to provide this to the cell modem, its power pin is directly connected to the positive battery terminal with wide traces over a short distance and with a large amount of capacitance. See our battery recommendations here and usage notes.
4. Antenna
We provide specific recommendations on which antennas to use with Panther Logger modules. A cellular antenna is needed to run this tutorial. It should be plugged into the u.fl connector on the Nimbelink modem. The antenna should be greater than 20 cm away from any human body during use to comply with FCC rules.
With the cell modem installed and battery connected, go to our Github page for the SendData_Cellular_GET code here. You will see multiple files. That's because this Arduino sketch has multiple tabs to organize the code better. As such it has multiple files that correspond to those tabs.
In the Arduino software, make a new sketch, then copy/paste the code from the SendData_Cellular_GET.ino file in our Github directory linked above into this new sketch and then "save as" with the same name. (see video on right)
Now, click on the down arrow in the upper right part of your new sketch. Choose new tab and give it the name of one of the other files in this Github folder (e.g. _01_Sensor_Functions). There are four files so you will need a total of three tabs in addition to the main first tab so go ahead and create all of the tabs needed. You can give the tabs any name you like, HOWEVER, the beginning of each tab name is critical. It gives the order and this order is important as it is the order that the code should be run. We used numbers so they are automatically ordered correctly. You will need to copy/paste the contents of each Github file into each respective tab and then save the entire script. See the video to the right as an example.
We will send data first to ThingSpeak using the GET method. Your ThingSpeak account and channels should be setup just as we did in tutorials for WiFi communications in the Panther Logger 3 tutorial. See that tutorial to setup your account and the channels we will use.
We need to change some things in the SendData_Cellular_GET code to send data to a specific ThingSpeak channel just like we did for WiFi. Find this section in the code near the beginning on the first tab:
char Token[] = "XXXXXXXXXXXXXXXXXX";
Replace the X's with your api_key from ThingSpeak.
Then find this code:
char Endpoint[] = "https://api.thingspeak.com/update.json?api_key";
This shows the ThingSpeak endpoint for making a GET call. After the "?" is the name of the credential we need to include. ThingSpeak calls this the "api_key" whereas other sites might call it just "key" or "token." See the API documentation for a REST HTTP GET method for the site you are communicating with. ThingSpeak's API documentation is here. Since we are sending data to ThingSpeak with this tutorial nothing needs to be changed, but if sending to a different database then the name of this "Token" might need to be changed based on the API documentation.
The code is going to build up this url with the api_key and the data we want to send. It will use the sprintf function to do this. See this function below:
sprintf(Payload, "%s=%s&field1=%.2f&field2=%.2f&field3=%.2f&field4=%.2f&field5=%d&field6=%.2f&field7=%.2f&field8=%.2f",
Endpoint,
Token,
AirTemp,
Humidity,
BaroPressure,
WindSpeed,
WindDirection,
DewPoint,
WindChill,
Batv
);
This function takes three arguments. The first is the character string, in this case we called it "Payload." This is the character string we will fill with the url. The second argument is the url text or characters. Any text with a percent in front of it refers to an injected variable from the third argument and in the order listed with a comma in between. So the first text with a percent is %s which means fill this with a string variable. The first variable is "Endpoint" define in the sketch as a C string or char variable and it is the first part of the url we need to send (i.e. https://api.thingspeak.com/update.json?) . Others are floats and ints or integers containing the data we want to send so we use %f or %d, respectively for those variables.
sprintf is a very important and useful function when the concatenate function strcat cannot be used because you need to inject various number and text formats into a string variable.
Here is an example of a GET url generated by this code. We replaced our api_key with X's.
ThingSpeak expects data in "fields" so data is specified by field numbers instead of variable names. Sensor data is inserted into this url with the sprintf function in the GET Functions tab. It is worth some time studying how this sprintf function works as it is very useful for getting sensor data into a string. Most modems expect or at least can use strings to send data. They usually do not or cannot expect float or int data.
We are going to send random numbers for weather data and actual measured battery voltage.
Sensors are measured on the Sensor Functions tab. We have a function to measure battery voltage that also makes use of a function to read millivolts on any analog pin (battery voltage is measured on analog pin 4 on the Panther Logger).
We have a function called readSensors() that puts random numbers into mock weather sensor variables and implements the battery voltage measurement. In other tutorials in our Learning Center we show how to measure various kinds of sensors using the Panther Logger. We are not showing that here in this tutorial so as not to complicate the task of sending data to the internet. In an actual application one would add additional functions here to read actual sensors on this tab, like weather and water quality sensors, soil moisture etc and then that data would get sent using the cellular modem provided that the sprintf function is updated to include them and that the server database is setup to receive them.
On the GET Functions tab there is a function to make the url (i.e. the payload) and a function to send the payload using the HTTP GET method called "GetData." The GetData command sends multiple AT commands to the modem to setup communications and finally sends the data. Note that many of these AT commands are universal to all modems whereas some are specific to this Quectel modem. We put comments in the Arduino sketch indicating what each command is doing.
Finally, the Cellular Functions tab contains functions to interact with the cell modem. This includes a function "sendAT" to send AT commands to the cell modem and read its response. It takes three arguments:
sendAT("AT+Command", "Response1", "Response2", Wait Time);
It is very important that code to send AT commands waits for an expected response from the modem whether it is a positive response or error before your program continues and sends another AT command. Sending multiple AT commands to the modem without waiting for each response from each AT command can cause the modem to freeze. This is why the code has multiple delays between sending AT commands along with this "sendAT" function to wait for expected responses. The AT command documentation for the Quectel BG96 modem provides the expected responses for each AT command. Generally a one second delay between sending AT commands is recommended.
This Cellular Functions tab in the sketch also contains functions to read network registration status, signal strength and quality. In other tutorials we will show how to read the date and time from the modem, get geolocation information and basic modem information like modem model number, SIM number, and network tower ID to which the modem is connected as well as the service provider.
Upload the SendData_Cellular_GET sketch to the Panther Logger and then open the serial monitor. You will see the processor sending AT commands to the modem in order to setup the modem to first get a signal and register with the network and then to setup the URL to send data with "GET." After the data is sent you should get:
+QHTTPGET
Sending:
Received: : 0,200
The "200" indicates a successful transmission. After that you should also get the header response information because the code sent the response header command:
AT+QHTTPCFG="responseheader",1"
Where the 1 indicates we wish to receive a response header (0 if we do not).
And we send the read AT command:
AT+QHTTPREAD=60
That command indicates that we want to read the server response and we give it 60 seconds to do so.
Here is a typical response from ThingSpeak:
CONNECT
HTTP/1.1 200 OK
Date: Wed, 06 Dec 2023 04:06:24 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Status: 200 OK
Cache-Control: max-age=0, private, must-revalidate
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 1800
X-Request-Id: 6b0566e5-9a04-4aca-a25a-b601810d05bf
Access-Control-Allow-Headers: origin, content-type, X-Requested-With
Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS, DELETE, PATCH
ETag: W/"313f8984cbbc2c3c315c8d0790cb6b85"
X-Frame-Options: SAMEORIGIN
{"channel_id":2362505,"created_at":"2023-12-06T04:06:24Z","entry_id":2251,"field1":"6.00","field2":"49.00","field3":"1192.00","field4":"38.00","field5":"1"e610,e710"e:."au:llgu:llann"a"u
OK
If you do not get an HTTP/200 response or errors then check the following:
1. Is antenna connected?
2. Is battery connected and the board turned on
3. Is the token or api_key entered correctly?
Be sure you copied the code correctly and if you changed anything from our Github code then go back to the original first. An example of serial monitor output is included in our Github repository here.
Now we will send data using HTTP POST. We will also send the data over a secure sockets layer connection (HTTPS). We are going to send data to Ubidots so make sure you have setup an account as described in Panther Logger 3
Go to our Github respository page for the SendData_Cellular_POST code here. As with the GET code above there are multiple files, each one corresponding to a tab in the Arduino sketch. Copy the contents of each file and put into tabs in a new Arduino sketch as done for the GET code. Name the tabs according to the file names. The main (first) tab should be the code in the SendData_Cellular_POST.ino file.
Go to this code in the main tab:
char url[] = "https://industrial.api.ubidots.com";
char Host[] = "industrial.api.ubidots.com:443";
char Token[] = "X-Auth-Token: XXXXXXXXXXXXXXXXXXX";
char Destination[] = "/api/v1.6/devices/XXXXXXXXXX";
The char url holds the endpoint address for Ubidots API and this is obtained from the Ubidots API documentation (here). The Host char will be inserted into the header information sent with the data and it should just be the domain name with a port of 443 since we are sending data over HTTPS. If sending over HTTP then the default is port 80. Again, check the API documentation for port settings. The token holds the API key or token or in this case "X-Auth-Token." The name of the token and the token itself will need to be changed according to the API documentation and of course your device's given token. The token from Ubidots is on your device information page. Copy the token from Ubidots and replace the X's in the Token char. In the Destination char ubidots used the device name that you gave your device when creating a new device at ubidots. In our case we called our device "Panther Logger" Replace the X's in the Destination char with your device name at Ubidots (see video on the right).
That's all that needs to be edited in the code. Go ahead and upload to your board and open the serial monitor.
As with the GET code above you will see AT commands sent to the modem and the modem responses. These AT commands register the modem on the network, get it setup for a POST request and then sends the data with a post command. Here is an example of a successful post request to Ubidots.
A critical part of the POST command code is the syntax of the header information. In the SendData_Cellular_POST code above see this part of the code on the _02_Post_Functions tab:
void MakePayload(){
String DataStringS = DataString;
sprintf(ContentLength,"Content-Length: %d",DataStringS.length());
strcpy(Payload,"POST "); strcat(Payload, Destination); strcat(Payload," HTTP/1.1"); strcat(Payload,"\r\n");
strcat(Payload, "Host: "); strcat(Payload, Host); strcat(Payload, "\r\n");
strcat(Payload, "Accept: */*"); strcat(Payload, "\r\n");
strcat(Payload, ContentLength); strcat(Payload, "\r\n");
strcat(Payload, "Content-Type: "); strcat(Payload, ContentType); strcat(Payload, "\r\n");
strcat(Payload, "User-Agent: "); strcat(Payload, UserAgent); strcat(Payload, "\r\n");
strcat(Payload, "Cache-Control: no-cache"); strcat(Payload, "\r\n");
strcat(Payload, "Connection: keep-alive"); strcat(Payload, "\r\n");
strcat(Payload, Token); strcat(Payload, "\r\n");
strcat(Payload, "\r\n");
strcat(Payload, DataString); strcat(Payload, "\r\n");
}
This is a function to make the payload to send and the first part of it is creating the request header. The request header looks like this:
POST /api/v1.6/devices/panther2 HTTP/1.1
Host: industrial.api.ubidots.com:443
Accept: */*
Content-Length: 42
Content-Type: application/json
User-Agent: panther2/1.0
Cache-Control: no-cache
Connection: keep-alive
X-Auth-Token: XXXXXXXXXXXXXXXXX
{"temperature": 16.00,"battery": 4.12}
All of the spelling (syntax), characters, and even spaces are important in this header information. The same was true in tutorial #3 when sending data via POST using WiFi. For example, the header must begin with "POST", then a space, then the destination address, then a space and then "HTTP/1.1" Each line of the header must end with \r\n indicating new line and line feed. A blank line must be in between the last line of the header and start of the data string to send. If these are not entered correctly then will result in an error.
There is a function on this tab to create the data string to send in json format. Right now this just sends actual battery voltage and fake temperature data. There are two lines of code to measure the length of this data string, which is inserted into the header for "Content-Length."
There is a function on this tab called "getPayloadCommand" to calculate the total length of the payload including the header information plus the data string and then make the AT command for a POST.
The length of the messages sent must be exact or the transmission will fail.
If you want to practice sending AT commands to the modem then you can upload our Cellular_Terminal sketch here. This will create a terminal from the serial monitor to talk to the modem. Upload the sketch and then open the serial window. The modem will be reset and then wait for "APP RDY."
At the bottom of the window set the line ending to "Both NL & CR." Then in the "send" box at the top of the serial window enter the simple AT command, AT, and then hit enter. The modem will respond with "OK."
See video on the right for a demonstration and be sure to turn on captions.
You can now send any AT command here and see how the modem responds. This can be a good way to try out AT commands, see how the modem works, and troubleshoot problems with sending data or getting data from the modem.
The AT command manual for the BG96 modem is here. Below are some useful AT commands. Try entering them into the serial monitor window and see the modem response.
The AT command below is in bold and the response in italics.
//Get modem model and revision number
ATI
Quectel
BG96
Revision: BG96MAR02A07M1G
//Get SIM card number. I replaced some numbers with X's
AT+GSN
8662330515XXXX
//Get the modem temperature. Returns temperature of three different parts of the modem (in Celsius)
AT+QTEMP
+QTEMP: 40,35,36
//Get the current date and time. Note this requires that the modem is registered on the network
AT+CCLK?
+CCLK: "23/12/11,08:13:15-24"
//Get signal strength and quality as well as current network.
//As you will see right now we are on a Cat-M1 network
//There are four numbers. The second and last numbers are the RSRP and RSRQ
//RSRP is strength and RSRQ is quality. See here for nice description.
AT+QCSQ
+QCSQ: "CAT-M1",-95,-125,108,-14
//Get network registration status
//We can send three commands at once
//This gets registration status for the three network types GPRS, ESD and CSD
//Look at the AT command manual for explanation of modem responses
//A response of 5 means registered and roaming
AT+CREG?;+CGREG?;+CEREG?
+CREG: 2,5,"4301","4A00F09",8
+CGREG: 2,4
+CEREG: 2,5,"4301","4A00F09",8
//Set to choose network automatically
AT+COPS=0
//Search for available networks
//This can take up to 30 minutes
//In my experience usually takes about 2 minutes
//This can be useful to do to get the modem registered initially
//Set AT+COPS=0 first and then:
AT+COPS=?
+COPS: (1,"311 589","311 589","311589",8),(1,"Verizon","Verizon","311480",8),(1,"311 588","311 588","311588",8),(1,"U.S.Cellular","USCC","311580",8),(2,"AT&T","AT&T","310410",8),(1,"313 100","313 100","313100",8),(3,"T-Mobile","T-Mobile","310260",8),(1,"311 490","311 490","311490",8),,(0,1,2,3,4),(0,1,2)
Get GPS Information
First we need to setup how we want to receive GPS information and then turn it on.
//Turn on the DC power to the GNSS antenna, and save it in this state across power off
AT+QCFG="gpio",1,64,1,0,0,1
OK
AT+QCFG="gpio",3,64,1,1
OK
//Query status of the antenna pin
AT+QCFG="gpio",2,64
+QCFG: "gpio",1
//Turn on GPS
AT+QGPS=1
OK
//Turn on NMEA output
AT+QGPSCFG="nmeasrc",1
OK
//Request NMEA sentences containing GNSS information. See here.
//The NMEA sentences "GGA" and "RMC" provides most information available.
AT+QGPSGNMEA="GGA"
+QGPSGNMEA: $GPGGA,,,,,,0,,,,,,,,*66
//The above response indicates we do not have GPS fix. Move device to clear view of the sky
We can enter the AT commands in the SendData_Cellular_GET sketch manually to send data to ThingSpeak. Copy and paste the AT commands below into the serial monitor line by line hitting enter to send each one. Replace the X's in the URL with your API key from ThingSpeak. This assumes you are using a Hologram.io SIM card. If not then change the APN in the AT+QICSGP command to your provider's APN. In the video to the right I am using a SIM card from Soracom, so the APN is set to "soracom.io" instead of "hologram"
AT+CFUN=1,1
ATE
AT+QCFG="nwscanseq"
AT+COPS=0
AT+QICSGP=1,1,"hologram"
AT+CREG=2;+CGREG=2;+CEREG=2
AT+QHTTPCFG="contextid",1
AT+QHTTPCFG="responseheader",1
AT+QHTTPCFG="requestheader",0
AT+QHTTPCFG="sslctxid",1
AT+QSSLCFG="seclevel",1,0
AT+QIACT?
AT+QIACT=1
AT+QIACT?
//After entering the AT command below the modem will respond with "CONNECT" and then you can enter the URL.
//The first number is the length of the URL (number of characters), which you will need to determine manually
AT+QHTTPURL=165,80
AT+QHTTPGET=80
//You will receive "ok" from the modem, but now wait for "+QHTTPGET: 0,200" (successful transmission) or at least some other response before continuing
//Issue read command to get response from ThingSpeak server
AT+QHTTPREAD=80
The forbidden network list or FPLMN (Forbidden Public Land Mobile Network) is a list of networks that the modem will maintain and not attempt to make a connection. In some cases it might be advantageous to add a carrier to this list. For example, we recently learned that one carrier in our country did not have great support for CatM/NB-IoT devices. Our modem (Quectel BG96) would connect to this carrier's network and send a few data packets and then completely stop. To fix the problem, we added this carrier to the forbidden network list in our area, the modem connected to a different carrier and was able to send data continuously.
To add a carrier to the FPLMN you need to know its MCC and MNC codes in your area. To find this, upload the Cellular_PassThrough sketch and send the following AT commands:
ATE
AT+COPS = 0
AT+COPS = ?
Wait up to 30 minutes (usually about 5 minutes). You will get a comma separated list of carriers in your area which will include their Home Network Identity (HNI) codes. This is simply a concatenation of their MCC and MNC numbers where the first three numbers of the HNI are the MCC and the last three numbers of the HNI are the MNC. You will need to use the MCC and MNC codes to create the PLMN code used to add the carrier to the forbidden network.
The PLMN code for a carrier is created from the MCC and MNC as follows:
Byte 1: MCC Digit 2 + MCC Digit 1
Byte 2: MNC Digit 3 + MCC Digit 3
Byte 3: MNC Digit 2 + MNC Digit 1
For example:
HNI ID = 310410 (home network ID for AT&T in the US)
MCC = 310
MNC = 410
PLMN ID = 130014
Byte 1 = 13
MCC Digit 2 = 1
MCC Digit 1 = 3
Byte 2 = 00
MNC Digit 3 = 0
MCC Digit 3 = 0
Byte 3 = 14
MNC Digit 2 = 1
MNC Digit 1 = 4
Once the PLMN has been created we need to issue it in the AT+CRSM command as follows:
AT+CRSM=214,28539,0,0,12,"XXXXXXFFFFFFFFFFFFFFFFFF"
Replace the X's in the above with the PLMN number of the carrier you want to add to the FPLMN list. Issue this AT command in the setup sequence for the Panther Logger cell modem.
Copyright © 2023 ElectroRex - All Rights Reserved.
Powered by GoDaddy
We use cookies to analyze website traffic and optimize your website experience. By accepting our use of cookies, your data will be aggregated with all other user data.