Calculation of distance using latitude and longitude information from user and home

Hi all,

as you perhaps also tried at sometime (like me) to get a distance information (user <> home) using latitude / longitude information (e.g. from OwnTracks), I would like to share my realization, how I finally solved this issue. If someone has an idea to improve this rule, please let me know - but so far it works fine already.

The formula behind this calculation I took from here.

``````rule OwnTrack: Distance User <> Home

when
Item OwnTrackUserLatitude changed or
Item OwnTrackUserLongitude changed

then

var Number LatitudeHome = xx.xxxxxx
var Number LongitudeHome = yy.yyyyyy

var Number LatitudeUser = (OwnTrackUserLatitude.state as DecimalType).doubleValue
var Number LongitudeUser = (OwnTrackUserLongitude.state as DecimalType).doubleValue

var Number pi80 = Math::PI / 180.0

var Number LatitudeHomePi = LatitudeHome * pi80
var Number LongitudeHomePi = LongitudeHome * pi80
var Number LatitudeUserPi = LatitudeUser * pi80
var Number LongitudeUserPi = LongitudeUser * pi80

var Number LatitudeDifferencePi = LatitudeUserPi - LatitudeHomePi
var Number LongitudeDifferencePi = LongitudeUserPi - LongitudeHomePi

var Number a = Math::sin((LatitudeDifferencePi / 2).doubleValue()) * Math::sin((LatitudeDifferencePi / 2).doubleValue()) + Math::cos(LatitudeHomePi.doubleValue()) * Math::cos(LatitudeUserPi.doubleValue()) * Math::sin((LongitudeDifferencePi / 2).doubleValue()) * Math::sin((LongitudeDifferencePi / 2).doubleValue())
var Number c = 2 * Math::atan2(Math::sqrt(a.doubleValue()), Math::sqrt(1 - a.doubleValue()))
var Number km = Earthradius * c

sendCommand(OwnTrackUserDistance, km)
end``````
1 Like

Use `PointType.distanceFrom(PointType)`:

``````import org.openhab.core.library.types.PointType

rule SetOwnTracksLocation
when
Item OwnTrackUserLatitude changed or
Item OwnTrackUserLongitude changed
then
val PointType homeLocation = new PointType("xx.xxxxxx,yy.yyyyyy")
val PointType newLocation = new PointType(OwnTrackUserLatitude.state, OwnTrackUserLatitude.state)
OwnTrackUserDistance.postUpdate(newLocation.distanceFrom(homeLocation))
end
``````
2 Likes

The â€śPointType itemâ€ť is a great feature.
But it is still not really documented. I am using it in a combination with my networkhealth item,
If i am at home: Set my distance to zero.

But which unit has the distance?
Should be metric, i suppose.
Is it possible to transform that distances below 5000 meters are printed as meters, above 5000 meters as kilometers and below 1000 meters displayed as a float (.1f)

below 1000 and 1000-4999,99 Meters could be formatted using two text items and the [visibilityâ€¦] switch in the sitemap.

In the example above your post, the item `OwnTrackUserDistance` is a `Number` item, so your rule might look like:

``````rule IAmHome
when
Item MyPhoneIsHome changed to ON
then
OwnTrackUserDistance.postUpdate(0)
end
``````

The return value from `aPoint.distanceFrom(anotherPoint)` is meters. So you could have a `String` item named `DistanceFromHome` and a rule like this (untested):

``````rule DistanceChanged
when
Item OwnTracksUserDistance changed
then
var Number m = OwnTracksUserDistance.state as DecimalType
var Number km = m / 1000
// if you use miles and feet, just multiply by conversion factors
switch m {
case 0 : readable = "I'm home!"
case m < 1000 : readable = String::format("%.1fm", m)
case m < 5000 : readable = String::format("%.0fm", m)
case m >= 5000 : readable = String::format("%.1fkm", km)
}
}
``````
2 Likes

Thanks,

small modification was needed, but now it works (i added .floatValue() behind the values in meters)
There was an unused Bracket } and the missing end parameter

``````rule "User 2 Distancce changed"
when
Item mqttDistU2toHome changed
then
var Number m = mqttDistU2toHome.state as DecimalType
var Number km = m / 1000
// if you use miles and feet, just multiply by conversion factors
switch m {
case 0 : readable = "Zuhause!"
case m < 1000 : readable = String::format("%.1fm", m.floatValue())
case m < 5000 : readable = String::format("%.0fm", m.floatValue())
case m >= 5000 : readable = String::format("%.1fkm", km)
}