So here´s the rule i´m using to reverse lookup the coordinates to an address and changing the presence.
Items:
Location iPMichael_Location "Ort" <map> (iPhones, gPersist) {channel="icloud:device:openHAB:iPMichael:location"}
String iPMichael_Address "Ort [%s]" <map> (iPhones, gPersist)
Switch iPMichael_Home "Michael Home [%s]" (iPhones, gPersist)
Rule:
// Reverse address lookup with OpenStreetmap
// https://wiki.openstreetmap.org/wiki/Nominatim#Reverse_Geocoding
// Function called to lookup address from a Location type item
// It assumes that the item
val Functions$Function1<GenericItem, String> lookupAddress= [ iPMichael_Location |
// get lat lon from item
val PointType location = iPMichael_Location.state as PointType
val String lat = location.latitude.toString
val String lon = location.longitude.toString
// build request
val String endpoint = 'https://nominatim.openstreetmap.org/reverse'
val String lang = 'de-DE'
val String query = 'lat=' + lat + '&lon=' + lon + '&accept-language=' + lang + '&format=json&addressdetails=1'
val String request = endpoint + '?' + query
// get result
val String result = sendHttpGetRequest(request)
// logInfo("lookupAddress", result)
var String road = transform("JSONPATH", "$.address.road", result)
var String house = transform("JSONPATH", "$.address.house_number", result)
var String city = transform("JSONPATH", "$.address.city", result)
var String town = transform("JSONPATH", "$.address.town", result)
var String country = transform("JSONPATH", "$.address.country", result)
var String hide = 'Deutschland' // in result language; hide your home country
// Empty the Strings if they´re not part of the result and the full result was put into the Strings
if(road.startsWith("{"))
{
road = ''
}
if(house.startsWith("{"))
{
house = ''
}
if(town.startsWith("{"))
{
town = ''
}
if(city.startsWith("{"))
{
city = ''
}
if(country.startsWith("{"))
{
country = ''
}
// Check if city is empty and fill in town
if(city == '')
{
city = town
}
// Check if city is still empty and fill Unknown
if(city == '')
{
city = 'Unknown'
}
var String address = road + ' ' + house + ', ' + city
// Check if the address starts with comma and only use the city
if(address.startsWith(",") || address.startsWith(" ,"))
{
address = '' + city
}
if (country != hide) {
address = address + ', ' + country
}
return address
]
rule "Michael Zuhause"
when
Item iPMichael_Location changed
then
// Definition von Zuhause und aktueller Standort
val PointType homeLocation = new PointType(new DecimalType(<Latitude>), new DecimalType(<Longitude>))
val PointType phoneLocation = iPMichael_Location.state as PointType
val int distance = phoneLocation.distanceFrom(homeLocation).intValue()
// Remove _Location from the triggering item and add _Address
val String updateItem = triggeringItem.name.toString.split("_Location").get(0) + '_Address'
// Fill in the address into the item
postUpdate(updateItem, lookupAddress.apply(triggeringItem))
if(distance < 150)
{
iPMichael_Home.postUpdate(ON)
logDebug("MichaelHome", "Michael is at home")
}
else
{
iPMichael_Home.postUpdate(OFF)
logDebug("MichaelHome", "Michael is gone")
}
end
I´ve to correct this…
You´re right, the Location isn´t stored with persistence!
It´s because the Location consists of multiple strings (Latitude, Longitude, Altitude).
The only way is to write a rule to store them in parts and another rule to restore them if needed.
Just a quick rule to get the parts of an Location value:
rule "Michael Location split"
when
Item iPMichael_Location changed
then
val String Latitude = triggeringItem.state.toString.split(",").get(0)
val String Longitude = triggeringItem.state.toString.split(",").get(1)
val String Altitude = triggeringItem.state.toString.split(",").get(2)
Michael_Latitude.postUpdate(Latitude)
Michael_Longitude.postUpdate(Longitude)
Michael_Altitude.postUpdate(Altitude)
Thread::sleep(100)
Michael_Latitude.persist
Michael_Longitude.persist
Michael_Altitude.persist
end
kind regards
Michael