mendhak/gpslogger

Custom URL logger to OwnTracks with speed in km/h

Closed this issue · 7 comments

I'm using GPSLogger as a client for my OwnTracks recorder server. I prefer GPSLogger because the android app for OwnTracks is more focused on location sharing and is also not able to log everything to a gpx file.

I use the custom URL logger in POST mode, pointing to the /pub endpoint of my OwnTracks server. The HTTP payload (json):

{
    "_type": "location",
    "lat": %LAT,
    "lon": %LON,
    "vel": %SPD,
    ...
}

It works like a charm, with one totally unnecessary problem: The OwnTracks ecosystem expects the velocity in km/h. They might have reasons for that. But for now, GPSLogger and OwnTracks are incompatible because neither of them is configurable.

I decided to open this issue here because (a) the OwnTracks ecosystem does not really encourage using a third-party app and (b) GPSLogger already works well with custom setups.

I have two ways in mind that I could implement to make this work:

  1. Add another variable to the custom URL logger like %SPEED_KMH (%SPD_KMH would probably not work, as replacing %SPD might run first, right?). This would be a very small change. Though, having different variables for different units might clutter this functionality.
  2. Add a setting for the custom URL logger to make the unit configurable. The setting could include "m/s", "km/h" and maybe even "mph" or "knots". And depending on what the user has selected, %SPD will be replaced by the converted value.

Tell me what you think about this. I tend towards the second option. But no matter what we decide, I can implement it and open a pull request afterwards.

I think I understand, did I get it right: although OwnTracks wants you to use their clients, GPSLogger is thiiiiis close to letting you use it as an unofficial client to push locations.

I think I won't mind the first option in a PR, which is a specific variable just for this. The variables list is already 'cluttered', and it has some duplicates for other things too, so one more is fine. Introducing per-variable configuration can get confusing.

I'd prefer the name %SPD_KPH and it shouldn't be a problem having that "SPD" overlap, just put SPD_KPH in the replacement block before SPD. Here's an example with TIMESTAMP before TIME.

https://github.com/mendhak/gpslogger/blob/master/gpslogger/src/main/java/com/mendhak/gpslogger/senders/customurl/CustomUrlManager.java#L220-L229

One more thing, because I'm introducing a big change, please could you do your PR against this branch: android_workmanager. As you can see in this PR,
I'm switching to WorkManager so I'd like to test them together.

Now I have some questions. OwnTracks looks interesting, how strange that I'm only aware of it now (it's been mentioned before but I never searched for it). Do you host it yourself? I think there's a map feature which you can host on a custom domain, does it come with authentication? It looks like something you could use on a walking holiday to share your location or just view for yourself.

Thanks for the insights! And yes, you got it right. With the correct unit of speed, GPSLogger would be a perfect unofficial client.

I missed that you're using a LinkedHashMap which has a predictable iteration order. So, I will implement %SPD_KPH as a new variable and create the PR against that branch. No problem!

