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 Earthradius = 6372.797 

		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 String readable = "hmmm...."
  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)
  }
  DistanceFromHome.postUpdate(readable)
}
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 String readable = "hmmm...."
  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)
  }
  mqttDistU2toHomeTXT.postUpdate(readable)
end
1 Like

Is this pseudo language or do these variables (OwnTrackUserDistance, etc.) exist?

[edit:]
Sorry, got it… it is just a freely named variable name.