How to calculate a geofence and know when in or out of it

I now have my mobile HA instance location being update every 5 minutes with Latitude and Longitude.

I’d like to be able to set a geofence of say 50m every time the vehicle stops and then get notified when HA moves out of that geofence.

I think I first need to be able to calculate the geofence circle from latitude and longitude.

Secondly calculate the distance from the stop point.

Any ideas?

Make a template sensor using a trigger of your choice with

for:
  minutes: 5

then in the template sensor store the latitude and longitude as attributes.

Second make a template sensor that calculates the distance between your current location and the previous template sensor. Use the distance() jinja function to do that. The output of the distance function is meters.

Then do whatever you want with the second sensor’s distance.

I have a feeling you’ll need more help. So…

template:
- trigger:
  - platform: state
    entity_id: person.xyz
    to: ~
    for:
      minutes: 5
  sensor:
  - name: XYZ Last Location
    unique_id: something_long_and_unique
    state: >
      {{ trigger.to_state.state }}
    attributes:
      latitude: >
        {{ trigger.to_state.attributes.latitude }}
      longitude: >
        {{ trigger.to_state.attributes.longitude }}

- sensor:
  - name: XYZ Distance from last location
    unique_id: something_long_and_unique2
    device_class: distance
    unit_of_measurement: m
    state: >
      {{ distance('person.xyz', 'sensor.xyz_last_location') }}
1 Like

Thank you both.

I found this calculation.

It’s a little more complicated than a subtraction but I can’t see a way of doing this using templating as the cos and arctan don’t seem to be available.

In python it looks like this (as far as I can work out) but I don’t know how to use it with HA.

i

import math

earth_radius = 6371e3

stationary_latitude_radians = stationary_latitude * math.pi/180

new_latitude_radians = new_latitude * math.pi/180

latitude_change = (new_latitude-stationary_latitude) * math.pi/180

longitude_change = (new_longitude-stationary_longitude) * math.pi/180

a = math.sin(latitude_change/2) * math.sin(latitude_change/2) + \

math.cos(stationary_latitude_radians) * math.cos(new_latitude_radians) * \

math.sin(longitude_change/2) * math.sin(longitude_change/2)

c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))

distance_moved = earth_radius * c

You don’t need what is there, the distance function in HA does this already without needing that calculation. Did you try what I wrote?

I have a feeling you didn’t read anything I wrote, I’m the single person who replied to you.

Apologies, Petro.

Yes, I did read it, or rather misread it. I wasn’t aware that ‘distance’ did that.

I will give it a try when I get home and let you know how it goes.

Thank you for your help.

That’s an excellent solution.

My challenge is creating the dummy person.xyz to use the HA lat and long for location.

Checking in Dev Tools the location of HA doesn’t seem to be available as an entity.

I have created lat and long sensors but how would I use them with person.xyz?

I could create a new sensor with both lat and long attributes and trigger from changes to that maybe. Not something I tried to do before so a nice challenge.

You don’t need a person, you can use a device tracker too. Or a sensor with lat/lon.

It just needs an entity with lat/lon attributes.

e.g.

template:
- sensor:
  - name: My Coordinates
    unique_id: something_long_and_unique0
    state: >
      {{ states('sensor.lat') }}, {{ states('sensor.lon') }}
    attributes:
      latitude: >
        {{ states('sensor.lat') }} }}
      longitude: >
        {{ states('sensor.lon') }}

- trigger:
  - platform: state
    entity_id: sensor.my_coordinates
    to: ~
    for:
      minutes: 5
  sensor:
  - name: XYZ Last Location
    unique_id: something_long_and_unique
    state: >
      {{ trigger.to_state.state }}
    attributes:
      latitude: >
        {{ trigger.to_state.attributes.latitude }}
      longitude: >
        {{ trigger.to_state.attributes.longitude }}

- sensor:
  - name: XYZ Distance from last location
    unique_id: something_long_and_unique2
    device_class: distance
    unit_of_measurement: m
    state: >
      {{ distance('person.xyz', 'sensor.xyz_last_location') }}

Thank you.

So, replace person.xyz with sensor.my coordinates in the last line?

just replace sensor.lat and sensor.lon wherever you see that in what I pasted with your lat/lon senosrs.

Then use that sensor in the trigger of the other sensor.

Sir, you are a genius. Works a treat. Thank you so much for your help.

  - sensor:
    - name: CIP Coordinates
      unique_id: cip_coordinates_for_geofence
      state: >
        {{ states('sensor.latitude') }}, {{ states('sensor.longitude') }}
      attributes:
        latitude: >
          {{ states('sensor.latitude') }}
        longitude: >
          {{ states('sensor.longitude') }}

  - trigger:
    - platform: state
      entity_id: sensor.cip_coordinates
      to: ~
      for:
        seconds: 5
    sensor:
    - name: CIP Last Location
      unique_id: cip_last_coordinates
      state: >
        {{ trigger.to_state.state }}
      attributes:
        latitude: >
          {{ trigger.to_state.attributes.latitude }}
        longitude: >
          {{ trigger.to_state.attributes.longitude }}

  - sensor:
    - name: CIP Distance from last location
      unique_id: cip_distance_from_parked_location
      device_class: distance
      unit_of_measurement: m
      state: >
        {{ distance('sensor.cip_coordinates', 'sensor.cip_last_location') }}

It does produce some rather odd distance values though.

I’m guessing that’s just micro movements caused by the satellites. I’m not able to actually move it just now but it all seems good.

Thanks again.

You can round the result with a {{ distance('sensor.cip_coordinates', 'sensor.cip_last_location') | round(2) }}