diff --git a/README.md b/README.md index b12e658..8654566 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Welcome to the Mesh Bot project! This feature-rich bot is designed to enhance yo - **New Node Hello**: Send a hello to any new node seen in text message. ### Interactive AI and Data Lookup -- **NOAA location Data**: Get localized weather(alerts), River Flow, and Tide information. Open-Meteo is used for wx only outside NOAA coverage. +- **NOAA/USGS location Data**: Get localized weather(alerts), Earthquake, River Flow, and Tide information. Open-Meteo is used for wx only outside NOAA coverage. - **Wiki Integration**: Look up data using Wikipedia results. - **Ollama LLM AI**: Interact with the [Ollama](https://github.com/ollama/ollama/tree/main/docs) LLM AI for advanced queries and responses. - **Satalite Pass Info**: Get passes for satalite at your location. @@ -101,6 +101,7 @@ git clone https://github.com/spudgunman/meshing-around | Command | Description | | |---------|-------------|------------------- | `ea` and `ealert` | Return FEMA iPAWS/EAS alerts in USA or DE Headline or expanded details for USA | | +| `earthquake` | Returns the largest and number of USGS events for the location | | | `hfcond` | Returns a table of HF solar conditions | | | `rlist` | Returns a table of nearby repeaters from RepeaterBook | | | `riverflow` | Return information from NOAA for river flow info. Example: `riverflow modules/settings.py`| | diff --git a/mesh_bot.py b/mesh_bot.py index a76db89..784a7e3 100755 --- a/mesh_bot.py +++ b/mesh_bot.py @@ -52,6 +52,7 @@ def auto_response(message, snr, rssi, hop, pkiStatus, message_from_id, channel_n "dopewars": lambda: handleDopeWars(message, message_from_id, deviceID), "ea": lambda: handle_emergency_alerts(message, message_from_id, deviceID), "ealert": lambda: handle_emergency_alerts(message, message_from_id, deviceID), + "earthquake": lambda: handleEarthquake(message, message_from_id, deviceID), "email:": lambda: handle_email(message_from_id, message), "games": lambda: gamesCmdList, "globalthermonuclearwar": lambda: handle_gTnW(), @@ -785,6 +786,11 @@ def handle_emergency_alerts(message, message_from_id, deviceID): else: # Headlines only FEMA return getIpawsAlert(str(location[0]), str(location[1]), shortAlerts=True) + +def handleEarthquake(message, message_from_id, deviceID): + location = get_node_location(message_from_id, deviceID) + if "earthquake" in message.lower(): + return checkUSGSEarthQuake(str(location[0]), str(location[1])) def handle_checklist(message, message_from_id, deviceID): name = get_name_from_number(message_from_id, 'short', deviceID) diff --git a/modules/locationdata.py b/modules/locationdata.py index 7b813a6..3656703 100644 --- a/modules/locationdata.py +++ b/modules/locationdata.py @@ -9,7 +9,7 @@ import bs4 as bs # pip install beautifulsoup4 import xml.dom.minidom from modules.log import * -trap_list_location = ("whereami", "wx", "wxa", "wxalert", "rlist", "ea", "ealert", "riverflow", "valert") +trap_list_location = ("whereami", "wx", "wxa", "wxalert", "rlist", "ea", "ealert", "riverflow", "valert", "earthquake") def where_am_i(lat=0, lon=0, short=False, zip=False): whereIam = "" @@ -761,3 +761,48 @@ def get_nws_marine(zone, days=3): return NO_DATA_NOGPS return marine_pz_report +def checkUSGSEarthQuake(lat=0, lon=0): + if lat == 0 and lon == 0: + lat = latitudeValue + lon = longitudeValue + radius = 100 # km + magnitude = 1.5 + history = 7 # days + startDate = datetime.fromtimestamp(datetime.now().timestamp() - history*24*60*60).strftime("%Y-%m-%d") + USGSquake_url = f"https://earthquake.usgs.gov/fdsnws/event/1/query?&format=xml&latitude={lat}&longitude={lon}&maxradiuskm={radius}&minmagnitude={magnitude}&starttime={startDate}" + description_text = "" + quake_count = 0 + # fetch the earthquake data from USGS + try: + quake_data = requests.get(USGSquake_url, timeout=urlTimeoutSeconds) + if not quake_data.ok: + logger.warning("Location:Error fetching earthquake data from USGS") + quake_count = 0 + if not quake_data.text.strip(): + quake_count = 0 + try: + quake_xml = xml.dom.minidom.parseString(quake_data.text) + except Exception as e: + logger.warning(f"Location: USGS earthquake API returned invalid XML: {e}") + quake_count = 0 + except (requests.exceptions.RequestException): + logger.warning("Location:Error fetching earthquake data from USGS") + quake_count = 0 + + quake_xml = xml.dom.minidom.parseString(quake_data.text) + quake_count = len(quake_xml.getElementsByTagName("event")) + + #get largest mag in magnitude of the set of quakes + largest_mag = 0.0 + for event in quake_xml.getElementsByTagName("event"): + mag = event.getElementsByTagName("magnitude")[0] + mag_value = float(mag.getElementsByTagName("value")[0].childNodes[0].nodeValue) + if mag_value > largest_mag: + largest_mag = mag_value + # set description text + description_text = event.getElementsByTagName("description")[0].getElementsByTagName("text")[0].childNodes[0].nodeValue + + if quake_count == 0: + return NO_ALERTS + else: + return f"{quake_count} quakes in last {history} days within {radius}km of you largest was {largest_mag}. {description_text}"