with ipinfo.io you can get some location (the city) of your linux device.
I used this to make a script.
#!/usr/bin/bash
# Variables
DEVICE_NAME="device_tracker.laptop" # Replace with your device's entity ID
HA_URL="https://home.assistant..com" # Replace with your Home Assistant URL
API_TOKEN="12345678" # Replace with your Home Assistant long-lived access token
STATE="not_home" # Default state if no zone matches
# Get IP location using ipinfo.io
LOCATION=$(curl -s https://ipinfo.io/json)
LATITUDE=$(echo "$LOCATION" | jq -r '.loc' | cut -d',' -f1)
LONGITUDE=$(echo "$LOCATION" | jq -r '.loc' | cut -d',' -f2)
CITY=$(echo "$LOCATION" | jq -r '.city')
COUNTRY=$(echo "$LOCATION" | jq -r '.country')
GPS_ACCURACY=50 # Default GPS accuracy value
# Fetch all zones from Home Assistant
ZONES=$(curl -s -H "Authorization: Bearer $API_TOKEN" -H "Content-Type: application/json" "$HA_URL/api/states" | jq '.[] | select(.entity_id | startswith("zone."))')
# Function to calculate distance between two coordinates
calculate_distance() {
LAT1=$1
LON1=$2
LAT2=$3
LON2=$4
gawk -v lat1="$LAT1" -v lon1="$LON1" -v lat2="$LAT2" -v lon2="$LON2" '
function acos(x) {
return atan2(sqrt(1 - x * x), x);
}
BEGIN {
pi = 3.141592653589793238;
radlat1 = pi * lat1 / 180;
radlat2 = pi * lat2 / 180;
theta = lon1 - lon2;
radtheta = pi * theta / 180;
dist = sin(radlat1) * sin(radlat2) + cos(radlat1) * cos(radlat2) * cos(radtheta);
if (dist > 1) dist = 1;
dist = acos(dist);
dist = dist * 180 / pi;
dist = dist * 60 * 1.1515 * 1.609344; # Convert to kilometers
print dist;
}'
}
# Determine the zone based on the closest match
BEST_ZONE="not_home"
BEST_DISTANCE=100000 # Start with a large distance
while read -r ZONE; do
ZONE_LAT=$(echo "$ZONE" | jq -r '.attributes.latitude')
ZONE_LON=$(echo "$ZONE" | jq -r '.attributes.longitude')
ZONE_RADIUS=$(echo "$ZONE" | jq -r '.attributes.radius')
ZONE_NAME=$(echo "$ZONE" | jq -r '.attributes.friendly_name')
DISTANCE=$(calculate_distance "$LATITUDE" "$LONGITUDE" "$ZONE_LAT" "$ZONE_LON")
if (( $(echo "$DISTANCE < $ZONE_RADIUS / 1000" | bc -l) )); then
if (( $(echo "$DISTANCE < $BEST_DISTANCE" | bc -l) )); then
BEST_DISTANCE=$DISTANCE
BEST_ZONE=$ZONE_NAME
fi
fi
done <<< "$(echo "$ZONES" | jq -c '.')"
# Update Home Assistant device tracker state
curl -X POST \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"state\": \"$BEST_ZONE\",
\"attributes\": {
\"latitude\": $LATITUDE,
\"longitude\": $LONGITUDE,
\"gps_accuracy\": $GPS_ACCURACY,
\"city\": \"$CITY\",
\"country\": \"$COUNTRY\"
}
}" \
"$HA_URL/api/states/$DEVICE_NAME"
# Print success message
echo "Location updated for $DEVICE_NAME to $BEST_ZONE zone ($LATITUDE, $LONGITUDE)."
also a script to geep ipinfo.io out of a local vpn.
#!/bin/bash
# Destination domain
DEST_DOMAIN="ipinfo.io"
# Fetch the current IP address of the destination domain
DEST_IP=$(nslookup $DEST_DOMAIN | awk '/^Address: / { print $2 }' | tail -n1)
if [ -z "$DEST_IP" ]; then
echo "Error: Unable to resolve $DEST_DOMAIN."
exit 1
fi
# Fetch the current default gateway and associated interface (excluding VPNs)
DEFAULT_ROUTE=$(ip route | grep -m 1 '^default' | grep -v tun)
DEFAULT_GATEWAY=$(echo "$DEFAULT_ROUTE" | awk '{print $3}')
NETWORK_INTERFACE=$(echo "$DEFAULT_ROUTE" | awk '{print $5}')
if [ -z "$DEFAULT_GATEWAY" ] || [ -z "$NETWORK_INTERFACE" ]; then
echo "Error: Unable to determine the default gateway or network interface."
exit 1
fi
# Check if a route for the destination IP already exists
EXISTING_ROUTE=$(ip route | grep "$DEST_IP")
if [[ "$EXISTING_ROUTE" == *"$DEFAULT_GATEWAY"* && "$EXISTING_ROUTE" == *"$NETWORK_INTERFACE"* ]]; then
echo "Route for $DEST_IP already exists and is correct."
else
# Remove the existing route if it points to a different gateway/interface
sudo ip route del $DEST_IP 2>/dev/null
# Add the new route
sudo ip route add $DEST_IP via $DEFAULT_GATEWAY dev $NETWORK_INTERFACE
echo "Added route for $DEST_IP via $DEFAULT_GATEWAY ($NETWORK_INTERFACE)."
fi
# Display the current route for the destination
echo "Current routing table entry for $DEST_IP:"
ip route get $DEST_IP
happy scripting