As for OwnTracks: (disclaimer: I'm new to OwnTracks, so the following might not be 100% correct)

The core of OwnTracks is the recorder. It's a server that accepts and delivers JSON. You can publish your location and query different users, devices, timespans, regions and whatever (either by http, mqtt or command-line tooling). The frontend makes use of this data and provides a simple web-ui with a map. They provide docker images which I selfhost. I think you can configure some authentication, but I already have everything behind an nginx reverse proxy that requires basic auth.

I want to use this setup to publish my location during day trips so my friends and family can see where I am in realtime (log interval < 60s) on a very simple map.

Test APK is here:

https://github.com/mendhak/gpslogger/releases/tag/v131-rc2

Note that if you use the FDroid version of this app, installing this is like new, so you'll lose previous data and settings.

Ah I tried setting up OwnTracks in Docker today but gave up.

The quickstart instructions didn't work, and the docker-compose-mqtt.yml didn't work either. The recorder is either unable to find the MQTT or connection gets refused.

Do you happen to have a working docker command or docker compose? If you happen to have one could you share it (it's OK if not, I'm mostly looking out of curiosity).

I also had troubles to set up docker and nginx on my server, but with some copy and paste from different guides I finally got it working.

~/owntracks/config/config.js (must exist before starting the frontend container)

// Here you can overwite the default configuration values
window.owntracks = window.owntracks || {};
window.owntracks.config = {
	api: {
    		baseUrl: "https://[mydomain]/owntracks/",
	},
	router: {
    		basePath: "/owntracks",
	},
};

~/owntracks/docker-compose.yml

services:
  owntracks-ui:
    image: owntracks/frontend
    ports:
      - 127.0.0.1:7000:80
    volumes:
      - ./config/config.js:/usr/share/nginx/html/config/config.js
    environment:
      - SERVER_HOST=otrecorder
      - SERVER_PORT=8083
    restart: unless-stopped
  owntracks-recorder:
    container_name: otrecorder
    image: owntracks/recorder
    environment:
      - OTR_PORT=0  # disables MQTT
    volumes:
      - ./recorder/store:/store
      - ./recorder/config:/config
    ports:
      - 127.0.0.1:8083:8083
    restart: unless-stopped

nginx location fragments

   location /owntracks/ {
        proxy_pass http://127.0.0.1:7000/;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_request_buffering off;
        proxy_buffering off;
   }
   location /owntracks/ws {
        proxy_pass http://127.0.0.1:7000/;
        rewrite ^/owntracks/(.*)    /$1 break;
        proxy_http_version  1.1;
        proxy_set_header    Upgrade $http_upgrade;
        proxy_set_header    Connection "upgrade";
        proxy_set_header    Host $host;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
   }
   location /owntracks/pub {
	# send directly to recorder server
        proxy_pass http://127.0.0.1:8083/;
        rewrite ^/owntracks/(.*)    /$1 break;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_request_buffering off;
        proxy_buffering off;
   }

I also had to create some folders because the recorder wasn't able to find stuff (maybe they get generated by publishing locations, but I tried the frontend first, so maybe it was just me)

  • ~/owntracks/recorder/store/last
  • ~/owntracks/recorder/store/rec

But with this setup I'm now able to view the map at https://[mydomain]/owntracks/ and publish my locations to https://[mydomain]/owntracks/pub.

Yes that's it thanks! Finally got it working! The OTR_PORT=0 was the crucial missing bit, the docker image kept failing and I couldn't figure out from the docs what was missing, that was it.

For future reference my docker compose

services:
  owntracks-ui:
    image: owntracks/frontend
    ports:
      - 0.0.0.0:7000:80
    volumes:
      - ${PWD}/config.js:/usr/share/nginx/html/config/config.js
    environment:
      - SERVER_HOST=otrecorder
      - SERVER_PORT=8083
    restart: unless-stopped
  owntracks-recorder:
    container_name: otrecorder
    image: owntracks/recorder
    environment:
      - OTR_PORT=0  # disables MQTT
    volumes:
      - ./recorder/store:/store
      - ./recorder/config:/config
    ports:
      - 0.0.0.0:8083:8083
    restart: unless-stopped

config.js

// Here you can overwite the default configuration values
window.owntracks = window.owntracks || {};
window.owntracks.config = {
	api: {
    		baseUrl: "https://localhost:8083/owntracks/",
	},
	router: {
    		basePath: "/owntracks",
	},
};

In GPSLogger:

URL: http://192.x.x.x:8083/pub?u=user&d=device1
HTTP Body:

{ "_type": "location", 
  "t": "u",
  "lon": %LON,
  "lat": %LAT,
  "tid": "test",
  "tst": %TIMESTAMP,
  "batt": %BATT,
  "cog": %DIR,
  "vel": %SPD_KPH,
  "topic": "owntracks/user/device1"
}

HTTP Headers: Content-Type: application/json

HTTP Method: POST


I'll have a play with this at some point and maybe even see if I could put some Cloudflare in front of this. eg, the UI authentication via OAuth, and somehow if I can get the /pub endpoint via different authentication mechanism. Make the IPs local, run it on a Raspberry Pi, etc.

v131 is in the releases and FDroid