I enjoy exploring the city I live in (vienna) by walking it's streets. However, I have noticed a tendency to always walk the same routes. Especially when I am not actively going somewhere my mind seems to always choose the same old routes, which is of course not what I want. The solution that I have come up with is to record my location data and render something like a heatmap of my location history. This way I would have a clear visualisitaion of the routes I have traveled often and where I haven't gone at all.
Since I would like to be in control of my data as much as possible the obvious choice is to host the solution myself. Essentially, I would need two parts, some kind of app that records the data and a server that receives it and creates the visualization.
Owntracks is a open source app, available for both Android and IOS. It does exactly what I need: record gps data and send it to a server. Owntracks supports two formats, MQTT and HTTP. HTTP is espcecially usefull, since it allows me two code up a server in minutes that can receive the JSON data POST'ed from the app.
I decided to implement my server app in Node.js and Express with a Sqlite database as the persistance layer.
First, I created a database schema:
CREATE TABLE IF NOT EXISTS locations
(
id INTEGER PRIMARY KEY,
tid TEXT NOT NULL, -- tracker id, identifies the device
lat REAL NOT NULL, -- latitude
lon REAL NOT NULL, -- longitude
tst INTEGER NOT NULL UNIQUE -- timestamp, only one datapoint per tst allowed
)
Here we receive the POST'ed data and save it to Sqlite3:
// Save location data in database.
app.post('*', async (req, res, next) => {
try {
const data = req.body;
// we only care about 'location' messages
if (data && data._type === "location") {
const sql = `INSERT INTO locations (lat, lon, tst, tid) VALUES (?, ?, ?, ?)`;
await run(sql, [data.lat, data.lon, data.tst, data.tid]);
}
// Owntracks expects an empty json array as reponse.
return res.status(200).json([]);
} catch (err) {
// Owntracks sometimes repeats messages. Already saved timestamp/location
// tuples shall be ignored.
if (err.code == "SQLITE_CONSTRAINT") {
console.error(err.code);
return res.status(200).json([]);
} else {
console.error(err);
return res.status(400).send("something went wrong");
}
}
});
You can find the full sourcecode here.
Now that we have collected all this data I would like to analyze it. It would be interested to have a kind of heatmap, preferably interactive, to show where I spend most of my time. Fortunatly for me, there is already heatmap.js, a leaflet overlay for generating something like this.
So I quickly add a endpoint for getting the location data from the database and voila: