mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
* Switch to ipapi.co (fixes #19846) * Fix name * Update name
This commit is contained in:
parent
4b3d4b275e
commit
25f6302813
@ -10,8 +10,8 @@ from typing import Any, Optional, Tuple, Dict
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
ELEVATION_URL = 'http://maps.googleapis.com/maps/api/elevation/json'
|
ELEVATION_URL = 'http://maps.googleapis.com/maps/api/elevation/json'
|
||||||
FREEGEO_API = 'https://freegeoip.net/json/'
|
|
||||||
IP_API = 'http://ip-api.com/json'
|
IP_API = 'http://ip-api.com/json'
|
||||||
|
IPAPI = 'https://ipapi.co/json/'
|
||||||
|
|
||||||
# Constants from https://github.com/maurycyp/vincenty
|
# Constants from https://github.com/maurycyp/vincenty
|
||||||
# Earth ellipsoid according to WGS 84
|
# Earth ellipsoid according to WGS 84
|
||||||
@ -35,7 +35,7 @@ LocationInfo = collections.namedtuple(
|
|||||||
|
|
||||||
def detect_location_info() -> Optional[LocationInfo]:
|
def detect_location_info() -> Optional[LocationInfo]:
|
||||||
"""Detect location information."""
|
"""Detect location information."""
|
||||||
data = _get_freegeoip()
|
data = _get_ipapi()
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
data = _get_ip_api()
|
data = _get_ip_api()
|
||||||
@ -159,22 +159,22 @@ def vincenty(point1: Tuple[float, float], point2: Tuple[float, float],
|
|||||||
return round(s, 6)
|
return round(s, 6)
|
||||||
|
|
||||||
|
|
||||||
def _get_freegeoip() -> Optional[Dict[str, Any]]:
|
def _get_ipapi() -> Optional[Dict[str, Any]]:
|
||||||
"""Query freegeoip.io for location data."""
|
"""Query ipapi.co for location data."""
|
||||||
try:
|
try:
|
||||||
raw_info = requests.get(FREEGEO_API, timeout=5).json()
|
raw_info = requests.get(IPAPI, timeout=5).json()
|
||||||
except (requests.RequestException, ValueError):
|
except (requests.RequestException, ValueError):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'ip': raw_info.get('ip'),
|
'ip': raw_info.get('ip'),
|
||||||
'country_code': raw_info.get('country_code'),
|
'country_code': raw_info.get('country'),
|
||||||
'country_name': raw_info.get('country_name'),
|
'country_name': raw_info.get('country_name'),
|
||||||
'region_code': raw_info.get('region_code'),
|
'region_code': raw_info.get('region_code'),
|
||||||
'region_name': raw_info.get('region_name'),
|
'region_name': raw_info.get('region'),
|
||||||
'city': raw_info.get('city'),
|
'city': raw_info.get('city'),
|
||||||
'zip_code': raw_info.get('zip_code'),
|
'zip_code': raw_info.get('postal'),
|
||||||
'time_zone': raw_info.get('time_zone'),
|
'time_zone': raw_info.get('timezone'),
|
||||||
'latitude': raw_info.get('latitude'),
|
'latitude': raw_info.get('latitude'),
|
||||||
'longitude': raw_info.get('longitude'),
|
'longitude': raw_info.get('longitude'),
|
||||||
}
|
}
|
||||||
|
13
tests/fixtures/freegeoip.io.json
vendored
13
tests/fixtures/freegeoip.io.json
vendored
@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"ip": "1.2.3.4",
|
|
||||||
"country_code": "US",
|
|
||||||
"country_name": "United States",
|
|
||||||
"region_code": "CA",
|
|
||||||
"region_name": "California",
|
|
||||||
"city": "San Diego",
|
|
||||||
"zip_code": "92122",
|
|
||||||
"time_zone": "America\/Los_Angeles",
|
|
||||||
"latitude": 32.8594,
|
|
||||||
"longitude": -117.2073,
|
|
||||||
"metro_code": 825
|
|
||||||
}
|
|
20
tests/fixtures/ipapi.co.json
vendored
Normal file
20
tests/fixtures/ipapi.co.json
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"ip": "1.2.3.4",
|
||||||
|
"city": "Bern",
|
||||||
|
"region": "Bern",
|
||||||
|
"region_code": "BE",
|
||||||
|
"country": "CH",
|
||||||
|
"country_name": "Switzerland",
|
||||||
|
"continent_code": "EU",
|
||||||
|
"in_eu": false,
|
||||||
|
"postal": "3000",
|
||||||
|
"latitude": 46.9480278,
|
||||||
|
"longitude": 7.4490812,
|
||||||
|
"timezone": "Europe/Zurich",
|
||||||
|
"utc_offset": "+0100",
|
||||||
|
"country_calling_code": "+41",
|
||||||
|
"currency": "CHF",
|
||||||
|
"languages": "de-CH,fr-CH,it-CH,rm",
|
||||||
|
"asn": "AS6830",
|
||||||
|
"org": "Liberty Global B.V."
|
||||||
|
}
|
@ -30,62 +30,59 @@ class TestLocationUtil(TestCase):
|
|||||||
|
|
||||||
def test_get_distance_to_same_place(self):
|
def test_get_distance_to_same_place(self):
|
||||||
"""Test getting the distance."""
|
"""Test getting the distance."""
|
||||||
meters = location_util.distance(COORDINATES_PARIS[0],
|
meters = location_util.distance(
|
||||||
COORDINATES_PARIS[1],
|
COORDINATES_PARIS[0], COORDINATES_PARIS[1],
|
||||||
COORDINATES_PARIS[0],
|
COORDINATES_PARIS[0], COORDINATES_PARIS[1])
|
||||||
COORDINATES_PARIS[1])
|
|
||||||
|
|
||||||
assert meters == 0
|
assert meters == 0
|
||||||
|
|
||||||
def test_get_distance(self):
|
def test_get_distance(self):
|
||||||
"""Test getting the distance."""
|
"""Test getting the distance."""
|
||||||
meters = location_util.distance(COORDINATES_PARIS[0],
|
meters = location_util.distance(
|
||||||
COORDINATES_PARIS[1],
|
COORDINATES_PARIS[0], COORDINATES_PARIS[1],
|
||||||
COORDINATES_NEW_YORK[0],
|
COORDINATES_NEW_YORK[0], COORDINATES_NEW_YORK[1])
|
||||||
COORDINATES_NEW_YORK[1])
|
|
||||||
|
|
||||||
assert meters/1000 - DISTANCE_KM < 0.01
|
assert meters/1000 - DISTANCE_KM < 0.01
|
||||||
|
|
||||||
def test_get_kilometers(self):
|
def test_get_kilometers(self):
|
||||||
"""Test getting the distance between given coordinates in km."""
|
"""Test getting the distance between given coordinates in km."""
|
||||||
kilometers = location_util.vincenty(COORDINATES_PARIS,
|
kilometers = location_util.vincenty(
|
||||||
COORDINATES_NEW_YORK)
|
COORDINATES_PARIS, COORDINATES_NEW_YORK)
|
||||||
assert round(kilometers, 2) == DISTANCE_KM
|
assert round(kilometers, 2) == DISTANCE_KM
|
||||||
|
|
||||||
def test_get_miles(self):
|
def test_get_miles(self):
|
||||||
"""Test getting the distance between given coordinates in miles."""
|
"""Test getting the distance between given coordinates in miles."""
|
||||||
miles = location_util.vincenty(COORDINATES_PARIS,
|
miles = location_util.vincenty(
|
||||||
COORDINATES_NEW_YORK,
|
COORDINATES_PARIS, COORDINATES_NEW_YORK, miles=True)
|
||||||
miles=True)
|
|
||||||
assert round(miles, 2) == DISTANCE_MILES
|
assert round(miles, 2) == DISTANCE_MILES
|
||||||
|
|
||||||
@requests_mock.Mocker()
|
@requests_mock.Mocker()
|
||||||
def test_detect_location_info_freegeoip(self, m):
|
def test_detect_location_info_ipapi(self, m):
|
||||||
"""Test detect location info using freegeoip."""
|
"""Test detect location info using ipapi.co."""
|
||||||
m.get(location_util.FREEGEO_API,
|
m.get(
|
||||||
text=load_fixture('freegeoip.io.json'))
|
location_util.IPAPI, text=load_fixture('ipapi.co.json'))
|
||||||
|
|
||||||
info = location_util.detect_location_info(_test_real=True)
|
info = location_util.detect_location_info(_test_real=True)
|
||||||
|
|
||||||
assert info is not None
|
assert info is not None
|
||||||
assert info.ip == '1.2.3.4'
|
assert info.ip == '1.2.3.4'
|
||||||
assert info.country_code == 'US'
|
assert info.country_code == 'CH'
|
||||||
assert info.country_name == 'United States'
|
assert info.country_name == 'Switzerland'
|
||||||
assert info.region_code == 'CA'
|
assert info.region_code == 'BE'
|
||||||
assert info.region_name == 'California'
|
assert info.region_name == 'Bern'
|
||||||
assert info.city == 'San Diego'
|
assert info.city == 'Bern'
|
||||||
assert info.zip_code == '92122'
|
assert info.zip_code == '3000'
|
||||||
assert info.time_zone == 'America/Los_Angeles'
|
assert info.time_zone == 'Europe/Zurich'
|
||||||
assert info.latitude == 32.8594
|
assert info.latitude == 46.9480278
|
||||||
assert info.longitude == -117.2073
|
assert info.longitude == 7.4490812
|
||||||
assert not info.use_metric
|
assert info.use_metric
|
||||||
|
|
||||||
@requests_mock.Mocker()
|
@requests_mock.Mocker()
|
||||||
@patch('homeassistant.util.location._get_freegeoip', return_value=None)
|
@patch('homeassistant.util.location._get_ipapi', return_value=None)
|
||||||
def test_detect_location_info_ipapi(self, mock_req, mock_freegeoip):
|
def test_detect_location_info_ip_api(self, mock_req, mock_ipapi):
|
||||||
"""Test detect location info using freegeoip."""
|
"""Test detect location info using ip-api.com."""
|
||||||
mock_req.get(location_util.IP_API,
|
mock_req.get(
|
||||||
text=load_fixture('ip-api.com.json'))
|
location_util.IP_API, text=load_fixture('ip-api.com.json'))
|
||||||
|
|
||||||
info = location_util.detect_location_info(_test_real=True)
|
info = location_util.detect_location_info(_test_real=True)
|
||||||
|
|
||||||
@ -103,11 +100,10 @@ class TestLocationUtil(TestCase):
|
|||||||
assert not info.use_metric
|
assert not info.use_metric
|
||||||
|
|
||||||
@patch('homeassistant.util.location.elevation', return_value=0)
|
@patch('homeassistant.util.location.elevation', return_value=0)
|
||||||
@patch('homeassistant.util.location._get_freegeoip', return_value=None)
|
@patch('homeassistant.util.location._get_ipapi', return_value=None)
|
||||||
@patch('homeassistant.util.location._get_ip_api', return_value=None)
|
@patch('homeassistant.util.location._get_ip_api', return_value=None)
|
||||||
def test_detect_location_info_both_queries_fail(self, mock_ipapi,
|
def test_detect_location_info_both_queries_fail(
|
||||||
mock_freegeoip,
|
self, mock_ipapi, mock_ip_api, mock_elevation):
|
||||||
mock_elevation):
|
|
||||||
"""Ensure we return None if both queries fail."""
|
"""Ensure we return None if both queries fail."""
|
||||||
info = location_util.detect_location_info(_test_real=True)
|
info = location_util.detect_location_info(_test_real=True)
|
||||||
assert info is None
|
assert info is None
|
||||||
@ -115,8 +111,8 @@ class TestLocationUtil(TestCase):
|
|||||||
@patch('homeassistant.util.location.requests.get',
|
@patch('homeassistant.util.location.requests.get',
|
||||||
side_effect=requests.RequestException)
|
side_effect=requests.RequestException)
|
||||||
def test_freegeoip_query_raises(self, mock_get):
|
def test_freegeoip_query_raises(self, mock_get):
|
||||||
"""Test freegeoip query when the request to API fails."""
|
"""Test ipapi.co query when the request to API fails."""
|
||||||
info = location_util._get_freegeoip()
|
info = location_util._get_ipapi()
|
||||||
assert info is None
|
assert info is None
|
||||||
|
|
||||||
@patch('homeassistant.util.location.requests.get',
|
@patch('homeassistant.util.location.requests.get',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user