Friday, 19 August 2016

ESP8266 Geolocation

The ESP8266 device, used as the heart and soul of my new beacon, knows its place in the world...

This post describes a couple of techniques for 'Geolocation' on the ESP8266 and uses them to derive the location information my beacon needs to broadcast (e.g.) a valid WSPR message.

Readers may remember I grafted a GPS module onto an earlier beacon system here in the shack - mainly for time synchronization - but don't know how much trouble I had with it (a north facing window made GPS reception VERY difficult).

Having my new beacon sat on the 'Internet of Things' opens up a new possibility for obtaining not just time (which I've already reported) but also position information, using geolocation. So - I decided this was a worthy avenue for experiment, both for the practical end of getting the location by other means than GPS and as an interesting learning exercise.

It turns out that Geolocation, by the methods I'll describe below, is a standard alternative to positioning via GPS in those places where a satellite signal cannot be obtained (indoors, underground etc.).

I'll describe two broad methods - and present working ESP8266 code to illustrate each.

The first uses your own IP address to provide a rough estimate of location, using a service such as Freegeoip. Adafruit has posted a very good example of how to use this service here and I've modified their code to provide a stand-alone application for the ESP8266.

The code on the github link above is presented as a sketch for the Arduino IDE. You'll need to modify it to include your own WiFi network's ssid and password before it will work. It will print the results into a Serial Monitor window (at 115200 baud).

I included an elaborated version of this code in my beacon, to generate the following location estimates on the little screen...

Clearly, it knows I'm in Manchester (!), but the map reference turns out to be quite a bit off...

It places me at a location about 8 km away from my actual QTH, as seen in the map above (the erroneous location is seen - not my home - this isn't an invitation for thieves).

All this might not matter too much, but for the fact that it is actually in the wrong (six-character) Maidenhead locator square...

This shows an incorrect placement in IO83uk when actually I'm in IO83tk.

Not too serious - but a reflection of the poor absolute accuracy of the location estimation afforded using this first IP-based Geolocation method. Remember - it is 8km out. In fact, as I write, is returning a location estimate which is much poorer than that - bang in the middle of London!

An alternative method clearly is needed to accurately resolve the correct locator square.

The second method, known as the WiFi positioning system or WPS, uses a scan of all the WiFi Access Points visible to the ESP8266. The result of this scan is uploaded to a Geolocation API, such as those offered by Google or Mozilla.

Both these services are entirely free to use, but Google make you jump through a lot of hoops to get an API Key. Mozilla is hoop-free.

I've written some code which shows how to access these services using the ESP8266 here.

The important part of the sketch is shown in this extract...

After setting up the important credentials for accessing the API (Host, Page and access key), the HTTPS client needs to be instantiated (it needs to be the Secure version of the WiFi client - so this won't be easy or even possible to run on a lesser processor than the ESP8266).

After this, the POST is fairly conventional (see, for example, the example at the bottom of this page) but it did take me a long time to figure out exactly how to get it working!

Here's the beginning of the result of the WiFi scan, as produced at my QTH, showing some of the WAPs visible here...

It is in the JSON format produced by the code and required for submission to the Geolocation APIs.

WPS databases operate in context of the mobile telephone industry and require that the header includes some parameters which spoof the API into believing that the request is coming from a mobile device with GSM capability. I used a Mobile Country Code and Network Code associated with a local network provider in the UK (which I looked up in a table). If you're not in the UK, you should probably choose a different MCC and MNC.

I also used the ArduinoJson library to handle the result from the Geolocation API.

With this method, location results have an accuracy of order metres, so an elaborated version of the code was implemented in my little proto-beacon...

Now we're in the building (actually, we're in a house at the bottom of my garden, but that sort of error I can live with).

With location and time (from the NTP servers, as previously reported) I have all the ingredients required to automatically generate a WSPR message, instead of going through the chore of generating it ahead of time in a command-line utility on the PC and uploading it as a constant into the beacon...

I looked at Gene, w3pm's on-line materials, among which are several Arduino sketches including a function 'void wsprGenCode()' which generates WSPR messages. This works perfectly well, but calls several other functions and isn't the easiest item to work with.

Fortunately, a further quick search produced John Newcombe's elegant WsprMessage c++ class, which I am now using. It is producing my WSPR message very efficiently...

Credit where it is due: both Gene's function(s) and John's class (/library) draw heavily on the work of Andy Talbot, g4jnt, who has produced a detailed explanation of the WSPR coding process.

The entire beacon now is literally turn-on and go, in any location with a WiFi connection. It ran last night on 30m with an unusually strong performance into S America...

although this seemed to be at the expense of contacts into the antipodes.

I hope others are as excited by this collision between amateur radio and the Internet of Things as I am - it seems alive with possibilities.

...-.- de m0xpd

1 comment:

  1. I'm bemused as to why the GPS was so inaccurate, would it benefit perhaps from an external antenna?

    I use a U-Blox Neo as a frequency reference with a tiny, magnetic external patch antenna and it 'knows' if I've moved it from one side of the roof to the other, a distance of only ~3 metres.

    I'm also loath to encourage Google et al to gather and use WiFi location methods.