Merge pull request #3 from Mason10198/develop

Develop
pull/17/head
Mason10198 3 years ago committed by GitHub
commit a6e87b223e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -60,6 +60,10 @@ sayalert_blocked_events = config["Blocking"].get("SayAlertBlockedEvents").split(
tailmessage_blocked_events = (
config["Blocking"].get("TailmessageBlockedEvents").split(",")
)
# Maximum number of alerts to process
max_alerts = config["Alerting"].getint("MaxAlerts", fallback=99)
# Configuration for tailmessage
tailmessage_config = config["Tailmessage"]
# Flag to enable/disable tailmessage
@ -271,7 +275,10 @@ def getAlerts(countyCodes):
Returns:
alerts (list): List of active weather alerts.
"""
# Check if we need to inject alerts from the config
# Severity mappings
severity_mapping_api = {"Extreme": 4, "Severe": 3, "Moderate": 2, "Minor": 1, "Unknown": 0}
severity_mapping_words = {"Warning": 4, "Watch": 3, "Advisory": 2, "Statement": 1}
if config.getboolean("DEV", "INJECT", fallback=False):
logger.debug("DEV Alert Injection Enabled")
alerts = [
@ -280,12 +287,13 @@ def getAlerts(countyCodes):
logger.debug("Injecting alerts: {}".format(alerts))
return alerts
alerts = set() # Change list to set to automatically avoid duplicate alerts
alerts = []
current_time = datetime.now(timezone.utc)
logger.debug("Checking for alerts in {}".format(countyCodes))
for countyCode in countyCodes:
logger.debug("Checking for alerts in {}".format(countyCode))
url = "https://api.weather.gov/alerts/active?zone={}".format(countyCode)
# url = "https://api.weather.gov/alerts/active?zone={}".format(countyCode)
url = "https://api.weather.gov/alerts/active?area=AR" # THIS RETURNS ALL ACTIVE ALERTS IN THE US
logger.debug("Requesting {}".format(url))
response = requests.get(url)
logger.debug("Response: {}\n\n".format(response.text))
@ -293,10 +301,12 @@ def getAlerts(countyCodes):
if response.status_code == 200:
alert_data = response.json()
for feature in alert_data["features"]:
effective = feature["properties"].get("effective")
expires = feature["properties"].get("expires")
if expires:
if effective and expires:
effective_time = parser.isoparse(effective)
expires_time = parser.isoparse(expires)
if expires_time > current_time:
if effective_time <= current_time < expires_time:
event = feature["properties"]["event"]
for global_blocked_event in global_blocked_events:
if fnmatch.fnmatch(event, global_blocked_event):
@ -307,8 +317,14 @@ def getAlerts(countyCodes):
)
break
else:
alerts.add(event) # Add event to set
logger.debug("{}: {}".format(countyCode, event))
severity = feature["properties"].get("severity")
if severity is None:
# Determine severity from the last word of the event if not provided
last_word = event.split()[-1]
severity = severity_mapping_words.get(last_word, 0)
else:
severity = severity_mapping_api.get(severity, 0)
alerts.append((event, severity)) # Add event to list as a tuple
else:
logger.error(
"Failed to retrieve alerts for {}, HTTP status code {}, response: {}".format(
@ -316,8 +332,25 @@ def getAlerts(countyCodes):
)
)
alerts = list(alerts) # Convert set back to list
alerts.sort(key=lambda x: WS.index(x) if x in WS else len(WS))
# Convert list to set to eliminate duplicates, then convert back to list
alerts = list(set(alerts))
# Sort by both API-provided severity and 'words' severity
alerts.sort(
key=lambda x: (
x[1], # API-provided severity
severity_mapping_words.get(x[0].split()[-1], 0) # 'words' severity
),
reverse=True
)
logger.debug("Sorted alerts: (alert), (severity)")
for alert in alerts:
logger.debug(alert)
# Only keep the events (not the severities)
alerts = [alert[0] for alert in alerts[:max_alerts]] # Only keep the first 'max_alerts' alerts
return alerts
@ -339,8 +372,8 @@ def sayAlert(alerts):
alert_count = 0 # Counter for alerts added to combined_sound
for alert in alerts:
# Check if alert is in the SayAlertBlockedEvents list
if alert in sayalert_blocked_events:
# Check if alert matches any pattern in the SayAlertBlockedEvents list
if any(fnmatch.fnmatch(alert, blocked_event) for blocked_event in sayalert_blocked_events):
logger.debug("SayAlert blocking {} as per configuration".format(alert))
continue
@ -420,8 +453,8 @@ def buildTailmessage(alerts):
os.path.join(sounds_path, "ALERTS", "SWP95.wav")
)
for alert in alerts:
# Check if alert is in the TailmessageBlockedEvents list
if alert in tailmessage_blocked_events:
# Check if alert matches any pattern in the TailmessageBlockedEvents list
if any(fnmatch.fnmatch(alert, blocked_event) for blocked_event in tailmessage_blocked_events):
logger.debug("Alert blocked by TailmessageBlockedEvents: {}".format(alert))
continue

@ -28,6 +28,16 @@ SayAlert = True
; Either True or False
SayAllClear = True
; Specify an optional maximum number of alerts to be processed.
; SkywarnPlus will retrieve all local alerts from the NWS API
; and order them by level of severity. This setting will cause
; SkywarnPlus to only process the N most severe alerts.
; e.g. If the alerts in your area are...
; [Tornado Warning, Severe Thunderstorm Warning, Flood Watch, Special Weather Statement],
; and MaxAlerts = 2, then SkywarnPlus will only process the Tornado Warning and Severe Thunderstorm Warning.
; Example: MaxAlerts = 3
MaxAlerts = 5
; Optional alternate path to the directory where sound files are stored
; Default is SkywarnPlus/SOUNDS
; Example: SoundsPath = /home/repeater/
@ -37,16 +47,21 @@ SayAllClear = True
[Blocking]
; GLOBAL BLOCKING - These alerts will be completely ignored and filtered out of the entire SkywarnPlus workflow
; CASE SENSITIVE list of events to ignore, comma separated. Wildcards can be used, e.g. *Statement, *Advisory
; Example: GlobalBlockedEvents = *Statement, *Advisory
GlobalBlockedEvents =
; SayAlert Blocking
; These alerts will be blocked from being spoken when they are received
; These alerts will still be added to the tailmessage
; CASE SENSITIVE list of events to ignore, comma separated.
; Example: SayAlertBlockedEvents = *Statement, *Advisory
SayAlertBlockedEvents =
; Tailmessage Blocking
; These alerts will be blocked from being added to the tailmessage
; These alerts will still be spoken when they are received
; CASE SENSITIVE list of events to ignore, comma separated.
; Example: TailmessageBlockedEvents = *Statement, *Advisory
TailmessageBlockedEvents =
; Tail message settings
@ -99,10 +114,13 @@ RptLinkCT = CT-LINK.ulaw
CTAlerts = Hurricane Force Wind Warning,
Severe Thunderstorm Warning,
Tropical Storm Warning,
Coastal Flood Warning,
Winter Storm Warning,
Thunderstorm Warning,
Extreme Wind Warning,
Storm Surge Warning,
Dust Storm Warning,
Avalanche Warning,
Ice Storm Warning,
Hurricane Warning,
Blizzard Warning,

Loading…
Cancel
Save

Powered by TurnKey Linux.