I have a SIM800L based data logging unit. This is part of a LilyGo T-Call 1.4 unit with an ESP32 controller. I wanted to find the location of the device using the GSM network and this post gives information relating to my attempts at doing this. Spoiler alert – you cannot easily get longitude and latitude information from this board!

Hardware overview

The hardware is an ESP32 based unit with the SIM800L GSM/GPRS module. There are lots of SIM800 based break out boards and lots of code examples for getting started with these boards. I used the TingGSM library within my arduino sketch and all examples given here have used that library and examples. Please start by ensuring your SIM800 module and microcontroller already work and connect correctly to your network – this is not covered in this post.

The datasheet (version 1.12) for AT commands for the SIM800L module is here. Please check for latest version as this is updated regularly.

Some additional examples for location commands is available from this application note.

You may also want to ensure your SIM800 has the latest version of the firmware installed. I followed these instructions for updating the firmware on the T-Call board. This did not change anything in my tests, so I assume my units came with the most up to date firmware!

In all of these examples it is assumed that the SIM800 is connected to a GPRS network and to an APN. Please see other posts or the TinyGSM library for more information on this.

The SIM800 module is communicated to with “AT” commands. These are not discussed in detail here, please check the AT commands and online examples for more information.

Test 1: +CIPGSMLOC

My first test was to use the “AT+CIPGSMLOC” command to ask for the GSM LOCation. It should return the longitude and latitude of the GSM tower that the unit is connected to.

Many people have used this function for building unit trackers (please search for GSM800 tracker or SIM800 GSMLOC). This seems to have worked well in the past, BUT… this was a service provided by Google, which has been discontinued towards the end of 2020. So this did not work for me!

This command is in the AT command list v1.09, but it has been removed in v1.12. The information from v1.09 is given here:

The code I used is given here:

modem.sendAT(GF("+CIPGSMLOC=1,1"));

if (modem.waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) == 1)
{
     String res = SerialAT.readStringUntil('\n');
     modem.waitResponse();
     SerialMon.print("Data:");
     SerialMon.println(res);
}

When connected to the network and APN then this returned the data:

“0,0.000000,0.000000,2021/11/03,14:16:17”

This should be “location code, longitude, latitude, date, time”. The location code, longitude and latitude are all zero. The date and time are correct (useful if you need that information!).

End result: This does not work due to Google stopping this service sometime in 2020.

Test 2: +CENG

The command “AT+CENG” is designed to put the unit into “Engineering Mode”. This is for field engineers to view and test network information recieved. The command from the v1.12 AT command list is here:

The code I used was:

      modem.sendAT(GF("+CENG=2"));
      if (modem.waitResponse(10000L, GF("+CENG:")) == 1)
      {
        String res3 = SerialAT.readStringUntil('\n');
        modem.waitResponse();
        SerialMon.print("Data:");
        SerialMon.println(res3);
      }

The data returned was:

0,”0669,43,00,234,30,31,74e3,06,00,09e1,00″

This is slightly useful, as it does return the cellid (74e3) , the MCC (234), MNC (30) and the LAC (09e1) of the cell tower the unit is conencted to. See the end of this post for details of how to convert this into cell tower location.

Test 3: +CLBS

The “AT+CLBS” command should get the Base station Location. It is used in conjunction with “AT+CLBSCFG” which is the configuration for CLBS. This info is from the SIM800 location application note.

Information from that is:

The code I used, following some examples I found online, was:

    for (int i = 5; i > 0; i--)
    {
      // Attempt this a few times
      SerialMon.print("Attempt:");
      SerialMon.println(i);
      String res2;

      modem.sendAT(GF("+CLBSCFG=0,1"));
      if (modem.waitResponse(10000L, GF("+CLBSCFG:")) == 1)
      {
        res2 = SerialAT.readStringUntil('\n');
        modem.waitResponse();
        SerialMon.print("Data:");
        SerialMon.println(res2);
      }

      modem.sendAT(GF("+CLBSCFG=0,2"));
      if (modem.waitResponse(10000L, GF("+CLBSCFG:")) == 1)
      {
        res2 = SerialAT.readStringUntil('\n');
        modem.waitResponse();
        SerialMon.print("Data:");
        SerialMon.println(res2);
      }

      modem.sendAT(GF("+CLBSCFG=0,3"));
      if (modem.waitResponse(10000L, GF("+CLBSCFG:")) == 1)
      {
        res2 = SerialAT.readStringUntil('\n');
        modem.waitResponse();
        SerialMon.print("Data:");
        SerialMon.println(res2);
      }

      modem.sendAT(GF("+CLBS=1,1"));
      if (modem.waitResponse(10000L, GF("+CLBS:")) == 1)
      {
        res2 = SerialAT.readStringUntil('\n');
        modem.waitResponse();
        SerialMon.print("Data:");
        SerialMon.println(res2);
      }

      modem.sendAT(GF("+CLBS=4,1"));
      if (modem.waitResponse(10000L, GF("+CLBS:")) == 1)
      {
        res2 = SerialAT.readStringUntil('\n');
        modem.waitResponse();
        SerialMon.print("Data:");
        SerialMon.println(res2);
      }      
    }

