Linux script for updating your laptop location using ipinfo.io

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

1 Like