Auto-update: Wed Jun 26 12:53:04 PDT 2024
This commit is contained in:
parent
c5a4242ec4
commit
ab86abc2f2
3 changed files with 64 additions and 34 deletions
|
@ -109,8 +109,6 @@ class IncomingEmail(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Location(BaseModel):
|
class Location(BaseModel):
|
||||||
latitude: float
|
latitude: float
|
||||||
longitude: float
|
longitude: float
|
||||||
|
|
|
@ -29,7 +29,7 @@ from sijapi.utilities import haversine
|
||||||
|
|
||||||
locate = APIRouter()
|
locate = APIRouter()
|
||||||
|
|
||||||
async def reverse_geocode(latitude: float, longitude: float) -> Optional[Location]:
|
async def reverse_geocode(latitude: float, longitude: float, elevation: float = None) -> Optional[Location]:
|
||||||
url = f"https://nominatim.openstreetmap.org/reverse?format=json&lat={latitude}&lon={longitude}"
|
url = f"https://nominatim.openstreetmap.org/reverse?format=json&lat={latitude}&lon={longitude}"
|
||||||
L.INFO(f"Calling Nominatim API at {url}")
|
L.INFO(f"Calling Nominatim API at {url}")
|
||||||
headers = {
|
headers = {
|
||||||
|
@ -42,21 +42,22 @@ async def reverse_geocode(latitude: float, longitude: float) -> Optional[Locatio
|
||||||
data = await response.json()
|
data = await response.json()
|
||||||
|
|
||||||
address = data.get("address", {})
|
address = data.get("address", {})
|
||||||
|
elevation = elevation or await get_elevation(latitude, longitude)
|
||||||
location = Location(
|
location = Location(
|
||||||
latitude=float(data.get("lat", latitude)),
|
latitude=latitude,
|
||||||
longitude=float(data.get("lon", longitude)),
|
longitude=longitude,
|
||||||
|
elevation=elevation,
|
||||||
datetime=datetime.now(timezone.utc),
|
datetime=datetime.now(timezone.utc),
|
||||||
zip=address.get("postcode"),
|
zip=address.get("postcode"),
|
||||||
street=address.get("road"),
|
street=address.get("road"),
|
||||||
city=address.get("city"),
|
city=address.get("city"),
|
||||||
state=address.get("state"),
|
state=address.get("state"),
|
||||||
country=address.get("country"),
|
country=address.get("country"),
|
||||||
context={}, # Initialize with an empty dict, to be filled as needed
|
context={},
|
||||||
class_=data.get("class"),
|
class_=data.get("class"),
|
||||||
type=data.get("type"),
|
type=data.get("type"),
|
||||||
name=data.get("name"),
|
name=data.get("name"),
|
||||||
display_name=data.get("display_name"),
|
display_name=data.get("display_name"),
|
||||||
boundingbox=data.get("boundingbox"),
|
|
||||||
amenity=address.get("amenity"),
|
amenity=address.get("amenity"),
|
||||||
house_number=address.get("house_number"),
|
house_number=address.get("house_number"),
|
||||||
road=address.get("road"),
|
road=address.get("road"),
|
||||||
|
@ -197,7 +198,8 @@ def find_override_locations(lat: float, lon: float) -> Optional[str]:
|
||||||
|
|
||||||
return closest_location
|
return closest_location
|
||||||
|
|
||||||
def get_elevation(latitude, longitude):
|
|
||||||
|
async def get_elevation(latitude, longitude):
|
||||||
url = "https://api.open-elevation.com/api/v1/lookup"
|
url = "https://api.open-elevation.com/api/v1/lookup"
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
|
@ -209,11 +211,12 @@ def get_elevation(latitude, longitude):
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
try:
|
try:
|
||||||
response = requests.post(url, json=payload)
|
async with session.post(url, json=payload) as response:
|
||||||
response.raise_for_status() # Raise an exception for unsuccessful requests
|
response.raise_for_status() # Raise an exception for unsuccessful requests
|
||||||
|
|
||||||
data = response.json()
|
data = await response.json()
|
||||||
|
|
||||||
if "results" in data:
|
if "results" in data:
|
||||||
elevation = data["results"][0]["elevation"]
|
elevation = data["results"][0]["elevation"]
|
||||||
|
@ -221,12 +224,13 @@ def get_elevation(latitude, longitude):
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except requests.exceptions.RequestException as e:
|
except aiohttp.ClientError as e:
|
||||||
L.ERR(f"Error: {e}")
|
L.ERR(f"Error: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def fetch_locations(start: datetime, end: datetime = None) -> List[Location]:
|
async def fetch_locations(start: datetime, end: datetime = None) -> List[Location]:
|
||||||
start_datetime = await localize_datetime(start)
|
start_datetime = await localize_datetime(start)
|
||||||
if end is None:
|
if end is None:
|
||||||
|
@ -385,7 +389,6 @@ async def generate_map(start_date: datetime, end_date: datetime):
|
||||||
|
|
||||||
return html_content
|
return html_content
|
||||||
|
|
||||||
|
|
||||||
async def post_location(location: Location):
|
async def post_location(location: Location):
|
||||||
L.DEBUG(f"post_location called with {location.datetime}")
|
L.DEBUG(f"post_location called with {location.datetime}")
|
||||||
|
|
||||||
|
@ -401,26 +404,50 @@ async def post_location(location: Location):
|
||||||
# Parse and localize the datetime
|
# Parse and localize the datetime
|
||||||
localized_datetime = await localize_datetime(location.datetime)
|
localized_datetime = await localize_datetime(location.datetime)
|
||||||
|
|
||||||
|
|
||||||
await conn.execute('''
|
await conn.execute('''
|
||||||
INSERT INTO locations (datetime, location, city, state, zip, street, action, device_type, device_model, device_name, device_os)
|
INSERT INTO locations (
|
||||||
VALUES ($1, ST_SetSRID(ST_MakePoint($2, $3, $4), 4326), $5, $6, $7, $8, $9, $10, $11, $12, $13)
|
datetime, location, city, state, zip, street, action, device_type, device_model, device_name, device_os,
|
||||||
''', localized_datetime, location.longitude, location.latitude, location.elevation, location.city, location.state, location.zip, location.street, action, device_type, device_model, device_name, device_os)
|
class_, type, name, display_name, amenity, house_number, road, quarter, neighbourhood,
|
||||||
|
suburb, county, country_code, country
|
||||||
|
)
|
||||||
|
VALUES ($1, ST_SetSRID(ST_MakePoint($2, $3, $4), 4326), $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15,
|
||||||
|
$16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26)
|
||||||
|
''', localized_datetime, location.longitude, location.latitude, location.elevation, location.city, location.state,
|
||||||
|
location.zip, location.street, action, device_type, device_model, device_name, device_os,
|
||||||
|
location.class_, location.type, location.name, location.display_name,
|
||||||
|
location.amenity, location.house_number, location.road, location.quarter, location.neighbourhood,
|
||||||
|
location.suburb, location.county, location.country_code, location.country)
|
||||||
|
|
||||||
await conn.close()
|
await conn.close()
|
||||||
L.INFO(f"Successfully posted location: {location.latitude}, {location.longitude} on {localized_datetime}")
|
L.INFO(f"Successfully posted location: {location.latitude}, {location.longitude}, {location.elevation} on {localized_datetime}")
|
||||||
return {
|
return {
|
||||||
'datetime': localized_datetime,
|
'datetime': localized_datetime,
|
||||||
'latitude': location.latitude,
|
'latitude': location.latitude,
|
||||||
'longitude': location.longitude,
|
'longitude': location.longitude,
|
||||||
|
'elevation': location.elevation,
|
||||||
'city': location.city,
|
'city': location.city,
|
||||||
'state': location.state,
|
'state': location.state,
|
||||||
'zip': location.zip,
|
'zip': location.zip,
|
||||||
'street': location.street,
|
'street': location.street,
|
||||||
'elevation': location.elevation,
|
|
||||||
'action': action,
|
'action': action,
|
||||||
'device_type': device_type,
|
'device_type': device_type,
|
||||||
'device_model': device_model,
|
'device_model': device_model,
|
||||||
'device_name': device_name,
|
'device_name': device_name,
|
||||||
'device_os': device_os
|
'device_os': device_os,
|
||||||
|
'class_': location.class_,
|
||||||
|
'type': location.type,
|
||||||
|
'name': location.name,
|
||||||
|
'display_name': location.display_name,
|
||||||
|
'amenity': location.amenity,
|
||||||
|
'house_number': location.house_number,
|
||||||
|
'road': location.road,
|
||||||
|
'quarter': location.quarter,
|
||||||
|
'neighbourhood': location.neighbourhood,
|
||||||
|
'suburb': location.suburb,
|
||||||
|
'county': location.county,
|
||||||
|
'country_code': location.country_code,
|
||||||
|
'country': location.country
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
L.ERR(f"Error posting location {e}")
|
L.ERR(f"Error posting location {e}")
|
||||||
|
@ -428,6 +455,7 @@ async def post_location(location: Location):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@locate.post("/locate")
|
@locate.post("/locate")
|
||||||
async def post_locate_endpoint(locations: Union[Location, List[Location]]):
|
async def post_locate_endpoint(locations: Union[Location, List[Location]]):
|
||||||
responses = []
|
responses = []
|
||||||
|
@ -451,22 +479,26 @@ async def post_locate_endpoint(locations: Union[Location, List[Location]]):
|
||||||
"device_os": "Unknown"
|
"device_os": "Unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
L.DEBUG(f"datetime before localization: {location.datetime}")
|
# L.DEBUG(f"datetime before localization: {location.datetime}")
|
||||||
# Convert datetime string to timezone-aware datetime object
|
|
||||||
location.datetime = await localize_datetime(location.datetime)
|
location.datetime = await localize_datetime(location.datetime)
|
||||||
L.DEBUG(f"datetime after localization: {location.datetime}")
|
# L.DEBUG(f"datetime after localization: {location.datetime}")
|
||||||
|
L.DEBUG(f"Location received for processing: {location}")
|
||||||
# Perform reverse geocoding
|
# Perform reverse geocoding
|
||||||
geocoded_location = await reverse_geocode(location.latitude, location.longitude)
|
geocoded_location = await reverse_geocode(location.latitude, location.longitude)
|
||||||
if geocoded_location:
|
if geocoded_location:
|
||||||
# Update location with geocoded information
|
L.DEBUG(f"Reverse geocoding result: {geocoded_location}")
|
||||||
for field in location.__fields__:
|
for field in location.__fields__:
|
||||||
if getattr(location, field) is None:
|
if getattr(location, field) is None:
|
||||||
setattr(location, field, getattr(geocoded_location, field))
|
setattr(location, field, getattr(geocoded_location, field))
|
||||||
|
else:
|
||||||
|
L.WARN(f"Geocoding failed!")
|
||||||
|
L.DEBUG(f"Final location submitted to database: {location}")
|
||||||
|
|
||||||
location_entry = await post_location(location)
|
location_entry = await post_location(location)
|
||||||
if location_entry:
|
if location_entry:
|
||||||
responses.append({"location_data": location_entry}) # Add weather data if necessary
|
responses.append({"location_data": location_entry}) # Add weather data if necessary
|
||||||
|
else:
|
||||||
|
L.WARN(f"Posing location to database appears to have failed.")
|
||||||
|
|
||||||
return {"message": "Locations and weather updated", "results": responses}
|
return {"message": "Locations and weather updated", "results": responses}
|
||||||
|
|
||||||
|
|
|
@ -667,7 +667,7 @@ async def generate_banner(dt, location: Location = None, forecast: str = None, m
|
||||||
if location.display_name:
|
if location.display_name:
|
||||||
display_name += f"{location.display_name}"
|
display_name += f"{location.display_name}"
|
||||||
|
|
||||||
else:
|
elif:
|
||||||
display_name += f"{location.road}, " if location.road else ""
|
display_name += f"{location.road}, " if location.road else ""
|
||||||
display_name += f"the {location.neighbourhood} neighbourhood of " if location.neighbourhood else ""
|
display_name += f"the {location.neighbourhood} neighbourhood of " if location.neighbourhood else ""
|
||||||
display_name += f"the {location.suburb} suburb of " if location.suburb else ""
|
display_name += f"the {location.suburb} suburb of " if location.suburb else ""
|
||||||
|
|
Loading…
Reference in a new issue