This returned the data:

Data: 0,1,""
Data: 0,2,147
Data: 0,3,"lbs-simcom.com:3002"
Data: 1
Data: 1

The last two items show that the location data has not been returned. It states in the application note that “this function needs special module and FW to be supported” so I think it must have special firmware applied to the SIM800 module for this function to work.

Test 4: modem.getGsmLocation

This test used an in-built command to the TinyGSM library, modem.getGsmLocation();

This used the following code:

    float lat      = 0;
    float lon      = 0;
    float accuracy = 0;
    int   year     = 0;
    int   month    = 0;
    int   day      = 0;
    int   hour     = 0;
    int   min      = 0;
    int sec = 0;
    for (int8_t i = 5; i; i--)
    {
      // Try this five times:
      SerialMon.println("Requesting current GSM location");
      if (modem.getGsmLocation(&lat, &lon, &accuracy, &year, &month, &day, &hour,
                               &min, &sec))
      {
        SerialMon.print("Latitude:");
        SerialMon.print(String(lat, 8));
        SerialMon.print("\tLongitude:");
        SerialMon.println(String(lon, 8));
        SerialMon.print("Accuracy:");
        SerialMon.println(accuracy);
        break;
      }
      else
      {
        SerialMon.println("Couldn't get GSM location, retrying in 1s.");
        delay(1000L);
      }
    }

This timed out and could not return any information. This command, I think, uses the AT+CIPGSMLOC command, which now no longer works since Google stopped the service (see above).

Test 5: +CNETSCAN

This command (“AT+CNETSCAN”) scans for the cell tower network (CTNET). It returns quite a lot of information regarding the operator and cell tower location. Here is the details from the AT command reference:

The code I used was:

      modem.sendAT(GF("+CNETSCAN=1"));
      modem.sendAT(GF("+CNETSCAN"));
      if (modem.waitResponse(10000L, GF("Operator:")) == 1)
      {
        String res1 = SerialAT.readStringUntil('\n');
        modem.waitResponse();
        SerialMon.print("Data:");
        SerialMon.println(res1);
      }

This returned the data:

“T-Mobile”,MCC:234,MNC:30,Rxlev:53,Cellid:74E2,Arfcn:649,Lac:09E1,Bsic:11

Now we are getting somewhere! The data returned includes the Cellid (ID of the cell tower) the MCC, MNC and LAC, which are both identifiers of GSM towers.

This data can be put into an online map of GSM towers, such as opencellid.org or http://www.cell2gps.com/ . You must remember to convert the Cell ID and the LAC from their HEX value into a decimal value. I used the scientific calculator function to do this. Putting the data returned into the cell2gps website then I found the following map, which was the correct location:

Final Thoughts

Using the SIM800 to find location is not ideal nor easy. It can only return the location of the GSM tower that it is connected to. This data is returned in a format of the Cell ID, MCC, MNC and LOC of the nearest cell tower. This needs to be compared to a database of cell mast locations and this can then return the approximate location of the unit.

This is potentially workable, if the list of cell towers is available or can be converted using some script from the data recorded. But it’s not very easy to get longitude and latitude. It will be simpler to use a GPS unit or SIM unit with in-built GPS to return accurate location data. If only the GSMLOC command was still working!!

Additional Information

Some additional links that may be useful to you:

One response to “Find Location with SIM800L

  1. Genial el trabajo.. tengo un problema con mi sim800c… cuando ejecuto CNETSAN, tengo como respuesta..
    [38456] ### Unhandled: Operator:”Retevision Movil”,MCC:214,MNC:03,Rxlev:44,Cellid:1950,Arfcn:985
    Operator:”Retevision Movil”,MCC:214,MNC:03,Rxlev:43,Cellid:194E,Arfcn:989
    Operator:”MOVISTAR”,MCC:214,MNC:07,Rxlev:40,Cellid:07E7,Arfcn:45
    Operator:”vodafone”,MCC:214,MNC:01,Rxlev:49,Cellid:F607,Arfcn:101
    Operator:”vodafone”,MCC:214,MNC:01,Rxlev:42,Cellid:F605,Arfcn:107

    Al tener el [38456] ### Unhandled:… no me guarda el resultado en un string para despues poder selccionar el mejor operador en esa zona… me puedes decir como solucionarlo??

Leave a Reply

Your email address will not be published. Required fields are marked *