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
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
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)
}
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
Hey everyone, I hope it’s ok if I pick up this old topic again as at least it nearly matches what I do… but looks like I’m to stupid to really understand what I have to do. Already found numerous thread here, the documentation and some other boards… But I can’t manage to find what I really have to create.
I’m very sorry I think it’s easy but I’m not able to manage it on my own.
I have to items. Both are location items.
Standort_Zuhause > Location of my house
Mercedes_Position > Current location of my car
What I want to do now is to check the distance between both locations and if the distance is lower than let’s they 10 meters I want something to happen for example sending a push.
As a trigger for the rule I of couse I can use change of “Mercedes_Position” item.But maybe this will create a lot of traffic as driving the car would result in continues rule triggers.
Second thing is how I define the rule itself? So how to check the distance between both iteam and how I define the value that the distacne has to go below of.
Already found that PointType could help but didn’t understood how.
This is how I set a switch to indicate if our car is at home or not:
rule "Zoe Home"
when
Item ZOE_Location changed
then
val String ZOE_position_north = ZOE_Location.state.toString.split(",").get(0)
val String ZOE_position_east = ZOE_Location.state.toString.split(",").get(1)
val PointType home_location_point = new PointType(new DecimalType(53.xxxxxx), new DecimalType( 7.yyyyyy))
val PointType Zoe_location_point = new PointType(new DecimalType(ZOE_position_north), new DecimalType(ZOE_position_east))
val int distance = Zoe_location_point.distanceFrom(home_location_point).intValue()
if ( distance < 50) {
ZOE_Home.postUpdate(ON)
} else {
ZOE_Home.postUpdate(OFF)
}
end