diff --git a/recordGenerators/Alerts.py b/recordGenerators/Alerts.py index 246cb5b..fd2da32 100644 --- a/recordGenerators/Alerts.py +++ b/recordGenerators/Alerts.py @@ -1,4 +1,3 @@ -from weakref import KeyedRef import requests import json import os @@ -33,7 +32,10 @@ def getAlerts(location): response = requests.get(fetchUrl) theCode = response.status_code - + + #Our global variables + + #Set the actions based on response code if theCode == 204: print('No alerts for area ' + location + '.\n') @@ -64,261 +66,255 @@ def getAlerts(location): return elif theCode == 200: pass + + #Alright lets map our headline variables. + l.debug('Found Alert for ' + location + '\n') + dataH = response.json() + alertsRoot = dataH['alerts'] + + for x in alertsRoot: + detailKey = x['detailKey'] + #Lets get map our detail variables. + detailsUrl = 'https://api.weather.com/v3/alerts/detail?alertId=' + detailKey + '&format=json&language=en-US&apiKey=' + detailsApiKey + detailsResponse = requests.get(detailsUrl) + dataD = detailsResponse.json() + detailsRoot = dataD['alertDetail'] + theDetailsText = detailsRoot['texts'] + detailsText = theDetailsText[0] + descriptionRaw = detailsText['description'] + language = detailsText['languageCode'] + Identifier = location + '_' + x['phenomena'] + '_' + x['significance'] + '_' + str(x['processTimeUTC']) + + #Is this for a NWS Zone or County? + last4 = location[2:] + locationType = None + if 'C' in last4: + locationType = 'C' + elif 'Z' in last4: + locationType = 'Z' + + #theIdent = str(Identifier) + try: + thecheck = open('./.temp/alertmanifest.txt', "r") + check = thecheck.read() + + if check.find(Identifier) != -1: + l.debug("Alert already sent...") + return + except FileNotFoundError: + l.warning("alert manifest does not exist (yet)") + k += 1 #We have an alert to send! + + #Lets Map Our Vocal Codes! + vocalCheck = x['phenomena'] + '_' + x['significance'] + vocalCode = None - try: - #Alright lets map our headline variables. - l.debug('Found Alert for ' + location + '\n') - dataH = response.json() - alertsRoot = dataH['alerts'] + if vocalCheck == 'HU_W': + vocalCode = 'HE001' + elif vocalCheck == 'TY_W': + vocalCode = 'HE002' + elif vocalCheck == 'HI_W': + vocalCode = 'HE003' + elif vocalCheck == 'TO_A': + vocalCode = 'HE004' + elif vocalCheck == 'SV_A': + vocalCode = 'HE005' + elif vocalCheck == 'HU_A': + vocalCode = 'HE006' + elif vocalCheck == 'TY_A': + vocalCode = 'HE007' + elif vocalCheck == 'TR_W': + vocalCode = 'HE008' + elif vocalCheck == 'TR_A': + vocalCode = 'HE009' + elif vocalCheck == 'TI_W': + vocalCode = 'HE010' + elif vocalCheck == 'HI_A': + vocalCode = 'HE011' + elif vocalCheck == 'TI_A': + vocalCode = 'HE012' + elif vocalCheck == 'BZ_W': + vocalCode = 'HE013' + elif vocalCheck == 'IS_W': + vocalCode = 'HE014' + elif vocalCheck == 'WS_W': + vocalCode = 'HE015' + elif vocalCheck == 'HW_W': + vocalCode = 'HE016' + elif vocalCheck == 'LE_W': + vocalCode = 'HE017' + elif vocalCheck == 'ZR_Y': + vocalCode = 'HE018' + elif vocalCheck == 'CF_W': + vocalCode = 'HE019' + elif vocalCheck == 'LS_W': + vocalCode = 'HE020' + elif vocalCheck == 'WW_Y': + vocalCode = 'HE021' + elif vocalCheck == 'LB_Y': + vocalCode = 'HE022' + elif vocalCheck == 'LE_Y': + vocalCode = 'HE023' + elif vocalCheck == 'BZ_A': + vocalCode = 'HE024' + elif vocalCheck == 'WS_A': + vocalCode = 'HE025' + elif vocalCheck == 'FF_A': + vocalCode = 'HE026' + elif vocalCheck == 'FA_A': + vocalCode = 'HE027' + elif vocalCheck == 'FA_Y': + vocalCode = 'HE028' + elif vocalCheck == 'HW_A': + vocalCode = 'HE029' + elif vocalCheck == 'LE_A': + vocalCode = 'HE030' + elif vocalCheck == 'SU_W': + vocalCode = 'HE031' + elif vocalCheck == 'LS_Y': + vocalCode = 'HE032' + elif vocalCheck == 'CF_A': + vocalCode = 'HE033' + elif vocalCheck == 'ZF_Y': + vocalCode = 'HE034' + elif vocalCheck == 'FG_Y': + vocalCode = 'HE035' + elif vocalCheck == 'SM_Y': + vocalCode = 'HE036' + elif vocalCheck == 'EC_W': + vocalCode = 'HE037' + elif vocalCheck == 'EH_W': + vocalCode = 'HE038' + elif vocalCheck == 'HZ_W': + vocalCode = 'HE039' + elif vocalCheck == 'FZ_W': + vocalCode = 'HE040' + elif vocalCheck == 'HT_Y': + vocalCode = 'HE041' + elif vocalCheck == 'WC_Y': + vocalCode = 'HE042' + elif vocalCheck == 'FR_Y': + vocalCode = 'HE043' + elif vocalCheck == 'EC_A': + vocalCode = 'HE044' + elif vocalCheck == 'EH_A': + vocalCode = 'HE045' + elif vocalCheck == 'HZ_A': + vocalCode = 'HE046' + elif vocalCheck == 'DS_W': + vocalCode = 'HE047' + elif vocalCheck == 'WI_Y': + vocalCode = 'HE048' + elif vocalCheck == 'SU_Y': + vocalCode = 'HE049' + elif vocalCheck == 'AS_Y': + vocalCode = 'HE050' + elif vocalCheck == 'WC_W': + vocalCode = 'HE051' + elif vocalCheck == 'FZ_A': + vocalCode = 'HE052' + elif vocalCheck == 'WC_A': + vocalCode = 'HE053' + elif vocalCheck == 'AF_W': + vocalCode = 'HE054' + elif vocalCheck == 'AF_Y': + vocalCode = 'HE055' + elif vocalCheck == 'DU_Y': + vocalCode = 'HE056' + elif vocalCheck == 'LW_Y': + vocalCode = 'HE057' + elif vocalCheck == 'LS_A': + vocalCode = 'HE058' + elif vocalCheck == 'HF_W': + vocalCode = 'HE059' + elif vocalCheck == 'SR_W': + vocalCode = 'HE060' + elif vocalCheck == 'GL_W': + vocalCode = 'HE061' + elif vocalCheck == 'HF_A': + vocalCode = 'HE062' + elif vocalCheck == 'UP_W': + vocalCode = 'HE063' + elif vocalCheck == 'SE_W': + vocalCode = 'HE064' + elif vocalCheck == 'SR_A': + vocalCode = 'HE065' + elif vocalCheck == 'GL_A': + vocalCode = 'HE066' + elif vocalCheck == 'MF_Y': + vocalCode = 'HE067' + elif vocalCheck == 'MS_Y': + vocalCode = 'HE068' + elif vocalCheck == 'SC_Y': + vocalCode = 'HE069' + elif vocalCheck == 'UP_Y': + vocalCode = 'HE073' + elif vocalCheck == 'LO_Y': + vocalCode = 'HE074' + elif vocalCheck == 'AF_V': + vocalCode = 'HE075' + elif vocalCheck == 'UP_A': + vocalCode = 'HE076' + elif vocalCheck == 'TAV_W': + vocalCode = 'HE077' + elif vocalCheck == 'TAV_A': + vocalCode = 'HE078' + elif vocalCheck == 'TO_W': + vocalCode = 'HE110' + else: + vocalCode = '' - for x in alertsRoot: - detailKey = x['detailKey'] - #Lets get map our detail variables. - detailsUrl = 'https://api.weather.com/v3/alerts/detail?alertId=' + detailKey + '&format=json&language=en-US&apiKey=' + detailsApiKey - detailsResponse = requests.get(detailsUrl) - dataD = detailsResponse.json() - detailsRoot = dataD['alertDetail'] - theDetailsText = detailsRoot['texts'] - detailsText = theDetailsText[0] - descriptionRaw = detailsText['description'] - language = detailsText['languageCode'] - Identifier = location + '_' + x['phenomena'] + '_' + x['significance'] + '_' + str(x['processTimeUTC']) - - #Is this for a NWS Zone or County? - last4 = location[2:] - locationType = None - if 'C' in last4: - locationType = 'C' - elif 'Z' in last4: - locationType = 'Z' - - #theIdent = str(Identifier) - try: - thecheck = open('./.temp/alertmanifest.txt', "r") - check = thecheck.read() - - if check.find(Identifier) != -1: - l.debug("Alert already sent...") - return - except FileNotFoundError: - l.warning("alert manifest does not exist (yet)") - k += 1 #We have an alert to send! - - #Lets Map Our Vocal Codes! - vocalCheck = x['phenomena'] + '_' + x['significance'] - vocalCode = None + #Do some date/time conversions + EndTimeUTCEpoch = x['expireTimeUTC'] + EndTimeUTC = datetime.utcfromtimestamp(EndTimeUTCEpoch).strftime('%Y%m%d%H%M') + #EndTimeUTC = EndTimeUTCString.astimezone(pytz.UTC) - if vocalCheck == 'HU_W': - vocalCode = 'HE001' - elif vocalCheck == 'TY_W': - vocalCode = 'HE002' - elif vocalCheck == 'HI_W': - vocalCode = 'HE003' - elif vocalCheck == 'TO_A': - vocalCode = 'HE004' - elif vocalCheck == 'SV_A': - vocalCode = 'HE005' - elif vocalCheck == 'HU_A': - vocalCode = 'HE006' - elif vocalCheck == 'TY_A': - vocalCode = 'HE007' - elif vocalCheck == 'TR_W': - vocalCode = 'HE008' - elif vocalCheck == 'TR_A': - vocalCode = 'HE009' - elif vocalCheck == 'TI_W': - vocalCode = 'HE010' - elif vocalCheck == 'HI_A': - vocalCode = 'HE011' - elif vocalCheck == 'TI_A': - vocalCode = 'HE012' - elif vocalCheck == 'BZ_W': - vocalCode = 'HE013' - elif vocalCheck == 'IS_W': - vocalCode = 'HE014' - elif vocalCheck == 'WS_W': - vocalCode = 'HE015' - elif vocalCheck == 'HW_W': - vocalCode = 'HE016' - elif vocalCheck == 'LE_W': - vocalCode = 'HE017' - elif vocalCheck == 'ZR_Y': - vocalCode = 'HE018' - elif vocalCheck == 'CF_W': - vocalCode = 'HE019' - elif vocalCheck == 'LS_W': - vocalCode = 'HE020' - elif vocalCheck == 'WW_Y': - vocalCode = 'HE021' - elif vocalCheck == 'LB_Y': - vocalCode = 'HE022' - elif vocalCheck == 'LE_Y': - vocalCode = 'HE023' - elif vocalCheck == 'BZ_A': - vocalCode = 'HE024' - elif vocalCheck == 'WS_A': - vocalCode = 'HE025' - elif vocalCheck == 'FF_A': - vocalCode = 'HE026' - elif vocalCheck == 'FA_A': - vocalCode = 'HE027' - elif vocalCheck == 'FA_Y': - vocalCode = 'HE028' - elif vocalCheck == 'HW_A': - vocalCode = 'HE029' - elif vocalCheck == 'LE_A': - vocalCode = 'HE030' - elif vocalCheck == 'SU_W': - vocalCode = 'HE031' - elif vocalCheck == 'LS_Y': - vocalCode = 'HE032' - elif vocalCheck == 'CF_A': - vocalCode = 'HE033' - elif vocalCheck == 'ZF_Y': - vocalCode = 'HE034' - elif vocalCheck == 'FG_Y': - vocalCode = 'HE035' - elif vocalCheck == 'SM_Y': - vocalCode = 'HE036' - elif vocalCheck == 'EC_W': - vocalCode = 'HE037' - elif vocalCheck == 'EH_W': - vocalCode = 'HE038' - elif vocalCheck == 'HZ_W': - vocalCode = 'HE039' - elif vocalCheck == 'FZ_W': - vocalCode = 'HE040' - elif vocalCheck == 'HT_Y': - vocalCode = 'HE041' - elif vocalCheck == 'WC_Y': - vocalCode = 'HE042' - elif vocalCheck == 'FR_Y': - vocalCode = 'HE043' - elif vocalCheck == 'EC_A': - vocalCode = 'HE044' - elif vocalCheck == 'EH_A': - vocalCode = 'HE045' - elif vocalCheck == 'HZ_A': - vocalCode = 'HE046' - elif vocalCheck == 'DS_W': - vocalCode = 'HE047' - elif vocalCheck == 'WI_Y': - vocalCode = 'HE048' - elif vocalCheck == 'SU_Y': - vocalCode = 'HE049' - elif vocalCheck == 'AS_Y': - vocalCode = 'HE050' - elif vocalCheck == 'WC_W': - vocalCode = 'HE051' - elif vocalCheck == 'FZ_A': - vocalCode = 'HE052' - elif vocalCheck == 'WC_A': - vocalCode = 'HE053' - elif vocalCheck == 'AF_W': - vocalCode = 'HE054' - elif vocalCheck == 'AF_Y': - vocalCode = 'HE055' - elif vocalCheck == 'DU_Y': - vocalCode = 'HE056' - elif vocalCheck == 'LW_Y': - vocalCode = 'HE057' - elif vocalCheck == 'LS_A': - vocalCode = 'HE058' - elif vocalCheck == 'HF_W': - vocalCode = 'HE059' - elif vocalCheck == 'SR_W': - vocalCode = 'HE060' - elif vocalCheck == 'GL_W': - vocalCode = 'HE061' - elif vocalCheck == 'HF_A': - vocalCode = 'HE062' - elif vocalCheck == 'UP_W': - vocalCode = 'HE063' - elif vocalCheck == 'SE_W': - vocalCode = 'HE064' - elif vocalCheck == 'SR_A': - vocalCode = 'HE065' - elif vocalCheck == 'GL_A': - vocalCode = 'HE066' - elif vocalCheck == 'MF_Y': - vocalCode = 'HE067' - elif vocalCheck == 'MS_Y': - vocalCode = 'HE068' - elif vocalCheck == 'SC_Y': - vocalCode = 'HE069' - elif vocalCheck == 'UP_Y': - vocalCode = 'HE073' - elif vocalCheck == 'LO_Y': - vocalCode = 'HE074' - elif vocalCheck == 'AF_V': - vocalCode = 'HE075' - elif vocalCheck == 'UP_A': - vocalCode = 'HE076' - elif vocalCheck == 'TAV_W': - vocalCode = 'HE077' - elif vocalCheck == 'TAV_A': - vocalCode = 'HE078' - elif vocalCheck == 'TO_W': - vocalCode = 'HE110' - else: - vocalCode = '' - - #Do some date/time conversions - EndTimeUTCEpoch = x['expireTimeUTC'] - EndTimeUTC = datetime.utcfromtimestamp(EndTimeUTCEpoch).strftime('%Y%m%d%H%M') - #EndTimeUTC = EndTimeUTCString.astimezone(pytz.UTC) - - expireTimeEpoch = x['expireTimeUTC'] - expireTimeUTC = datetime.utcfromtimestamp(expireTimeEpoch).strftime('%Y%m%d%H%M') - - #V3 Alert API doesn't give us issueTime in UTC. So we have to convert ourselves. Ughhh!! - iTLDTS = x['issueTimeLocal'] - iTLDTO = datetime.strptime(iTLDTS, '%Y-%m-%dT%H:%M:%S%z') - issueTimeToUTC = iTLDTO.astimezone(pytz.UTC) - issueTimeUtc = issueTimeToUTC.strftime('%Y%m%d%H%M') - - processTimeEpoch = x['processTimeUTC'] - processTime = datetime.fromtimestamp(processTimeEpoch).strftime('%Y%m%d%H%M%S') - - #What is the action of this alert? - Action = None - if x['messageType'] == 'Update': - Action = 'CON' - elif x['messageType'] == 'New': - Action = 'NEW' + expireTimeEpoch = x['expireTimeUTC'] + expireTimeUTC = datetime.utcfromtimestamp(expireTimeEpoch).strftime('%Y%m%d%H%M') - #Fix description to replace new lines with space and add XML escape Chars. when needed - - description = ' '.join(descriptionRaw.splitlines()) - description = description.replace('&', '&') - description = description.replace('<', '<') - description = description.replace('>', '>') - description = description.replace('-', '') - description = description.replace(':', '') - - #Is this alert urgent? - urgency ='piss' - if vocalCheck == 'TO_W' or vocalCheck == 'SV_W' or vocalCheck == 'FF_W': - urgency = 'BEUrgent' - else: - urgency = 'BERecord' - - alertMsg = 'NOT_USED' + x['productIdentifier'] + 'NOT_USED' + Action + '' + x['officeCode'] + '' + x['phenomena'] + '' + x['significance'] + '' + x['eventTrackingNumber'] + '' + x['eventDescription'] + 'NOT_USED' + EndTimeUTC + '' + str(x['severityCode']) + 'NOT_USED' + expireTimeUTC + '' + location + '' + x['adminDistrictCode'] + 'NOT_USEDNOT_USEDNOT_USED' + x['identifier'] + '' + processTime + '' + issueTimeUtc + '' + x['headlineText'] + '' + vocalCode + 'NOT_USED' + description + 'NOT_USED' + location + '_' + x['phenomena'] + '_' + x['significance'] + '_' + x['eventTrackingNumber'] + '_' + x['officeCode'] + '' + #V3 Alert API doesn't give us issueTime in UTC. So we have to convert ourselves. Ughhh!! + iTLDTS = x['issueTimeLocal'] + iTLDTO = datetime.strptime(iTLDTS, '%Y-%m-%dT%H:%M:%S%z') + issueTimeToUTC = iTLDTO.astimezone(pytz.UTC) + issueTimeUtc = issueTimeToUTC.strftime('%Y%m%d%H%M') - #Append BERecord - with open('./.temp/BERecord.xml', "a") as b: - b.write(alertMsg) - b.close() - - #Add our alert to the manifest so we don't keep sending in the same alert every 60 seconds unless an update is issued. - with open('./.temp/alertmanifest.txt', "a") as c: - c.write('\n' + location + '_' + x['phenomena'] + '_' + x['significance'] + '_' + str(x['processTimeUTC'])) - c.close() - except KeyError: - # For some reason, TWC will return a 200 even though there's no alerts present in the API. - l.error("DO NOT REPORT THE ERROR BELOW") - l.error("Failed to write BERecord - Returned 200 but had no alerts.") - os.remove('./.temp/BERecord.xml') + processTimeEpoch = x['processTimeUTC'] + processTime = datetime.fromtimestamp(processTimeEpoch).strftime('%Y%m%d%H%M%S') + + #What is the action of this alert? + Action = None + if x['messageType'] == 'Update': + Action = 'CON' + elif x['messageType'] == 'New': + Action = 'NEW' + + #Fix description to replace new lines with space and add XML escape Chars. when needed + + description = ' '.join(descriptionRaw.splitlines()) + description = description.replace('&', '&') + description = description.replace('<', '<') + description = description.replace('>', '>') + description = description.replace('-', '') + description = description.replace(':', '') + + #Is this alert urgent? + urgency ='piss' + if vocalCheck == 'TO_W' or vocalCheck == 'SV_W' or vocalCheck == 'FF_W': + urgency = 'BEUrgent' + else: + urgency = 'BERecord' + + alertMsg = 'NOT_USED' + x['productIdentifier'] + 'NOT_USED' + Action + '' + x['officeCode'] + '' + x['phenomena'] + '' + x['significance'] + '' + x['eventTrackingNumber'] + '' + x['eventDescription'] + 'NOT_USED' + EndTimeUTC + '' + str(x['severityCode']) + 'NOT_USED' + expireTimeUTC + '' + location + '' + x['adminDistrictCode'] + 'NOT_USEDNOT_USEDNOT_USED' + x['identifier'] + '' + processTime + '' + issueTimeUtc + '' + x['headlineText'] + '' + vocalCode + 'NOT_USED' + description + 'NOT_USED' + location + '_' + x['phenomena'] + '_' + x['significance'] + '_' + x['eventTrackingNumber'] + '_' + x['officeCode'] + '' + + #Append BERecord + with open('./.temp/BERecord.xml', "a") as b: + b.write(alertMsg) + b.close() + + #Add our alert to the manifest so we don't keep sending in the same alert every 60 seconds unless an update is issued. + with open('./.temp/alertmanifest.txt', "a") as c: + c.write('\n' + location + '_' + x['phenomena'] + '_' + x['significance'] + '_' + str(x['processTimeUTC'])) + c.close() # TODO: This should be converted into a function so it works better with async, that way we're not getting hung up on that time.sleep() call.