mirror of
https://github.com/SpudGunMan/meshing-around.git
synced 2026-03-28 17:32:36 +01:00
145 lines
5.5 KiB
Python
145 lines
5.5 KiB
Python
# helper functions to use location data
|
|
# K7MHI Kelly Keeton 2024
|
|
|
|
import json
|
|
from geopy.geocoders import Nominatim # pip install geopy
|
|
import maidenhead as mh # pip install maidenhead
|
|
import requests # pip install requests
|
|
import bs4 as bs # pip install beautifulsoup4
|
|
|
|
URL_TIMEOUT = 10 # wait time for URL requests
|
|
DAYS_OF_WEATHER = 4 # weather forecast days, the first two rows are today and tonight
|
|
# unified error messages to be able to test them from tests
|
|
NO_DATA_NOGPS = "no location data: does your device have GPS?"
|
|
ERROR_FETCHING_DATA = "error fetching data"
|
|
|
|
def where_am_i(lat=0, lon=0):
|
|
whereIam = ""
|
|
if float(lat) == 0 and float(lon) == 0:
|
|
return NO_DATA_NOGPS
|
|
# initialize Nominatim API
|
|
geolocator = Nominatim(user_agent="mesh-bot")
|
|
|
|
location = geolocator.reverse(lat + ", " + lon)
|
|
address = location.raw['address']
|
|
address_components = ['house_number', 'road', 'city', 'state', 'postcode', 'county', 'country']
|
|
whereIam += ' '.join([address.get(component, '') for component in address_components if component in address])
|
|
grid = mh.to_maiden(float(lat), float(lon))
|
|
whereIam += " Grid: " + grid
|
|
|
|
return whereIam
|
|
|
|
def get_tide(lat=0, lon=0):
|
|
station_id = ""
|
|
if float(lat) == 0 and float(lon) == 0:
|
|
return NO_DATA_NOGPS
|
|
station_lookup_url = "https://api.tidesandcurrents.noaa.gov/mdapi/prod/webapi/tidepredstations.json?lat=" + str(lat) + "&lon=" + str(lon) + "&radius=50"
|
|
try:
|
|
station_data = requests.get(station_lookup_url, timeout=URL_TIMEOUT)
|
|
if station_data.ok:
|
|
station_json = station_data.json()
|
|
else:
|
|
return ERROR_FETCHING_DATA
|
|
except (requests.exceptions.RequestException, json.JSONDecodeError):
|
|
return ERROR_FETCHING_DATA
|
|
|
|
station_id = station_json['stationList'][0]['stationId']
|
|
|
|
station_url = "https://tidesandcurrents.noaa.gov/noaatidepredictions.html?id=" + station_id
|
|
|
|
try:
|
|
station_data = requests.get(station_url, timeout=URL_TIMEOUT)
|
|
if not station_data.ok:
|
|
return ERROR_FETCHING_DATA
|
|
except (requests.exceptions.RequestException):
|
|
return ERROR_FETCHING_DATA
|
|
|
|
# extract table class="table table-condensed"
|
|
soup = bs.BeautifulSoup(station_data.text, 'html.parser')
|
|
table = soup.find('table', class_='table table-condensed')
|
|
|
|
# extract rows
|
|
rows = table.find_all('tr')
|
|
# extract data from rows
|
|
tide_data = []
|
|
for row in rows:
|
|
row_text = ""
|
|
cols = row.find_all('td')
|
|
for col in cols:
|
|
row_text += col.text + " "
|
|
tide_data.append(row_text)
|
|
# format tide data into a string
|
|
tide_string = ""
|
|
for data in tide_data:
|
|
tide_string += data + "\n"
|
|
# trim off last newline
|
|
tide_string = tide_string[:-1]
|
|
return tide_string
|
|
|
|
def get_weather(lat=0, lon=0, unit=0):
|
|
weather = ""
|
|
if float(lat) == 0 and float(lon) == 0:
|
|
return NO_DATA_NOGPS
|
|
weather_url = "https://forecast.weather.gov/MapClick.php?FcstType=text&lat=" + str(lat) + "&lon=" + str(lon) + "&unit=" + str(unit)
|
|
try:
|
|
weather_data = requests.get(weather_url, timeout=URL_TIMEOUT)
|
|
if not weather_data.ok:
|
|
return ERROR_FETCHING_DATA
|
|
except (requests.exceptions.RequestException):
|
|
return ERROR_FETCHING_DATA
|
|
|
|
|
|
soup = bs.BeautifulSoup(weather_data.text, 'html.parser')
|
|
table = soup.find('div', id="detailed-forecast-body")
|
|
|
|
if table is None:
|
|
return "no weather data found on NOAA for your location"
|
|
else:
|
|
# get rows
|
|
rows = table.find_all('div', class_="row")
|
|
|
|
# extract data from rows
|
|
for row in rows:
|
|
# shrink the text
|
|
line = replace_weather(row.text)
|
|
# only grab a few days of weather
|
|
if len(weather.split("\n")) < DAYS_OF_WEATHER:
|
|
weather += line + "\n"
|
|
# trim off last newline
|
|
weather = weather[:-1]
|
|
|
|
return weather
|
|
|
|
def replace_weather(row):
|
|
line = row.replace("Monday", "Mon ") \
|
|
.replace("Tuesday", "Tue ") \
|
|
.replace("Wednesday", "Wed ") \
|
|
.replace("Thursday", "Thu ") \
|
|
.replace("Friday", "Fri ") \
|
|
.replace("Saturday", "Sat ") \
|
|
.replace("Today", "Today ") \
|
|
.replace("Tonight", "Tonight ") \
|
|
.replace("Tomorrow", "Tomorrow ") \
|
|
.replace("This Afternoon", "Afternoon ") \
|
|
.replace("northwest", "NW") \
|
|
.replace("northeast", "NE") \
|
|
.replace("southwest", "SW") \
|
|
.replace("southeast", "SE") \
|
|
.replace("north", "N") \
|
|
.replace("south", "S") \
|
|
.replace("east", "E") \
|
|
.replace("west", "W") \
|
|
.replace("Northwest", "NW") \
|
|
.replace("Northeast", "NE") \
|
|
.replace("Southwest", "SW") \
|
|
.replace("Southeast", "SE") \
|
|
.replace("North", "N") \
|
|
.replace("South", "S") \
|
|
.replace("East", "E") \
|
|
.replace("West", "W") \
|
|
.replace("precipitation", "precip") \
|
|
.replace("showers", "shwrs") \
|
|
.replace("thunderstorms", "t-storms")
|
|
|
|
return line
|