[SOLVED] Reverse Geocode GPS tracker location

Does anyone know an easy way in OH3 to reverse geocode the location channel of a GPStracker Thing?
The channel returns GPS coordinates, but I’d need the address corresponding to that location.

You can try to use the exec binding or the http binding.
A request with wget would look like:

wget "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode?f=pjson&featureTypes=&location=-0.1249710976555222,51.526172028215704" -O result.txt

Result would be:

{
 "address": {
  "Match_addr": "37 Tavistock Place, London, England, WC1H 9",
  "LongLabel": "37 Tavistock Place, London, England, WC1H 9, GBR",
  "ShortLabel": "37 Tavistock Place",
  "Addr_type": "PointAddress",
  "Type": "",
  "PlaceName": "",
  "AddNum": "37",
  "Address": "37 Tavistock Place",
  "Block": "",
  "Sector": "",
  "Neighborhood": "",
  "District": "",
  "City": "London",
  "MetroArea": "",
  "Subregion": "London",
  "Region": "England",
  "Territory": "",
  "Postal": "WC1H 9",
  "PostalExt": "",
  "CountryCode": "GBR"
 },
 "location": {
  "x": -0.1249710976555222,
  "y": 51.526172028215704,
  "spatialReference": {
   "wkid": 4326,
   "latestWkid": 4326
  }
 }
}

The GPS coordinates are dynamic and stored in an item.
I do not know how I can use the value of an item in the exec command of another thing.
Item = GPSTracker_Address
Channel/item containing the GPS coordinates is GPSTracker_Location

You can use the API-Explorer ( in the administration area ) to construct the curl command that can be used to get the value from the item. That curl command then can be used in the exec binding.

Command looks like:

curl -X GET "http://pi:8080/rest/items/YourItemNameHere/state" -H  "accept: text/plain"

In case access is denied you have to set and use an Authorization Bearer token.

I create a rule in OH3 web frontend with trigger GPSTracker_Location changed

then I run a python script

> # importing modules
> from geopy.geocoders import Nominatim
> 
> # calling the nominatim tool
> geoLoc = Nominatim(user_agent="GetLoc")
> 
> # passing the coordinates
> latlon = ir.getItem("GPSTracker_location").state
> locname = geoLoc.reverse(latlon,language="nl",addressdetails=True)
> 
> # printing the address/location name
> parts = locname.address.split(", ")
> #print(parts[0] + " " + parts[6] + " " + parts[2] + " " + parts[7])
> #print(locname.address)
> 
> events.postUpdate("GPSTrackerSB_Address", parts[0] + " " + parts[6] + " " + parts[2] + " " + parts[7])

This gives below error:
Script execution of rule with UID ‘fb61159892’ failed: ImportError: No module named geopy in at line number 2

While geopy has been installed under current user and openhab user

Who can help

This is python from the helper libraries ?
See Reference — openHAB Helper Libraries documentation resp. Reference — openHAB Helper Libraries documentation about the location where to put additional modules.

Specifying the geopy path does resolve the error.
Only error remaining now:

2021-09-17 11:59:46.567 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID ‘fb61159892’ failed: org.python.antlr.ParseException: org.python.antlr.ParseException: encoding declaration in Unicode string

My script so far

#!/usr/bin/python
# encoding: utf-8

#importing modules
import os, sys
sys.path.append("/usr/local/lib/python3.7/dist-packages")
from geopy.geocoders import Nominatim

# calling the nominatim tool
geoLoc = Nominatim(user_agent="GetLoc")

# passing the coordinates
lalo = ir.getItem("GPSTracker_location").state
# location item returns "4.13°N 52.23°E 0m” thus converting it to 4.13,52.23
lat = lalo.split("°N ")
lon = lat[1].split("°E ")
latlon = str(lat[0]) + "," + str(lon[0])
locname = geoLoc.reverse(latlon,language="nl",addressdetails=True)

# printing the address/location name
parts = locname.address.split(", ")
events.postUpdate("GPSTrackerSB_Address", str(parts[0]) + " " + str(parts[6]) + " " + str(parts[2]) + " " + str(parts[7]))

Does it have to be

or
# -*- coding: utf-8 -*-

Is the problem in the lines with the degree symbol ?

I guess so.
changing encoding to your proposal gives the same error

Would it work to split on space and cut of the last two characters ?

Chanbging to

# passing the coordinates
lalo = ir.getItem("GPSTrackerSB_locatie").state
# ir.getItem("GPSTrackerSB_locatie").state returns "4.13°N 52.23°E 0m” => converting it to 4.13,52.23
lat = lalo.split(" ")
la = str(lat[0])[:-2]
lon = lat[1].split(" ")
lo = str(lon[0])[:-2]
latlon = la + "," + lo
# latlon is now a string in format 4.13,52.23
locname = geoLoc.reverse(latlon,language="nl",addressdetails=True)

gives the same error

When running the same py script from terminal it does work :smirk:
Must have something to do with the Jython implementation

you may have a look to this thread/post ( No international characters (Unicode) with jsr223 / Jython? - #12 by cris ). There are a few more suggestions.

Already did, but can’t get the issue solved. A pity since the geopy library is easy and practical. Will have to look for another means

geopy looks to be Python3. Jython is Python2.7 only, unfortunately.

Indeed that seems to be the problem. Abandoning the python path

You can use your script and execute it via the exec binding. The python part should work what is missing would be getting the item stateof your GPS tracker and returning the result.

Problem solved with ECMAScript rule

var Transformation = Java.type("org.openhab.core.transform.actions.Transformation")

var lalo = itemRegistry.getItem(“GPSTracker_Location").getState().toString();
var lat = lalo.split(",")[0].toString();
var lon = lalo.split(",")[1].toString();

var url = "https://nominatim.openstreetmap.org/reverse?format=json&lat=" + parseFloat(lat) + "&lon=" + parseFloat(lon) + "&accept-language=nl&addressdetails=1";

var HttpUtil = Java.type("org.openhab.core.io.net.http.HttpUtil");
var response = HttpUtil.executeUrl("GET", url, 2000);

var straat = Transformation.transform("JSONPATH", "$.address.road", response);
var postcode = Transformation.transform("JSONPATH", "$.address.postcode", response);
var gemeente = Transformation.transform("JSONPATH", "$.address.town", response);
var land = Transformation.transform("JSONPATH", "$.address.country", response);
if(land == "België") {
   land = "";
}
var address = straat + " " + postcode + " " + gemeente + " " + land;

events.postUpdate("GPSTracker_Address", address.toString());
1 Like