From c27b6ed8a1e86c4096ee511f6877499dfcab69b5 Mon Sep 17 00:00:00 2001 From: SpudGunMan Date: Thu, 19 Dec 2024 16:18:38 -0800 Subject: [PATCH] enhanceEmergency Alerting --- README.md | 16 ++++++------ config.template | 13 +++++----- mesh_bot.py | 8 +++--- modules/settings.py | 27 ++++++++------------ modules/system.py | 61 ++++++++++++++++++++++++++++++++++----------- 5 files changed, 75 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 5695fdb..7ca40a5 100644 --- a/README.md +++ b/README.md @@ -213,19 +213,17 @@ alert_interface = 1 ### EAS Alerting To Alert on Mesh with the EAS API you can set the channels and enable, checks every 20min. -#### FEMA iPAWS/EAS -This uses the SAME, FIPS, ZIP code to locate the alerts in the feed. By default ignoring Test messages. femaAlertBroadcastCh is currently not written, still under development. +#### FEMA iPAWS/EAS and UK.gov +This uses USA: SAME, FIPS, ZIP code to locate the alerts in the feed. By default ignoring Test messages. UK.gov for England ```ini -# FEMA IPAWS/CAP Alert Broadcast -femaAlertBroadcastEnabled = True -# FEMA IPAWS/CAP Alert Broadcast Channels -femaAlertBroadcastCh = 2,4 -# Ignore any headline that includes the word Test -ignoreFEMAtest = True -# comma separated list of codes trigger local alert. (e.g., SAME, FIPS, ZIP) +eAlertBroadcastEnabled = False # Goverment IPAWS/CAP Alert Broadcast +eAlertBroadcastCh = 2,3 # Goverment Emergency IPAWS/CAP Alert Broadcast Channels +ignoreFEMAtest = True # Ignore any headline that includes the word Test +# comma separated list of codes (e.g., SAME,FIPS,ZIP) trigger local alert. # find your SAME https://www.weather.gov/nwr/counties mySAME = 053029,053073 +enableGBalerts = False # use UK.gov for alert source ``` #### NOAA EAS diff --git a/config.template b/config.template index cd56976..7fad863 100644 --- a/config.template +++ b/config.template @@ -127,10 +127,8 @@ NOAAalertCount = 2 # use Open-Meteo API for weather data not NOAA useful for non US locations UseMeteoWxAPI = False -enableGBalerts = False -# NOAA Hydrology -# unique identifiers, LID or USGS ID +# NOAA Hydrology unique identifiers, LID or USGS ID riverListDefault = # EAS Alert Broadcast @@ -138,15 +136,16 @@ wxAlertBroadcastEnabled = False # EAS Alert Broadcast Channels wxAlertBroadcastCh = 2 -# FEMA IPAWS/CAP Alert Broadcast -femaAlertBroadcastEnabled = False -# FEMA IPAWS/CAP Alert Broadcast Channels -femaAlertBroadcastCh = 2 +# Goverment IPAWS/CAP Alert Broadcast +eAlertBroadcastEnabled = False +# Goverment Emergency IPAWS/CAP Alert Broadcast Channels +eAlertBroadcastCh = 2 # Ignore any headline that includes the word Test ignoreFEMAtest = True # comma separated list of codes (e.g., SAME,FIPS,ZIP) trigger local alert. # find your SAME https://www.weather.gov/nwr/counties mySAME = 053029,053073 +enableGBalerts = False # Satalite Pass Prediction # Register for free API https://www.n2yo.com/login/ diff --git a/mesh_bot.py b/mesh_bot.py index 600cc6a..da2519f 100755 --- a/mesh_bot.py +++ b/mesh_bot.py @@ -43,8 +43,8 @@ def auto_response(message, snr, rssi, hop, pkiStatus, message_from_id, channel_n "cqcq": lambda: handle_ping(message_from_id, deviceID, message, hop, snr, rssi, isDM, channel_number), "cqcqcq": lambda: handle_ping(message_from_id, deviceID, message, hop, snr, rssi, isDM, channel_number), "dopewars": lambda: handleDopeWars(message, message_from_id, deviceID), - "ea": lambda: handle_fema_alerts(message, message_from_id, deviceID), - "ealert": lambda: handle_fema_alerts(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), "email:": lambda: handle_email(message_from_id, message), "games": lambda: gamesCmdList, "globalthermonuclearwar": lambda: handle_gTnW(), @@ -686,7 +686,7 @@ def handle_wxc(message_from_id, deviceID, cmd): weather = get_NOAAweather(str(location[0]), str(location[1])) return weather -def handle_fema_alerts(message, message_from_id, deviceID): +def handle_emergency_alerts(message, message_from_id, deviceID): location = get_node_location(message_from_id, deviceID) if enableGBalerts: # UK Alerts @@ -1278,6 +1278,8 @@ async def start_rx(): logger.debug(f"System: File Monitor News Reader Enabled for {news_file_path}") if wxAlertBroadcastEnabled: logger.debug(f"System: Weather Alert Broadcast Enabled on channels {wxAlertBroadcastChannel}") + if emergencyAlertBrodcastEnabled: + logger.debug(f"System: Emergency Alert Broadcast Enabled on channels {emergencyAlertBroadcastCh}") if emergency_responder_enabled: logger.debug(f"System: Emergency Responder Enabled on channels {emergency_responder_alert_channel} for interface {emergency_responder_alert_interface}") if enableSMTP: diff --git a/modules/settings.py b/modules/settings.py index 3589592..5c51255 100644 --- a/modules/settings.py +++ b/modules/settings.py @@ -155,28 +155,23 @@ try: latitudeValue = config['location'].getfloat('lat', 48.50) longitudeValue = config['location'].getfloat('lon', -123.0) use_meteo_wxApi = config['location'].getboolean('UseMeteoWxAPI', False) # default False use NOAA - enableGBalerts = config['location'].getboolean('enableGBalerts', False) # default False use_metric = config['location'].getboolean('useMetric', False) # default Imperial units - forecastDuration = config['location'].getint('NOAAforecastDuration', 4) # NOAA forcast days - numWxAlerts = config['location'].getint('NOAAalertCount', 2) # default 2 alerts - wxAlertsEnabled = config['location'].getboolean('NOAAalertsEnabled', True) # default True not enabled yet repeater_lookup = config['location'].get('repeaterLookup', 'rbook') # default repeater lookup source - mySAME = config['location'].get('mySAME', '').split(',') # default empty - ipawsPIN = config['location'].get('ipawsPIN', '000000') # default 000000 - femaAlertBroadcastEnabled = config['location'].getboolean('femaAlertBroadcastEnabled', False) # default False - femaAlertBroadcastCh = config['location'].get('femaAlertBroadcastCh', '2').split(',') # default Channel 2 - wxAlertBroadcastEnabled = config['location'].getboolean('wxAlertBroadcastEnabled', False) # default False - ignoreFEMAtest = config['location'].getboolean('ignoreFEMAtest', True) # default True n2yoAPIKey = config['location'].get('n2yoAPIKey', '') # default empty satListConfig = config['location'].get('satList', '25544').split(',') # default 25544 ISS riverListDefault = config['location'].get('riverList', '').split(',') # default 12061500 Skagit River - # brodcast channel for weather alerts + # location alerts + emergencyAlertBrodcastEnabled = config['location'].getboolean('eAlertBroadcastEnabled', False) # default False + wxAlertBroadcastEnabled = config['location'].getboolean('wxAlertBroadcastEnabled', False) # default False + enableGBalerts = config['location'].getboolean('enableGBalerts', False) # default False + wxAlertsEnabled = config['location'].getboolean('NOAAalertsEnabled', True) # default True + mySAME = config['location'].get('mySAME', '').split(',') # default empty + forecastDuration = config['location'].getint('NOAAforecastDuration', 4) # NOAA forcast days + numWxAlerts = config['location'].getint('NOAAalertCount', 2) # default 2 alerts + ipawsPIN = config['location'].get('ipawsPIN', '000000') # default 000000 + ignoreFEMAtest = config['location'].getboolean('ignoreFEMAtest', True) # default True wxAlertBroadcastChannel = config['location'].get('wxAlertBroadcastCh') - if wxAlertBroadcastChannel: - if ',' in wxAlertBroadcastChannel: - wxAlertBroadcastChannel = config['location'].get('wxAlertBroadcastCh').split(',') - else: - wxAlertBroadcastChannel = config['location'].getint('wxAlertBroadcastCh', 2) # default 2 + emergencyAlertBroadcastCh = config['location'].get('eAlertBroadcastCh', '2').split(',') # default Channel 2 # bbs bbs_enabled = config['bbs'].getboolean('enabled', False) diff --git a/modules/system.py b/modules/system.py index 48c4fb0..ba4c4b1 100644 --- a/modules/system.py +++ b/modules/system.py @@ -665,7 +665,7 @@ def handleMultiPing(nodeID=0, deviceID=1): break -def handleWxBroadcast(deviceID=1): +def handleAlertBroadcast(deviceID=1): # only allow API call every 20 minutes # the watchdog will call this function 3 times, seeing possible throttling on the API clock = datetime.now() @@ -675,15 +675,42 @@ def handleWxBroadcast(deviceID=1): return False # check for alerts - alert = alertBrodcastNOAA() - if alert: - msg = f"🚨 {alert[1]} EAS ALERTs: {alert[0]}" - if isinstance(wxAlertBroadcastChannel, list): - for channel in wxAlertBroadcastChannel: - send_message(msg, int(channel), 0, deviceID) - else: - send_message(msg, wxAlertBroadcastChannel, 0, deviceID) - return True + alertWx = alertBrodcastNOAA() + alertFema = getIpawsAlert(latitudeValue,longitudeValue, shortAlerts=True) + alertUk = get_govUK_alerts(latitudeValue, longitudeValue) + + # format alert + wxAlert = f"🚨 {alertWx[1]} EAS WX ALERT: {alertWx[0]}" + femaAlert = alertFema + ukAlert = alertUk + + if emergencyAlertBrodcastEnabled: + if NO_ALERTS not in femaAlert: + if isinstance(emergencyAlertBroadcastCh, list): + for channel in emergencyAlertBroadcastCh: + send_message(femaAlert, int(channel), 0, deviceID) + else: + send_message(femaAlert, emergencyAlertBroadcastCh, 0, deviceID) + return True + if NO_ALERTS not in ukAlert: + if isinstance(emergencyAlertBroadcastCh, list): + for channel in emergencyAlertBroadcastCh: + send_message(ukAlert, int(channel), 0, deviceID) + else: + send_message(ukAlert, emergencyAlertBroadcastCh, 0, deviceID) + return True + + # pause for 10 seconds + time.sleep(10) + + if wxAlertBroadcastEnabled: + if wxAlert: + if isinstance(wxAlertBroadcastChannel, list): + for channel in wxAlertBroadcastChannel: + send_message(wxAlert, int(channel), 0, deviceID) + else: + send_message(wxAlert, wxAlertBroadcastChannel, 0, deviceID) + return True def onDisconnect(interface): global retry_int1, retry_int2 @@ -1090,8 +1117,10 @@ async def watchdog(): # multiPing handler handleMultiPing(0,1) - if wxAlertBroadcastEnabled: - handleWxBroadcast(1) + # Alert Broadcast + if wxAlertBroadcastEnabled or emergencyAlertBrodcastEnabled: + # weather alerts + handleAlertBroadcast(1) # Telemetry data int1Data = displayNodeTelemetry(0, 1) @@ -1120,10 +1149,12 @@ async def watchdog(): await handleSentinel(2) # multiPing handler - handleMultiPing(0,2) + handleMultiPing(0,1) - if wxAlertBroadcastEnabled: - handleWxBroadcast(2) + # Alert Broadcast + if wxAlertBroadcastEnabled or emergencyAlertBrodcastEnabled: + # weather alerts + handleAlertBroadcast(1) # Telemetry data int2Data = displayNodeTelemetry(0, 2)