Distance to flying Object

Hello
i need some help to calculate the Distance to a flying Object
the homePos would be Fix the satPos would be changing (of course)

var SatDistance = ??? satPos to homePos ???

homePos:
lat: 47.28779
lng: 7.94586
altitude: 450m

satPos: object
lat: 44.92328212186796
lng: 15.170434085073536
alt: 572.0248134159765

but i just have no idea how to do this math and hold the meter or kilometer into the var

would be happy for some help

have a nice day
vinc

You need to apply a haversine formula. Here is an such example..

function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2) {
  var R = 6371; // Radius of the earth in km
  var dLat = deg2rad(lat2-lat1);  // deg2rad below
  var dLon = deg2rad(lon2-lon1); 
  var a = 
    Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * 
    Math.sin(dLon/2) * Math.sin(dLon/2)
    ; 
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
  var d = R * c; // Distance in km
  return d;
}

function deg2rad(deg) {
  return deg * (Math.PI/180)
}

Taken from here.

Send your two sets of coordinates to the function.

1 Like

i will try to add it. but you don't have used the altitude so a bit confused.

I think that also assumes that the Earth is a globe? (no I'm not implying that it is FLAT!) In fact, it is an oblique spheroid. Depending where you are on the Earth and how accurate you need the calculation to be, not sure if that might be important.

Maybe this might help? python - Calculating distance between two points using latitude longitude and altitude (elevation) - Stack Overflow. I just did a Google search and that was the first result.

1 Like

ok im happy the earth is not flat :wink:

i have tryied to add it like this

var lat1            = 47.28779;
var lon1            = 7.94586; 
var lat2            = msg.payload[0].satPos.lat; 
var lon2            = msg.payload[0].satPos.lng;
var distanze       = function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2) {
  var R = 6371; // Radius of the earth i.................

and yes i got just to formel and not the result so something need to be changed i have tryied to add it between the ' ' but no change

Without you sharing the full code, hard to say what is wrong. Though you haven't actually called the function in the snippet you shared.

Here is the technical stuff about the great circle calculation: Great-circle distance - Wikipedia - In it, it notes that using a mean radius of 637100.9 m minimises the spheroid error.

Probably best to do some more searching on t'internet since I found quite a few possible answers even with helpful code.

I think you missed a zero there! Either that or you're doing the calculations for an asteroid :smiley: Nothing like a bit of celestial nav to exercise the old brain cells...

Drat, trying to be clever on a Friday evening certainly not a good idea! :grinning:

@molesworth i do calculate the distance to a satellite not a asteroid
@TotallyInformation for the Grat circle distance i think i missed some class for that.

my Problem is the
var distanze = function.....

the function is not calculated and there to show it with disanze, when is outpt distance it show the formula it self

To call the function you just use
var distanze = getLat...( . )
You only use the word function when defining it.

Ah, I was just joking with @TotallyInformation that his Earth radius was 10 times too small - more the size of an asteroid than a planet :wink:

If you're calculating the distance to a satellite you will need to include altitude in the calculation, otherwise you will just get the distance to the point on the Earth directly beneath it. Of course, depending on what reult you actually want...

Did you solve this?

Here is a solution (including elevation) based on this: https://javascript.plainenglish.io/calculating-azimuth-distance-and-altitude-from-a-pair-of-gps-locations-36b4325d8ab0

[{"id":"8035c186.ff4e3","type":"inject","z":"dd03fa8d.2f4be8","name":"{\"from\":{\"lat\":51,\"lon\":0.1,\"elv\":0},\"to\":{\"lat\":50.99,\"lon\":0.11,\"elv\":12}}","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"to","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"from\":{\"lat\":51,\"lon\":0.1,\"elv\":0},\"to\":{\"lat\":50.99,\"lon\":0.11,\"elv\":12}}","payloadType":"json","x":500,"y":900,"wires":[["a3a3aa25.e2e358"]]},{"id":"a3a3aa25.e2e358","type":"function","z":"dd03fa8d.2f4be8","name":"calculate distance between 2 coords","func":"//Credit: https://javascript.plainenglish.io/calculating-azimuth-distance-and-altitude-from-a-pair-of-gps-locations-36b4325d8ab0\n\nfunction ParseAngle(ang, limit) {\n    var angle = parseFloat(ang);\n    if (isNaN(angle) || (angle < -limit) || (angle > limit)) {\n        node.error(\"Invalid angle value.\", msg);\n        return null;\n    } else {\n        return angle;\n    }\n}\n\nfunction ParseElevation(el) {\n    var angle = parseFloat(el);\n    if (isNaN(angle)) {\n        node.error(\"Invalid elevation value.\", msg);\n        return null;\n    } else {\n        return angle;\n    }\n}\n\nfunction ParseLocation(pos) {\n    var lat = ParseAngle(pos.lat, 90.0);\n    var location = null;\n    if (lat != null) {\n        var lon = ParseAngle(pos.lon, 180.0);\n        if (lon != null) {\n            var elv = ParseElevation(pos.elv);\n            if (elv != null) {\n                location = { lat: lat, lon: lon, elv: elv };\n            }\n        }\n    }\n    return location;\n}\n\nfunction EarthRadiusInMeters(latitudeRadians) {\n    // latitudeRadians is geodetic, i.e. that reported by GPS.\n    // http://en.wikipedia.org/wiki/Earth_radius\n    var a = 6378137.0;  // equatorial radius in meters\n    var b = 6356752.3;  // polar radius in meters\n    var cos = Math.cos(latitudeRadians);\n    var sin = Math.sin(latitudeRadians);\n    var t1 = a * a * cos;\n    var t2 = b * b * sin;\n    var t3 = a * cos;\n    var t4 = b * sin;\n    return Math.sqrt((t1 * t1 + t2 * t2) / (t3 * t3 + t4 * t4));\n}\n\nfunction GeocentricLatitude(lat) {\n    // Convert geodetic latitude 'lat' to a geocentric latitude 'clat'.\n    // Geodetic latitude is the latitude as given by GPS.\n    // Geocentric latitude is the angle measured from center of Earth between a point and the equator.\n    // https://en.wikipedia.org/wiki/Latitude#Geocentric_latitude\n    var e2 = 0.00669437999014;\n    var clat = Math.atan((1.0 - e2) * Math.tan(lat));\n    return clat;\n}\n\nfunction LocationToPoint(c) {\n    // Convert (lat, lon, elv) to (x, y, z).\n    var lat = c.lat * Math.PI / 180.0;\n    var lon = c.lon * Math.PI / 180.0;\n    var radius = EarthRadiusInMeters(lat);\n    var clat = GeocentricLatitude(lat);\n\n    var cosLon = Math.cos(lon);\n    var sinLon = Math.sin(lon);\n    var cosLat = Math.cos(clat);\n    var sinLat = Math.sin(clat);\n    var x = radius * cosLon * cosLat;\n    var y = radius * sinLon * cosLat;\n    var z = radius * sinLat;\n\n    // We used geocentric latitude to calculate (x,y,z) on the Earth's ellipsoid.\n    // Now we use geodetic latitude to calculate normal vector from the surface, to correct for elevation.\n    var cosGlat = Math.cos(lat);\n    var sinGlat = Math.sin(lat);\n\n    var nx = cosGlat * cosLon;\n    var ny = cosGlat * sinLon;\n    var nz = sinGlat;\n\n    x += c.elv * nx;\n    y += c.elv * ny;\n    z += c.elv * nz;\n\n    return { x: x, y: y, z: z, radius: radius, nx: nx, ny: ny, nz: nz };\n}\n\nfunction Distance(ap, bp) {\n    var dx = ap.x - bp.x;\n    var dy = ap.y - bp.y;\n    var dz = ap.z - bp.z;\n    return Math.sqrt(dx * dx + dy * dy + dz * dz);\n}\n\nfunction RotateGlobe(b, a, bradius, aradius) {\n    // Get modified coordinates of 'b' by rotating the globe so that 'a' is at lat=0, lon=0.\n    var br = { lat: b.lat, lon: (b.lon - a.lon), elv: b.elv };\n    var brp = LocationToPoint(br);\n\n    // Rotate brp cartesian coordinates around the z-axis by a.lon degrees,\n    // then around the y-axis by a.lat degrees.\n    // Though we are decreasing by a.lat degrees, as seen above the y-axis,\n    // this is a positive (counterclockwise) rotation (if B's longitude is east of A's).\n    // However, from this point of view the x-axis is pointing left.\n    // So we will look the other way making the x-axis pointing right, the z-axis\n    // pointing up, and the rotation treated as negative.\n\n    var alat = GeocentricLatitude(-a.lat * Math.PI / 180.0);\n    var acos = Math.cos(alat);\n    var asin = Math.sin(alat);\n\n    var bx = (brp.x * acos) - (brp.z * asin);\n    var by = brp.y;\n    var bz = (brp.x * asin) + (brp.z * acos);\n\n    return { x: bx, y: by, z: bz, radius: bradius };\n}\n\nfunction NormalizeVectorDiff(b, a) {\n    // Calculate norm(b-a), where norm divides a vector by its length to produce a unit vector.\n    var dx = b.x - a.x;\n    var dy = b.y - a.y;\n    var dz = b.z - a.z;\n    var dist2 = dx * dx + dy * dy + dz * dz;\n    if (dist2 == 0) {\n        return null;\n    }\n    var dist = Math.sqrt(dist2);\n    return { x: (dx / dist), y: (dy / dist), z: (dz / dist), radius: 1.0 };\n}\n\nfunction Calculate(pos1, pos2) {\n   \n    var result = {\n        from: pos1,\n        to: pos2,\n    };\n\n    var a = ParseLocation(pos1);\n    if (a != null) {\n        var b = ParseLocation(pos2);\n        if (b != null) {\n            var ap = LocationToPoint(a);\n            var bp = LocationToPoint(b);\n            var distKm = 0.001 * Distance(ap, bp);\n            result.distanceKm = distKm;\n\n            // Let's use a trick to calculate azimuth:\n            // Rotate the globe so that point A looks like latitude 0, longitude 0.\n            // We keep the actual radii calculated based on the oblate geoid,\n            // but use angles based on subtraction.\n            // Point A will be at x=radius, y=0, z=0.\n            // Vector difference B-A will have dz = N/S component, dy = E/W component.\n            var br = RotateGlobe(b, a, bp.radius, ap.radius);\n            if (br.z * br.z + br.y * br.y > 1.0e-6) {\n                var theta = Math.atan2(br.z, br.y) * 180.0 / Math.PI;\n                var azimuth = 90.0 - theta;\n                if (azimuth < 0.0) {\n                    azimuth += 360.0;\n                }\n                if (azimuth > 360.0) {\n                    azimuth -= 360.0;\n                }\n                result.azimuth = azimuth;\n            }\n\n            var bma = NormalizeVectorDiff(bp, ap);\n            if (bma != null) {\n                // Calculate altitude, which is the angle above the horizon of B as seen from A.\n                // Almost always, B will actually be below the horizon, so the altitude will be negative.\n                // The dot product of bma and norm = cos(zenith_angle), and zenith_angle = (90 deg) - altitude.\n                // So altitude = 90 - acos(dotprod).\n                var altitude = 90.0 - (180.0 / Math.PI) * Math.acos(bma.x * ap.nx + bma.y * ap.ny + bma.z * ap.nz);\n                result.altitude = altitude;\n            }\n        }\n    }\n    return result;\n}\nmsg.payload = Calculate(msg.payload.from, msg.payload.to);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":930,"y":840,"wires":[["9bec75c7.82ec08"]]},{"id":"9bec75c7.82ec08","type":"debug","z":"dd03fa8d.2f4be8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":990,"y":880,"wires":[]},{"id":"8daeb3b9.878cd","type":"inject","z":"dd03fa8d.2f4be8","name":"{\"from\":{\"lat\":50,\"lon\":1,\"elv\":0},\"to\":{\"lat\":50,\"lon\":1,\"elv\":12}}","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"to","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"from\":{\"lat\":50,\"lon\":1,\"elv\":0},\"to\":{\"lat\":50,\"lon\":1,\"elv\":12}}","payloadType":"json","x":480,"y":780,"wires":[["a3a3aa25.e2e358"]]},{"id":"4d1fac3d.f00ec4","type":"inject","z":"dd03fa8d.2f4be8","name":"{\"from\":{\"lat\":50,\"lon\":0,\"elv\":0},\"to\":{\"lat\":50,\"lon\":1,\"elv\":0}}","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"to","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"from\":{\"lat\":50,\"lon\":0,\"elv\":0},\"to\":{\"lat\":50,\"lon\":1,\"elv\":0}}","payloadType":"json","x":470,"y":820,"wires":[["a3a3aa25.e2e358"]]},{"id":"e9ddbe09.e734f","type":"inject","z":"dd03fa8d.2f4be8","name":"{\"from\":{\"lat\":50,\"lon\":0,\"elv\":0},\"to\":{\"lat\":51,\"lon\":0,\"elv\":0}}","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"to","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"from\":{\"lat\":50,\"lon\":0,\"elv\":0},\"to\":{\"lat\":51,\"lon\":0,\"elv\":0}}","payloadType":"json","x":470,"y":860,"wires":[["a3a3aa25.e2e358"]]}]
2 Likes

this is impressive

Thanks for the great formula. I'd like to use this flow for home automation presence detection. I can successfully extract Latitude, Longitude and Altitude from -

I'm lacking some skills in how to transform the data into the required lat, lon and elv variables. The 'From' location will be the moving iPhone location. The 'To' location will be the static home location.

Any assistance much appreciated.

@Tico

instead of 3 separate change nodes, use one node to set lat, lon and elv from your iDevice - that way, instead of 3 separate messages with 3 separate values, you have all values in one place (then you can build the to coords). Look in the "prepare to/from coords" for how I put them together.

image

demo flow

[{"id":"8035c186.ff4e3","type":"inject","z":"dd03fa8d.2f4be8","name":"{\"from\":{\"lat\":51,\"lon\":0.1,\"elv\":0},\"to\":{\"lat\":50.99,\"lon\":0.11,\"elv\":12}}","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"to","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"from\":{\"lat\":51,\"lon\":0.1,\"elv\":0},\"to\":{\"lat\":50.99,\"lon\":0.11,\"elv\":12}}","payloadType":"json","x":500,"y":900,"wires":[["a3a3aa25.e2e358"]]},{"id":"a3a3aa25.e2e358","type":"function","z":"dd03fa8d.2f4be8","name":"calculate distance between 2 coords","func":"//Credit: https://javascript.plainenglish.io/calculating-azimuth-distance-and-altitude-from-a-pair-of-gps-locations-36b4325d8ab0\n\nfunction ParseAngle(ang, limit) {\n    var angle = parseFloat(ang);\n    if (isNaN(angle) || (angle < -limit) || (angle > limit)) {\n        node.error(\"Invalid angle value.\", msg);\n        return null;\n    } else {\n        return angle;\n    }\n}\n\nfunction ParseElevation(el) {\n    var angle = parseFloat(el);\n    if (isNaN(angle)) {\n        node.error(\"Invalid elevation value.\", msg);\n        return null;\n    } else {\n        return angle;\n    }\n}\n\nfunction ParseLocation(pos) {\n    var lat = ParseAngle(pos.lat, 90.0);\n    var location = null;\n    if (lat != null) {\n        var lon = ParseAngle(pos.lon, 180.0);\n        if (lon != null) {\n            var elv = ParseElevation(pos.elv);\n            if (elv != null) {\n                location = { lat: lat, lon: lon, elv: elv };\n            }\n        }\n    }\n    return location;\n}\n\nfunction EarthRadiusInMeters(latitudeRadians) {\n    // latitudeRadians is geodetic, i.e. that reported by GPS.\n    // http://en.wikipedia.org/wiki/Earth_radius\n    var a = 6378137.0;  // equatorial radius in meters\n    var b = 6356752.3;  // polar radius in meters\n    var cos = Math.cos(latitudeRadians);\n    var sin = Math.sin(latitudeRadians);\n    var t1 = a * a * cos;\n    var t2 = b * b * sin;\n    var t3 = a * cos;\n    var t4 = b * sin;\n    return Math.sqrt((t1 * t1 + t2 * t2) / (t3 * t3 + t4 * t4));\n}\n\nfunction GeocentricLatitude(lat) {\n    // Convert geodetic latitude 'lat' to a geocentric latitude 'clat'.\n    // Geodetic latitude is the latitude as given by GPS.\n    // Geocentric latitude is the angle measured from center of Earth between a point and the equator.\n    // https://en.wikipedia.org/wiki/Latitude#Geocentric_latitude\n    var e2 = 0.00669437999014;\n    var clat = Math.atan((1.0 - e2) * Math.tan(lat));\n    return clat;\n}\n\nfunction LocationToPoint(c) {\n    // Convert (lat, lon, elv) to (x, y, z).\n    var lat = c.lat * Math.PI / 180.0;\n    var lon = c.lon * Math.PI / 180.0;\n    var radius = EarthRadiusInMeters(lat);\n    var clat = GeocentricLatitude(lat);\n\n    var cosLon = Math.cos(lon);\n    var sinLon = Math.sin(lon);\n    var cosLat = Math.cos(clat);\n    var sinLat = Math.sin(clat);\n    var x = radius * cosLon * cosLat;\n    var y = radius * sinLon * cosLat;\n    var z = radius * sinLat;\n\n    // We used geocentric latitude to calculate (x,y,z) on the Earth's ellipsoid.\n    // Now we use geodetic latitude to calculate normal vector from the surface, to correct for elevation.\n    var cosGlat = Math.cos(lat);\n    var sinGlat = Math.sin(lat);\n\n    var nx = cosGlat * cosLon;\n    var ny = cosGlat * sinLon;\n    var nz = sinGlat;\n\n    x += c.elv * nx;\n    y += c.elv * ny;\n    z += c.elv * nz;\n\n    return { x: x, y: y, z: z, radius: radius, nx: nx, ny: ny, nz: nz };\n}\n\nfunction Distance(ap, bp) {\n    var dx = ap.x - bp.x;\n    var dy = ap.y - bp.y;\n    var dz = ap.z - bp.z;\n    return Math.sqrt(dx * dx + dy * dy + dz * dz);\n}\n\nfunction RotateGlobe(b, a, bradius, aradius) {\n    // Get modified coordinates of 'b' by rotating the globe so that 'a' is at lat=0, lon=0.\n    var br = { lat: b.lat, lon: (b.lon - a.lon), elv: b.elv };\n    var brp = LocationToPoint(br);\n\n    // Rotate brp cartesian coordinates around the z-axis by a.lon degrees,\n    // then around the y-axis by a.lat degrees.\n    // Though we are decreasing by a.lat degrees, as seen above the y-axis,\n    // this is a positive (counterclockwise) rotation (if B's longitude is east of A's).\n    // However, from this point of view the x-axis is pointing left.\n    // So we will look the other way making the x-axis pointing right, the z-axis\n    // pointing up, and the rotation treated as negative.\n\n    var alat = GeocentricLatitude(-a.lat * Math.PI / 180.0);\n    var acos = Math.cos(alat);\n    var asin = Math.sin(alat);\n\n    var bx = (brp.x * acos) - (brp.z * asin);\n    var by = brp.y;\n    var bz = (brp.x * asin) + (brp.z * acos);\n\n    return { x: bx, y: by, z: bz, radius: bradius };\n}\n\nfunction NormalizeVectorDiff(b, a) {\n    // Calculate norm(b-a), where norm divides a vector by its length to produce a unit vector.\n    var dx = b.x - a.x;\n    var dy = b.y - a.y;\n    var dz = b.z - a.z;\n    var dist2 = dx * dx + dy * dy + dz * dz;\n    if (dist2 == 0) {\n        return null;\n    }\n    var dist = Math.sqrt(dist2);\n    return { x: (dx / dist), y: (dy / dist), z: (dz / dist), radius: 1.0 };\n}\n\nfunction Calculate(pos1, pos2) {\n   \n    var result = {\n        from: pos1,\n        to: pos2,\n    };\n\n    var a = ParseLocation(pos1);\n    if (a != null) {\n        var b = ParseLocation(pos2);\n        if (b != null) {\n            var ap = LocationToPoint(a);\n            var bp = LocationToPoint(b);\n            var distKm = 0.001 * Distance(ap, bp);\n            result.distanceKm = distKm;\n\n            // Let's use a trick to calculate azimuth:\n            // Rotate the globe so that point A looks like latitude 0, longitude 0.\n            // We keep the actual radii calculated based on the oblate geoid,\n            // but use angles based on subtraction.\n            // Point A will be at x=radius, y=0, z=0.\n            // Vector difference B-A will have dz = N/S component, dy = E/W component.\n            var br = RotateGlobe(b, a, bp.radius, ap.radius);\n            if (br.z * br.z + br.y * br.y > 1.0e-6) {\n                var theta = Math.atan2(br.z, br.y) * 180.0 / Math.PI;\n                var azimuth = 90.0 - theta;\n                if (azimuth < 0.0) {\n                    azimuth += 360.0;\n                }\n                if (azimuth > 360.0) {\n                    azimuth -= 360.0;\n                }\n                result.azimuth = azimuth;\n            }\n\n            var bma = NormalizeVectorDiff(bp, ap);\n            if (bma != null) {\n                // Calculate altitude, which is the angle above the horizon of B as seen from A.\n                // Almost always, B will actually be below the horizon, so the altitude will be negative.\n                // The dot product of bma and norm = cos(zenith_angle), and zenith_angle = (90 deg) - altitude.\n                // So altitude = 90 - acos(dotprod).\n                var altitude = 90.0 - (180.0 / Math.PI) * Math.acos(bma.x * ap.nx + bma.y * ap.ny + bma.z * ap.nz);\n                result.altitude = altitude;\n            }\n        }\n    }\n    return result;\n}\nmsg.payload = Calculate(msg.payload.from, msg.payload.to);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":930,"y":840,"wires":[["9bec75c7.82ec08"]]},{"id":"9bec75c7.82ec08","type":"debug","z":"dd03fa8d.2f4be8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":990,"y":880,"wires":[]},{"id":"8daeb3b9.878cd","type":"inject","z":"dd03fa8d.2f4be8","name":"{\"from\":{\"lat\":50,\"lon\":1,\"elv\":0},\"to\":{\"lat\":50,\"lon\":1,\"elv\":12}}","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"to","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"from\":{\"lat\":50,\"lon\":1,\"elv\":0},\"to\":{\"lat\":50,\"lon\":1,\"elv\":12}}","payloadType":"json","x":480,"y":780,"wires":[["a3a3aa25.e2e358"]]},{"id":"4d1fac3d.f00ec4","type":"inject","z":"dd03fa8d.2f4be8","name":"{\"from\":{\"lat\":50,\"lon\":0,\"elv\":0},\"to\":{\"lat\":50,\"lon\":1,\"elv\":0}}","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"to","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"from\":{\"lat\":50,\"lon\":0,\"elv\":0},\"to\":{\"lat\":50,\"lon\":1,\"elv\":0}}","payloadType":"json","x":470,"y":820,"wires":[["a3a3aa25.e2e358"]]},{"id":"e9ddbe09.e734f","type":"inject","z":"dd03fa8d.2f4be8","name":"{\"from\":{\"lat\":50,\"lon\":0,\"elv\":0},\"to\":{\"lat\":51,\"lon\":0,\"elv\":0}}","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"to","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"from\":{\"lat\":50,\"lon\":0,\"elv\":0},\"to\":{\"lat\":51,\"lon\":0,\"elv\":0}}","payloadType":"json","x":470,"y":860,"wires":[["a3a3aa25.e2e358"]]},{"id":"734fe766.dd6de8","type":"function","z":"dd03fa8d.2f4be8","name":"(fake) My iDevice","func":"msg.payload = {\n    iPad: [-31.9, 115.8, 0, 0]\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":750,"y":700,"wires":[["f3a2052b.cca9a8"]]},{"id":"e8b119ae.f9fbb8","type":"inject","z":"dd03fa8d.2f4be8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":540,"y":700,"wires":[["734fe766.dd6de8"]]},{"id":"f3a2052b.cca9a8","type":"function","z":"dd03fa8d.2f4be8","name":"prepare to/from coords","func":"//home position\nvar from = {\n    lat: -31.89,\n    lon: 115.87,\n    elv: 0,\n}\n\n//ipad pos\nvar iPad = msg.payload.iPad;\nvar to = {\n    lat: iPad[0],\n    lon: iPad[1],\n    elv: iPad[2],\n}\n\n\nmsg.payload = {\n    from: from,\n    to: to\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1020,"y":700,"wires":[["a3a3aa25.e2e358"]]}]

Thanks! Works a treat.

For the info of anyone using the node-red-contrib-apple-find-me, the slight variation I made to the function node 'prepare to/from coords' is as follows -

//home position
var from = {
    lat: -31.89,
    lon: 115.87,
    elv: 0,
}

//ipad pos
var iPad = msg.payload.iPad;
var to = {
    lat: msg.payload.iPhone[1].locationInfo.latitude,
    lon: msg.payload.iPhone[1].locationInfo.longitude,
    elv: msg.payload.iPhone[1].locationInfo.altitude,
}

msg.payload = {
    from: from,
    to: to
}
return msg;

Place a debug node on the Apple node to list all the devices on a given iCloud account. iPhone[1] will need to be changed to whichever iDevice you wish to track (and the home position obviously needs changing...) :slightly_smiling_face:

Is your home elevation really 0 ? Do you really live on the WGS84 ellipsoid ?

You are quite correct. The Home location has been refined to 6 decimal places and the elevation gleaned from Google Earth. The typical vertical error I'm seeing with a good fix is about 1.5 metres. Much better accuracy than I anticipated for a vertical fix.

1 Like

Spoke too soon. The reason why the vertical error is so accurate is because the iPhone always reports altitude as 0. It might be a bug in the Apple node? Alternatively, iDevices might always report the position tied to the WGS84 ellipsoid?

GPS altitude fixes are notoriously hard. I think that you typically need outside, clear sky access with sufficient horizon to get 4 satellites or more in view. Even with modern phones I doubt that you will get anything useful indoors or in urban or forested environments.

Google Earth/Maps can also be quite a way out because its horizontal accuracy is relatively poor - at least on steep elevations. Poor = 100m out in extreme cases.

In the UK, your local library (if you still have one) may keep copies of the most detailed local OS maps and they are your best option since they use more accurate surveying options.