Lilygo-T-SIM7000G, GPS and Cellular Data, in Micropython

Lilygo-T-SIM7000G, GPS and Cellular Data, in Micropython

I’ve been struggling with a new toy for the last few days. I purchased the Lilgo-T-SIM7000G -AFFILIATE LINK board about a month ago and it’s been a real struggle. Here I’m going to document my successes and failures in the hopes that I'’ll help someone in the future, probably even myself.

The inital goal is really not important but to help you understand what I’m working with, it’s a neat little board with GPS, a cellular modem (the SIM7000G to be exact), an onboard battery, and solar charge controller. All built into a nice size board. As I said, the project isn’t important, maybe I’ll cover that in the future, but I need access to cellular data and to GPS data. Thus began my troubles.

Most documentation is for Arduino

The first challenge was really just finding any sort of documentation. I’ll admit, I’m very disappointed in the documentation that exists for how to interact with the module itself, but what made this even more troublesome was that I’m using micropython. It’s a choice, I know. There is always Arduino and in fact I did try and get things going with Arduino and still had some issues, just in testing. Ultimatly I prevailed in Micropython.

As far as documentation, as I said, I found it rather lacking. The most important document I found was the SIM7000 Series AT Manual. It takes a little digging but eventually you will find it helpful. Another helpful resource is the lilygo-micropython repository.

Getting started… slownly

This was kind of a slow start. I got distracted by some older example code in another repository. I never got that code to work, be warned. What I ended up doing was building a micropython image off the lilygo-micropython repository, flashing that to the my ESP32 and then began the troubles.

With limited documentation, I didn’t exactly know how to interact with the GSM or GPS modules. What classes were included, functions, etc. What I ended up doing was digging into the reportory and finding `/extmod/network/at`. Utilizing the at module I was able to kind of start to put together in my mind how to work with the library that was included in the build I had flashed.

Finally, some success… but with the GPS module

So after 2 days of messing around with the GPRS modules and trying to get some sort of connection to the outside world, I decided to give GPS a go and it actually worked right away. Taking the test code from the repo provided a working test example of working with the GPS and ultimatly, I was able to get some GPS data including date, time, and location.

Getting a working data connection

Getting the data connection working was more challengeing. I again leaned on the test directory in the repo and hit a few snags. Running the network test file didn’t do much. It appeared to be connected but I’d never actually been able to see that I was on the network according to my provider. Hologram had a fairly useful document and I decided to break things apart in the network test file and start putting things together is sections. I commented out the loop just to make life easier added a stupid simple function to allow me to send AT commands and see the response easier.

def myT(cmd):
	g.sendCmd(cmd)
	res, data = g.waitResponse()
	print(data)

Very simple but was a valuable tool for poking around a testing the module. Now I could run `myT(“AT+<CMD>")` and just see my response. I noticed that after I removed the loop, some weirdness stopped, I’m not really sure but the loop may have overwhelmed and confused the modem a bit because ocassionally, when the loop was in play and I’d run something, it’d fail sometimes and work others.

So, if you’re following along you’ll see that the bulk of this consists of sending AT commands. Below are what I needed to get things working on my end. This is after a great deal of trial and error and reading the above Sim7000 Series manual.

AT+CFUN=1 = Sets functionality to full
AT+CNMP=38 Sets prefered mode functionality to LTE only
AT+CMNB=1 Sets prefered selection to Cat-M (Note: I don't even know what this means... )
AT+CIPSTATUS Query current connection status
AT+CIPSHUT Deactivate GPRS PDP context
AT+CSTT="hologram" Start task and set APN (Note: APN is Access Point Name from your SIM provider)
AT+CIICR Bring up wireless connection with GPRS
AT+CIFSR Get local IP address
AT+CPSI? Inquiring UE System Information
AT+CGPADDR Show PDP address

The above will get things connected (if everything goes correctly) Side note that Im working on cleaning up my test file and I’ll put it on Github here soon so this makes a bit more sense.

Now is where the real fun begins…. At this point I was able to get a connection to hologram (my sim provider) but I couldn’t hit my server with a request. So I had to do some more digging and ultimatly landed on the following. For clarity sake, I’ll leaving this in python code to show you how I was testing and add in a few notes. You’ll see I also dropped this into a function so I could run it when I was ready to after the above connection was completed. This just gave me a chance to slow things down and look at what I was really worried about.

def myRequest():
	g.sendCmd('''AT+SHREQ?''')
	# Here I'm  checking the request type, this probably isn't required and is probably a holdover from initial testing and experimenting
	res, data = g.waitResponse()
	print(data)

	g.sendCmd('''AT+CNACT=1,"hologram"''')
	# Set APP networik to active....
	res, data = g.waitResponse()
	print(data)

	g.sendCmd('''AT+SHCONF="URL","http://357a-68-162-68-13.ngrok.io"''')
	# That url is down, so don't bother... and yes it's http, https is in the works....
	# SHCONF sets URL parameters. There are a few options here including URL, TIMEOUT, BODYLEN, HEADLEN, IP VERSION, ETC... see the manual for more
	res, data = g.waitResponse()
	print(data)

	g.sendCmd('''AT+SHCONF="BODYLEN",1024''')
	# Same as above. Not sure if these need to be set separatly or if at all... still testing.
	res, data = g.waitResponse()
	print(data)

	g.sendCmd('''AT+SHCONF="HEADERLEN",350''')
	# same as above
	res, data = g.waitResponse()
	print(data)

	g.sendCmd('''AT+SHCONN''')
	res, data = g.waitResponse()
	print(data)

	g.sendCmd('''AT+SHSTATE?''')
	# query the connection state
	res, data = g.waitResponse()
	print(data)

	g.sendCmd('''AT+SHREQ="/api",1''')
	# Read more below on this... this one had me tripped up for a while but this is the RESOURCE you need....
	res, data = g.waitResponse()
	print(data)

	g.sendCmd("AT+SHDISC")
	# Disconnect
	res, data = g.waitResponse()
	print(data)

AT+SHREQ is the resource. I found this question everywhere and eventually realized that the URL is set above with SHCONF and the resource (after the domain name) is set with SHREQ. The 1 here is the request type (GET, POST, ETC)

Conclusion

Well, I don’t think I’m doing much here, honeslty I always feel these posts are useless but after spending nearly two days cobling this together I sure hope it helps someone, or my future self. I’ll post more as I come across it.