Merge pull request #6 from Open-Telecom/collectorsToAsync

Convert data collectors to async
This commit is contained in:
April Wormwood 2022-11-13 17:19:56 -07:00 committed by GitHub
commit 66a769fe9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 828 additions and 624 deletions

97
RecordTasks.py Normal file
View File

@ -0,0 +1,97 @@
import asyncio
from recordGenerators import Alerts,CurrentObservations,HourlyForecast,DailyForecast, AirQuality, AirportDelays, AchesAndPains, Breathing, HeatingAndCooling, MosquitoActivity, PollenForecast, TideForecast, WateringNeeds
from radar import TWCRadarCollector
from datetime import datetime
""" This houses the tasks needed to update the data records concurrently
I have no idea if this is a messy way to do things, but it will be worked upon if it is.
"""
async def updateMosaicTask():
mosaicUpdateIntervals = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55]
while True:
# Server takes ~15 - 35 seconds to fully generate a frame, so use 40 seconds to ensure it's fully generated.
if datetime.now().minute in mosaicUpdateIntervals and datetime.now().second == 40:
await TWCRadarCollector.collect("radarmosaic")
await asyncio.sleep(1)
async def updateSatradTask():
satradUpdateIntervals = [0, 10, 20, 30, 40, 50]
while True:
# Server takes ~15 - 35 seconds to fully generate a frame, so use 40 seconds to ensure it's fully generated.
if datetime.now().minute in satradUpdateIntervals and datetime.now().second == 40:
await TWCRadarCollector.collect("satrad")
await asyncio.sleep(1)
async def alertsTask():
while True:
await Alerts.makeRecord()
await asyncio.sleep(60)
async def coTask():
while True:
await CurrentObservations.makeDataFile()
await asyncio.sleep(5 * 60)
# These tasks should be updated every hour
async def hfTask():
while True:
await HourlyForecast.makeDataFile()
await asyncio.sleep(60 * 60)
async def dfTask():
while True:
await DailyForecast.makeDataFile()
await asyncio.sleep(60 * 60)
async def aqTask():
while True:
await AirQuality.writeData()
await asyncio.sleep(60 * 60)
async def aptTask():
while True:
await AirportDelays.writeData()
await asyncio.sleep(60 * 60)
async def apTask():
while True:
await AchesAndPains.makeRecord()
await asyncio.sleep(60 * 60)
async def brTask():
while True:
await Breathing.makeDataFile()
await asyncio.sleep(60 * 60)
async def hcTask():
while True:
await HeatingAndCooling.makeRecord()
await asyncio.sleep(60 * 60)
async def maTask():
while True:
await MosquitoActivity.makeRecord()
await asyncio.sleep(60 * 60)
async def pTask():
while True:
await PollenForecast.makeDataFile()
await asyncio.sleep(60 * 60)
async def tTask():
while True:
await TideForecast.makeRecord()
await asyncio.sleep(60 * 60)
async def wnTask():
while True:
await WateringNeeds.makeRecord()
await asyncio.sleep(60 * 60)

View File

@ -50,9 +50,90 @@ def getTideStations():
def getAirportCodes():
""" Returns all of the airport identifiers present in the MachineProductCfg """
airports = []
airports = [
'ATL',
'LAX',
'ORD',
'DFW',
'JFK',
'DEN',
'SFO',
'CLT',
'LAS',
'PHX',
'IAH',
'MIA',
'SEA',
'EWR',
'MCO',
'MSP',
'DTW',
'BOS',
'PHL',
'LGA',
'FLL',
'BWI',
'IAD',
'MDW',
'SLC',
'DCA',
'HNL',
'SAN',
'TPA',
'PDX',
'STL',
'HOU',
'BNA',
'AUS',
'OAK',
'MSY',
'RDU',
'SJC',
'SNA',
'DAL',
'SMF',
'SAT',
'RSW',
'PIT',
'CLE',
'IND',
'MKE',
'CMH',
'OGG',
'PBI',
'BDL',
'CVG',
'JAX',
'ANC',
'BUF',
'ABQ',
'ONT',
'OMA',
'BUR',
'OKC',
'MEM',
'PVD',
'RIC',
'SDF',
'RNO',
'TUS',
'CHS',
'ORF',
'PWM',
'GRR',
'BHM',
'LIT',
'DSM',
'FAR',
'FSD',
'ICT',
'LBB',
'BIL',
'BOI',
'GEG'
]
for i in data['Config']['ConfigDef']['ConfigItems']['ConfigItem']:
if "Airport" in i['@key'] and i['@value'] != "":
if "Airport" in i['@key'] and i['@value'] != "" and not i['@value'] in airports:
# Split the string up
airports.append(i['@value'].split("_")[2])

136
main.py
View File

@ -1,93 +1,81 @@
import asyncio
import asyncio, aiofiles
from asyncio.log import logger
from asyncore import loop
import logging,coloredlogs
from recordGenerators import Alerts,CurrentObservations,DailyForecast,HourlyForecast,AirportDelays,AirQuality,HeatingAndCooling,PollenForecast,Breathing, AchesAndPains, MosquitoActivity, WateringNeeds, TideForecast
from radar import TWCRadarCollector
import os
from datetime import datetime
import RecordTasks
l = logging.getLogger(__name__)
coloredlogs.install(logger=l)
useRadarServer = True
# Create dirs and files
if not os.path.exists('.temp/'):
os.makedirs('.temp/')
if not os.path.exists('.temp/tiles/'):
os.makedirs('.temp/tiles/')
if not os.path.exists('.temp/tiles/output/'):
os.makedirs('.temp/tiles/output/')
if not os.path.exists('.temp/msgId.txt'):
print("Creating initial msgId file")
with open('.temp/msgId.txt', "w") as f:
f.write("410080515")
"""
CurrentConditions: Every 5 minutes
Daily Forecasts, Hourlies, etc: 60 minutes
Alerts: 5 minutes
"""
l.info("Starting i2RecordCollector")
l.info("Developed by mewtek32, Floppaa, Goldblaze, and needlenose")
async def grabAlertsLoop():
while True:
Alerts.makeRecord()
await asyncio.sleep(60)
async def FiveMinUpdaters():
while True:
CurrentObservations.makeDataFile()
l.debug("Sleeping for 5 minutes...")
await asyncio.sleep(5 * 60)
async def HourUpdaters():
while True:
DailyForecast.makeDataFile()
HourlyForecast.makeDataFile()
AirQuality.writeData()
PollenForecast.makeDataFile()
AirportDelays.writeData()
Breathing.makeDataFile()
HeatingAndCooling.makeRecord()
WateringNeeds.makeRecord()
MosquitoActivity.makeRecord()
AchesAndPains.makeRecord()
TideForecast.makeRecord()
l.debug("Sleeping for an hour...")
await asyncio.sleep(60 * 60)
async def radarCollector():
mosaicUpdateIntervals = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55]
satradUpdateIntervals = [0, 10, 20, 30, 40, 50]
while True:
# Server takes ~15 - 35 seconds on average to fully generate a frame, use 40 seconds
# to make sure the radar frame is fully good to go
if datetime.now().minute in mosaicUpdateIntervals and datetime.now().second == 40:
await TWCRadarCollector.collect("radarmosaic")
if datetime.now().minute in satradUpdateIntervals and datetime.now().second == 45:
await TWCRadarCollector.collect("satrad")
async def createTemp():
""" Used on a first time run, creates necessary files & directories for the message encoder to work properly. """
if not (os.path.exists('./.temp/')):
l.info("Creating necessary directories & files..")
os.mkdir('./.temp')
await asyncio.sleep(1)
# Used for the record generator
os.mkdir('./.temp/tiles/')
os.mkdir('./.temp/tiles/output/')
loop = asyncio.get_event_loop()
alertTask = loop.create_task(grabAlertsLoop())
CCtask = loop.create_task(FiveMinUpdaters())
ForecastsTask = loop.create_task(HourUpdaters())
# Used for radar server downloads
os.mkdir('./.temp/output')
os.mkdir('./.temp/output/radarmosaic')
os.mkdir('./.temp/output/satrad')
if useRadarServer: radarTask = loop.create_task(radarCollector())
# Create msgId file for bit.py
async with aiofiles.open('./.temp/msgId.txt', 'w') as msgId:
await msgId.write('410080515')
await msgId.close()
else:
l.debug(".temp file exists")
return
try:
loop.run_until_complete(alertTask)
loop.run_until_complete(CCtask)
loop.run_until_complete(ForecastsTask)
if useRadarServer: loop.run_until_complete(radarTask)
except asyncio.CancelledError: pass
async def main():
await createTemp()
mosaicTask = asyncio.create_task(RecordTasks.updateMosaicTask())
satradTask = asyncio.create_task(RecordTasks.updateSatradTask())
alertsTask = asyncio.create_task(RecordTasks.alertsTask())
coTask = asyncio.create_task(RecordTasks.coTask())
hfTask = asyncio.create_task(RecordTasks.hfTask())
dfTask = asyncio.create_task(RecordTasks.dfTask())
aqTask = asyncio.create_task(RecordTasks.aqTask())
aptTask = asyncio.create_task(RecordTasks.aptTask())
apTask = asyncio.create_task(RecordTasks.apTask())
brTask = asyncio.create_task(RecordTasks.brTask())
hcTask = asyncio.create_task(RecordTasks.hcTask())
maTask = asyncio.create_task(RecordTasks.maTask())
pTask = asyncio.create_task(RecordTasks.pTask())
tTask = asyncio.create_task(RecordTasks.tTask())
wnTask = asyncio.create_task(RecordTasks.wnTask())
# In theory, these should all run concurrently without problems
await alertsTask
await coTask
await hfTask
await dfTask
await aqTask
await aptTask
await apTask
await brTask
await hcTask
await maTask
await pTask
await tTask
await wnTask
if useRadarServer:
await mosaicTask
await satradTask
if __name__ == "__main__":
asyncio.run(main())

View File

@ -42,4 +42,4 @@ def makeStarBundle(Directory, Type, flag, Version, date, sendAfter):
#Directory which contains Files to be bundled Type Flags Version Date SendImmediately(Does not apply to this script)
makeStarBundle('./.temp/i2State/SD/Managed/Events', 'Managed', 'Domestic_SD_Universe', '637898877227230030', '09/28/2022', 0)
# makeStarBundle('./.temp/i2State/SD/Managed/Events', 'Managed', 'Domestic_SD_Universe', '637898877227230030', '09/28/2022', 0)

View File

@ -55,8 +55,8 @@ def WorldCoordinateToTile(coord: Point) -> Point:
scale = 1 << 6
return Point(
x = math.floor(coord.x * scale / 256),
y = math.floor(coord.y * scale / 256)
x = math.floor(coord.x * scale / 255),
y = math.floor(coord.y * scale / 255)
)
def WorldCoordinateToPixel(coord: Point) -> Point:
@ -68,10 +68,10 @@ def WorldCoordinateToPixel(coord: Point) -> Point:
)
def LatLongProject(lat, long) -> Point:
siny = math.sin(lat * math.pi / 185)
siny = math.sin(lat * math.pi / 180)
siny = min(max(siny, -0.9999), 0.9999)
return Point(
x = 256 * (0.5 + long / 360),
y = 256 * (0.5 - math.log((1 + siny) / (1 - siny)) / (4 * math.pi))
)
)

View File

@ -88,6 +88,7 @@ def getTime(timestamp) -> str:
return str(time)
async def collect(radarType: str):
loop = asyncio.get_running_loop()
ts = await getValidTimestamps(radarType)
frames = await downloadRadarFrames(radarType, ts)

View File

@ -7,6 +7,7 @@ import records.LFRecord as LFR
import gzip
from os import remove
import xml.dom.minidom
import aiohttp, aiofiles, asyncio
l = logging.getLogger(__name__)
coloredlogs.install()
@ -20,46 +21,49 @@ for i in MPC.getPrimaryLocations():
apiKey = "21d8a80b3d6b444998a80b3d6b1449d3"
def getData(coopId, geocode):
async def getData(coopId, geocode):
fetchUrl = f"https://api.weather.com/v2/indices/achePain/daypart/7day?geocode={geocode}&language=en-US&format=xml&apiKey={apiKey}"
data = ""
async with aiohttp.ClientSession() as s:
async with s.get(fetchUrl) as r:
if r.status != 200:
l.error(f"Failed to write AchesAndPains record -- status code {r.status}")
return
data = await r.text()
res = requests.get(fetchUrl)
if res.status_code != 200:
l.error("DO NOT REPORT THE ERROR BELOW")
l.error(f"Failed to write AchesAndPains record -- Status code {res.status_code}")
return
data = res.text
newData = data[63:-26]
i2Doc = f'\n <AchesAndPains id="000000000" locationKey="{coopId}" isWxScan="0">\n {newData}\n <clientKey>{coopId}</clientKey>\n </AchesAndPains>'
f = open('./.temp/AchesAndPains.i2m', 'a')
f.write(i2Doc)
f.close()
async with aiofiles.open('./.temp/AchesAndPains.i2m', 'a') as f:
await f.write(i2Doc)
await f.close()
def makeRecord():
async def makeRecord():
loop = asyncio.get_running_loop()
l.info("Writing AchesAndPains record.")
header = '<Data type="AchesAndPains">'
footer = '</Data>'
with open('./.temp/AchesAndPains.i2m', 'a') as doc:
doc.write(header)
async with aiofiles.open('./.temp/AchesAndPains.i2m', 'a') as doc:
await doc.write(header)
for (x, y) in zip(coopIds, geocodes):
getData(x,y)
await getData(x,y)
with open('./.temp/AchesAndPains.i2m', 'a') as end:
end.write(footer)
async with aiofiles.open('./.temp/AchesAndPains.i2m', 'a') as end:
await end.write(footer)
dom = xml.dom.minidom.parse('./.temp/AchesAndPains.i2m')
xmlPretty = dom.toprettyxml(indent= " ")
with open('./.temp/AchesAndPains.i2m', 'w') as g:
g.write(xmlPretty[23:])
g.close()
async with aiofiles.open('./.temp/AchesAndPains.i2m', 'w') as g:
await g.write(xmlPretty[23:])
await g.close()
# Compresss i2m to gzip

View File

@ -4,6 +4,7 @@ import os
import shutil
import xml.dom.minidom
import logging,coloredlogs
import aiohttp, aiofiles, asyncio
l = logging.getLogger(__name__)
coloredlogs.install()
@ -27,22 +28,25 @@ for i in MPC.getPrimaryLocations():
apiKey = '21d8a80b3d6b444998a80b3d6b1449d3'
def getData(epaId, zipcode):
async def getData(epaId, zipcode):
url = f"https://api.weather.com/v1/location/{zipcode}:4:US/airquality.xml?language=en-US&apiKey={apiKey}"
data = ""
res = requests.get(url=url)
data = res.text
async with aiohttp.ClientSession() as s:
async with s.get(url) as r:
data = await r.text()
newData = data[57:-11]
# Write to i2doc file
i2Doc = f'<AirQuality id="000000000" locationKey="{epaId}" isWxScan="0">' + '' + newData + f'<clientKey>{epaId}</clientKey></AirQuality>'
f = open("./.temp/AirQuality.i2m", 'a')
f.write(i2Doc)
f.close()
async with aiofiles.open("./.temp/AirQuality.i2m", 'a') as f:
await f.write(i2Doc)
await f.close()
def writeData():
async def writeData():
loop = asyncio.get_running_loop()
useData = False
workingEpaIds = []
@ -62,21 +66,21 @@ def writeData():
header = '<Data type="AirQuality">'
footer = "</Data>"
with open("./.temp/AirQuality.i2m", 'w') as doc:
doc.write(header)
async with aiofiles.open("./.temp/AirQuality.i2m", 'w') as doc:
await doc.write(header)
for (x, y) in zip(workingEpaIds, zipCodes):
getData(x, y)
await getData(x, y)
with open("./.temp/AirQuality.i2m", 'a') as end:
end.write(footer)
async with aiofiles.open("./.temp/AirQuality.i2m", 'a') as end:
await end.write(footer)
dom = xml.dom.minidom.parse("./.temp/AirQuality.i2m")
xmlPretty = dom.toprettyxml(indent = " ")
with open("./.temp/AirQuality.i2m", 'w') as g:
g.write(xmlPretty[23:])
g.close()
async with aiofiles.open("./.temp/AirQuality.i2m", 'w') as g:
await g.write(xmlPretty[23:])
await g.close()
files = []
commands = []

View File

@ -4,6 +4,7 @@ import os
import shutil
import xml.dom.minidom
import logging,coloredlogs
import aiohttp, aiofiles, asyncio
import sys
sys.path.append("./py2lib")
@ -29,56 +30,57 @@ l.debug(airports)
apiKey = '21d8a80b3d6b444998a80b3d6b1449d3'
def getData(airport):
async def getData(airport):
url = f"https://api.weather.com/v1/airportcode/{airport}/airport/delays.xml?language=en-US&apiKey={apiKey}"
data = ""
res = requests.get(url=url)
async with aiohttp.ClientSession() as s:
async with s.get(url) as r:
data = await r.text()
data = res.text
newData = data[48:-11]
newData = data[48:-11].replace('¿', '-')
# Write to i2doc file
i2Doc = f'<AirportDelays id="000000000" locationKey="{airport}" isWxScan="0">' + '' + newData + f'<clientKey>{airport}</clientKey></AirportDelays>'
f = open("./.temp/AirportDelays.i2m", 'a')
f.write(i2Doc)
f.close()
async with aiofiles.open("./.temp/AirportDelays.i2m", 'a') as f:
await f.write(i2Doc)
await f.close()
def writeData():
async def writeData():
loop = asyncio.get_running_loop()
useData = False
airportsWithDelays = []
for x in airports:
# Do a quick check to see if the airport in question has a delay or not
res = requests.get(f"https://api.weather.com/v1/airportcode/{x}/airport/delays.xml?language=en-US&apiKey={apiKey}")
if (res.status_code != 200):
l.debug(f"[AIRPORT DELAYS] No delays for {x} found, skipping..")
else:
airportsWithDelays.append(x)
l.debug(f"[AIRPORT DELAYS] {x} has a delay! Writing a file..")
useData = True
async with aiohttp.ClientSession() as s:
async with s.get(f"https://api.weather.com/v1/airportcode/{x}/airport/delays.xml?language=en-US&apiKey={apiKey}") as r:
if r.status != 200:
l.debug(f"No delay for {x} found, skipping..")
else:
airportsWithDelays.append(x)
useData = True
if (useData):
l.info("Writing an AirportDelays record.")
header = '<Data type="AirportDelays">'
footer = "</Data>"
with open("./.temp/AirportDelays.i2m", 'w') as doc:
doc.write(header)
async with aiofiles.open("./.temp/AirportDelays.i2m", 'w') as doc:
await doc.write(header)
for x in airportsWithDelays:
getData(x)
await getData(x)
with open("./.temp/AirportDelays.i2m", 'a') as end:
end.write(footer)
async with aiofiles.open("./.temp/AirportDelays.i2m", 'a') as end:
await end.write(footer)
dom = xml.dom.minidom.parse("./.temp/AirportDelays.i2m")
prettyXml = dom.toprettyxml(indent=" ")
with open("./.temp/AirportDelays.i2m", 'w') as g:
g.write(prettyXml)
g.close()
async with aiofiles.open("./.temp/AirportDelays.i2m", 'w') as g:
await g.write(prettyXml)
await g.close()
files = []
commands = []

View File

@ -9,6 +9,7 @@ import xml.dom.minidom
import shutil
import gzip
import logging,coloredlogs
import aiohttp, aiofiles, asyncio
import sys
@ -26,321 +27,326 @@ headlineApiKey = '21d8a80b3d6b444998a80b3d6b1449d3'
detailsApiKey = '21d8a80b3d6b444998a80b3d6b1449d3'
k = 0
def getAlerts(location):
async def getAlerts(location):
global k
fetchUrl = 'https://api.weather.com/v3/alerts/headlines?areaId=' + location + ':US&format=json&language=en-US&apiKey=' + headlineApiKey
response = requests.get(fetchUrl)
# response = requests.get(fetchUrl)
theCode = response.status_code
#Our global variables
#Set the actions based on response code
if theCode == 204:
l.info('No alerts for area ' + location + '.\n')
return
elif theCode == 403:
l.critical("Uh oh! Your API key may not be authorized for alerts. Tsk Tsk. Maybe you shouldn't pirate IBM data :)\n")
return
elif theCode == 401:
l.critical("Uh oh! This request requires authentication. Maybe you shouldn't try to access resources for IBM employee's only :)\n")
return
elif theCode == 404:
l.error("Uh oh! The requested resource cannot be found. This means either the URL is wrong or IBM is having technical difficulties :(\n Or.... They deleted the API :O\n")
return
elif theCode == 405:
l.error("Uh oh! Got a 405! This means that somehow.... someway..... this script made an invalid request. So sad..... So terrible..... :(\n")
return
elif theCode == 406:
l.critical("Uh oh! Got a 406! This means that IBM doesn't like us. :(\n")
return
elif theCode == 408:
l.error("Uh oh! We were too slow in providing IBM our alert request. Although I prefer to say we were Slowly Capable! :)\n")
return
elif theCode == 500:
l.error("Uh oh! Seems IBM's on call IT Tech spilled coffee on the server! Looks like no alerts for a while. Please check back later :)\n")
return
elif theCode == 502 or theCode == 503 or theCode == 504:
l.error("Uh oh! This is why you don't have interns messing with the server configuration. Please stand by while IBM's on call IT Tech resolves the issue :)\n")
return
elif theCode == 200:
pass
# theCode = response.status_code
#Alright lets map our headline variables.
l.debug('Found Alert for ' + location + '\n')
dataH = response.json()
alertsRoot = dataH['alerts']
theCode = 0
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'
async with aiohttp.ClientSession() as s:
async with s.get(fetchUrl) as r:
theCode = await r.status
#Set the actions based on response code
if theCode == 204:
l.info('No alerts for area ' + location + '.\n')
return
elif theCode == 403:
l.critical("Uh oh! Your API key may not be authorized for alerts. Tsk Tsk. Maybe you shouldn't pirate IBM data :)\n")
return
elif theCode == 401:
l.critical("Uh oh! This request requires authentication. Maybe you shouldn't try to access resources for IBM employee's only :)\n")
return
elif theCode == 404:
l.error("Uh oh! The requested resource cannot be found. This means either the URL is wrong or IBM is having technical difficulties :(\n Or.... They deleted the API :O\n")
return
elif theCode == 405:
l.error("Uh oh! Got a 405! This means that somehow.... someway..... this script made an invalid request. So sad..... So terrible..... :(\n")
return
elif theCode == 406:
l.critical("Uh oh! Got a 406! This means that IBM doesn't like us. :(\n")
return
elif theCode == 408:
l.error("Uh oh! We were too slow in providing IBM our alert request. Although I prefer to say we were Slowly Capable! :)\n")
return
elif theCode == 500:
l.error("Uh oh! Seems IBM's on call IT Tech spilled coffee on the server! Looks like no alerts for a while. Please check back later :)\n")
return
elif theCode == 502 or theCode == 503 or theCode == 504:
l.error("Uh oh! This is why you don't have interns messing with the server configuration. Please stand by while IBM's on call IT Tech resolves the issue :)\n")
return
elif theCode == 200:
pass
#theIdent = str(Identifier)
try:
thecheck = open('./.temp/alertmanifest.txt', "r")
check = thecheck.read()
# Map headline variables
l.debug('Found Alert for ' + location + '\n')
dataH = await r.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'])
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!
#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:
async with aiofiles.open('./.temp/alertmanifest.txt', 'r' ) as checkFile:
c = await checkFile.read()
if c.find(Identifier) != -1:
l.debug(f"{Identifier} was sent already, skipping..")
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
#Lets Map Our Vocal Codes!
vocalCheck = x['phenomena'] + '_' + x['significance']
vocalCode = None
if vocalCheck == 'HU_W':
vocalCode = '<bVocHdlnCd>HE001</bVocHdlnCd>'
elif vocalCheck == 'TY_W':
vocalCode = '<bVocHdlnCd>HE002</bVocHdlnCd>'
elif vocalCheck == 'HI_W':
vocalCode = '<bVocHdlnCd>HE003</bVocHdlnCd>'
elif vocalCheck == 'TO_A':
vocalCode = '<bVocHdlnCd>HE004</bVocHdlnCd>'
elif vocalCheck == 'SV_A':
vocalCode = '<bVocHdlnCd>HE005</bVocHdlnCd>'
elif vocalCheck == 'HU_A':
vocalCode = '<bVocHdlnCd>HE006</bVocHdlnCd>'
elif vocalCheck == 'TY_A':
vocalCode = '<bVocHdlnCd>HE007</bVocHdlnCd>'
elif vocalCheck == 'TR_W':
vocalCode = '<bVocHdlnCd>HE008</bVocHdlnCd>'
elif vocalCheck == 'TR_A':
vocalCode = '<bVocHdlnCd>HE009</bVocHdlnCd>'
elif vocalCheck == 'TI_W':
vocalCode = '<bVocHdlnCd>HE010</bVocHdlnCd>'
elif vocalCheck == 'HI_A':
vocalCode = '<bVocHdlnCd>HE011</bVocHdlnCd>'
elif vocalCheck == 'TI_A':
vocalCode = '<bVocHdlnCd>HE012</bVocHdlnCd>'
elif vocalCheck == 'BZ_W':
vocalCode = '<bVocHdlnCd>HE013</bVocHdlnCd>'
elif vocalCheck == 'IS_W':
vocalCode = '<bVocHdlnCd>HE014</bVocHdlnCd>'
elif vocalCheck == 'WS_W':
vocalCode = '<bVocHdlnCd>HE015</bVocHdlnCd>'
elif vocalCheck == 'HW_W':
vocalCode = '<bVocHdlnCd>HE016</bVocHdlnCd>'
elif vocalCheck == 'LE_W':
vocalCode = '<bVocHdlnCd>HE017</bVocHdlnCd>'
elif vocalCheck == 'ZR_Y':
vocalCode = '<bVocHdlnCd>HE018</bVocHdlnCd>'
elif vocalCheck == 'CF_W':
vocalCode = '<bVocHdlnCd>HE019</bVocHdlnCd>'
elif vocalCheck == 'LS_W':
vocalCode = '<bVocHdlnCd>HE020</bVocHdlnCd>'
elif vocalCheck == 'WW_Y':
vocalCode = '<bVocHdlnCd>HE021</bVocHdlnCd>'
elif vocalCheck == 'LB_Y':
vocalCode = '<bVocHdlnCd>HE022</bVocHdlnCd>'
elif vocalCheck == 'LE_Y':
vocalCode = '<bVocHdlnCd>HE023</bVocHdlnCd>'
elif vocalCheck == 'BZ_A':
vocalCode = '<bVocHdlnCd>HE024</bVocHdlnCd>'
elif vocalCheck == 'WS_A':
vocalCode = '<bVocHdlnCd>HE025</bVocHdlnCd>'
elif vocalCheck == 'FF_A':
vocalCode = '<bVocHdlnCd>HE026</bVocHdlnCd>'
elif vocalCheck == 'FA_A':
vocalCode = '<bVocHdlnCd>HE027</bVocHdlnCd>'
elif vocalCheck == 'FA_Y':
vocalCode = '<bVocHdlnCd>HE028</bVocHdlnCd>'
elif vocalCheck == 'HW_A':
vocalCode = '<bVocHdlnCd>HE029</bVocHdlnCd>'
elif vocalCheck == 'LE_A':
vocalCode = '<bVocHdlnCd>HE030</bVocHdlnCd>'
elif vocalCheck == 'SU_W':
vocalCode = '<bVocHdlnCd>HE031</bVocHdlnCd>'
elif vocalCheck == 'LS_Y':
vocalCode = '<bVocHdlnCd>HE032</bVocHdlnCd>'
elif vocalCheck == 'CF_A':
vocalCode = '<bVocHdlnCd>HE033</bVocHdlnCd>'
elif vocalCheck == 'ZF_Y':
vocalCode = '<bVocHdlnCd>HE034</bVocHdlnCd>'
elif vocalCheck == 'FG_Y':
vocalCode = '<bVocHdlnCd>HE035</bVocHdlnCd>'
elif vocalCheck == 'SM_Y':
vocalCode = '<bVocHdlnCd>HE036</bVocHdlnCd>'
elif vocalCheck == 'EC_W':
vocalCode = '<bVocHdlnCd>HE037</bVocHdlnCd>'
elif vocalCheck == 'EH_W':
vocalCode = '<bVocHdlnCd>HE038</bVocHdlnCd>'
elif vocalCheck == 'HZ_W':
vocalCode = '<bVocHdlnCd>HE039</bVocHdlnCd>'
elif vocalCheck == 'FZ_W':
vocalCode = '<bVocHdlnCd>HE040</bVocHdlnCd>'
elif vocalCheck == 'HT_Y':
vocalCode = '<bVocHdlnCd>HE041</bVocHdlnCd>'
elif vocalCheck == 'WC_Y':
vocalCode = '<bVocHdlnCd>HE042</bVocHdlnCd>'
elif vocalCheck == 'FR_Y':
vocalCode = '<bVocHdlnCd>HE043</bVocHdlnCd>'
elif vocalCheck == 'EC_A':
vocalCode = '<bVocHdlnCd>HE044</bVocHdlnCd>'
elif vocalCheck == 'EH_A':
vocalCode = '<bVocHdlnCd>HE045</bVocHdlnCd>'
elif vocalCheck == 'HZ_A':
vocalCode = '<bVocHdlnCd>HE046</bVocHdlnCd>'
elif vocalCheck == 'DS_W':
vocalCode = '<bVocHdlnCd>HE047</bVocHdlnCd>'
elif vocalCheck == 'WI_Y':
vocalCode = '<bVocHdlnCd>HE048</bVocHdlnCd>'
elif vocalCheck == 'SU_Y':
vocalCode = '<bVocHdlnCd>HE049</bVocHdlnCd>'
elif vocalCheck == 'AS_Y':
vocalCode = '<bVocHdlnCd>HE050</bVocHdlnCd>'
elif vocalCheck == 'WC_W':
vocalCode = '<bVocHdlnCd>HE051</bVocHdlnCd>'
elif vocalCheck == 'FZ_A':
vocalCode = '<bVocHdlnCd>HE052</bVocHdlnCd>'
elif vocalCheck == 'WC_A':
vocalCode = '<bVocHdlnCd>HE053</bVocHdlnCd>'
elif vocalCheck == 'AF_W':
vocalCode = '<bVocHdlnCd>HE054</bVocHdlnCd>'
elif vocalCheck == 'AF_Y':
vocalCode = '<bVocHdlnCd>HE055</bVocHdlnCd>'
elif vocalCheck == 'DU_Y':
vocalCode = '<bVocHdlnCd>HE056</bVocHdlnCd>'
elif vocalCheck == 'LW_Y':
vocalCode = '<bVocHdlnCd>HE057</bVocHdlnCd>'
elif vocalCheck == 'LS_A':
vocalCode = '<bVocHdlnCd>HE058</bVocHdlnCd>'
elif vocalCheck == 'HF_W':
vocalCode = '<bVocHdlnCd>HE059</bVocHdlnCd>'
elif vocalCheck == 'SR_W':
vocalCode = '<bVocHdlnCd>HE060</bVocHdlnCd>'
elif vocalCheck == 'GL_W':
vocalCode = '<bVocHdlnCd>HE061</bVocHdlnCd>'
elif vocalCheck == 'HF_A':
vocalCode = '<bVocHdlnCd>HE062</bVocHdlnCd>'
elif vocalCheck == 'UP_W':
vocalCode = '<bVocHdlnCd>HE063</bVocHdlnCd>'
elif vocalCheck == 'SE_W':
vocalCode = '<bVocHdlnCd>HE064</bVocHdlnCd>'
elif vocalCheck == 'SR_A':
vocalCode = '<bVocHdlnCd>HE065</bVocHdlnCd>'
elif vocalCheck == 'GL_A':
vocalCode = '<bVocHdlnCd>HE066</bVocHdlnCd>'
elif vocalCheck == 'MF_Y':
vocalCode = '<bVocHdlnCd>HE067</bVocHdlnCd>'
elif vocalCheck == 'MS_Y':
vocalCode = '<bVocHdlnCd>HE068</bVocHdlnCd>'
elif vocalCheck == 'SC_Y':
vocalCode = '<bVocHdlnCd>HE069</bVocHdlnCd>'
elif vocalCheck == 'UP_Y':
vocalCode = '<bVocHdlnCd>HE073</bVocHdlnCd>'
elif vocalCheck == 'LO_Y':
vocalCode = '<bVocHdlnCd>HE074</bVocHdlnCd>'
elif vocalCheck == 'AF_V':
vocalCode = '<bVocHdlnCd>HE075</bVocHdlnCd>'
elif vocalCheck == 'UP_A':
vocalCode = '<bVocHdlnCd>HE076</bVocHdlnCd>'
elif vocalCheck == 'TAV_W':
vocalCode = '<bVocHdlnCd>HE077</bVocHdlnCd>'
elif vocalCheck == 'TAV_A':
vocalCode = '<bVocHdlnCd>HE078</bVocHdlnCd>'
elif vocalCheck == 'TO_W':
vocalCode = '<bVocHdlnCd>HE110</bVocHdlnCd>'
else:
vocalCode = '<bVocHdlnCd />'
if vocalCheck == 'HU_W':
vocalCode = '<bVocHdlnCd>HE001</bVocHdlnCd>'
elif vocalCheck == 'TY_W':
vocalCode = '<bVocHdlnCd>HE002</bVocHdlnCd>'
elif vocalCheck == 'HI_W':
vocalCode = '<bVocHdlnCd>HE003</bVocHdlnCd>'
elif vocalCheck == 'TO_A':
vocalCode = '<bVocHdlnCd>HE004</bVocHdlnCd>'
elif vocalCheck == 'SV_A':
vocalCode = '<bVocHdlnCd>HE005</bVocHdlnCd>'
elif vocalCheck == 'HU_A':
vocalCode = '<bVocHdlnCd>HE006</bVocHdlnCd>'
elif vocalCheck == 'TY_A':
vocalCode = '<bVocHdlnCd>HE007</bVocHdlnCd>'
elif vocalCheck == 'TR_W':
vocalCode = '<bVocHdlnCd>HE008</bVocHdlnCd>'
elif vocalCheck == 'TR_A':
vocalCode = '<bVocHdlnCd>HE009</bVocHdlnCd>'
elif vocalCheck == 'TI_W':
vocalCode = '<bVocHdlnCd>HE010</bVocHdlnCd>'
elif vocalCheck == 'HI_A':
vocalCode = '<bVocHdlnCd>HE011</bVocHdlnCd>'
elif vocalCheck == 'TI_A':
vocalCode = '<bVocHdlnCd>HE012</bVocHdlnCd>'
elif vocalCheck == 'BZ_W':
vocalCode = '<bVocHdlnCd>HE013</bVocHdlnCd>'
elif vocalCheck == 'IS_W':
vocalCode = '<bVocHdlnCd>HE014</bVocHdlnCd>'
elif vocalCheck == 'WS_W':
vocalCode = '<bVocHdlnCd>HE015</bVocHdlnCd>'
elif vocalCheck == 'HW_W':
vocalCode = '<bVocHdlnCd>HE016</bVocHdlnCd>'
elif vocalCheck == 'LE_W':
vocalCode = '<bVocHdlnCd>HE017</bVocHdlnCd>'
elif vocalCheck == 'ZR_Y':
vocalCode = '<bVocHdlnCd>HE018</bVocHdlnCd>'
elif vocalCheck == 'CF_W':
vocalCode = '<bVocHdlnCd>HE019</bVocHdlnCd>'
elif vocalCheck == 'LS_W':
vocalCode = '<bVocHdlnCd>HE020</bVocHdlnCd>'
elif vocalCheck == 'WW_Y':
vocalCode = '<bVocHdlnCd>HE021</bVocHdlnCd>'
elif vocalCheck == 'LB_Y':
vocalCode = '<bVocHdlnCd>HE022</bVocHdlnCd>'
elif vocalCheck == 'LE_Y':
vocalCode = '<bVocHdlnCd>HE023</bVocHdlnCd>'
elif vocalCheck == 'BZ_A':
vocalCode = '<bVocHdlnCd>HE024</bVocHdlnCd>'
elif vocalCheck == 'WS_A':
vocalCode = '<bVocHdlnCd>HE025</bVocHdlnCd>'
elif vocalCheck == 'FF_A':
vocalCode = '<bVocHdlnCd>HE026</bVocHdlnCd>'
elif vocalCheck == 'FA_A':
vocalCode = '<bVocHdlnCd>HE027</bVocHdlnCd>'
elif vocalCheck == 'FA_Y':
vocalCode = '<bVocHdlnCd>HE028</bVocHdlnCd>'
elif vocalCheck == 'HW_A':
vocalCode = '<bVocHdlnCd>HE029</bVocHdlnCd>'
elif vocalCheck == 'LE_A':
vocalCode = '<bVocHdlnCd>HE030</bVocHdlnCd>'
elif vocalCheck == 'SU_W':
vocalCode = '<bVocHdlnCd>HE031</bVocHdlnCd>'
elif vocalCheck == 'LS_Y':
vocalCode = '<bVocHdlnCd>HE032</bVocHdlnCd>'
elif vocalCheck == 'CF_A':
vocalCode = '<bVocHdlnCd>HE033</bVocHdlnCd>'
elif vocalCheck == 'ZF_Y':
vocalCode = '<bVocHdlnCd>HE034</bVocHdlnCd>'
elif vocalCheck == 'FG_Y':
vocalCode = '<bVocHdlnCd>HE035</bVocHdlnCd>'
elif vocalCheck == 'SM_Y':
vocalCode = '<bVocHdlnCd>HE036</bVocHdlnCd>'
elif vocalCheck == 'EC_W':
vocalCode = '<bVocHdlnCd>HE037</bVocHdlnCd>'
elif vocalCheck == 'EH_W':
vocalCode = '<bVocHdlnCd>HE038</bVocHdlnCd>'
elif vocalCheck == 'HZ_W':
vocalCode = '<bVocHdlnCd>HE039</bVocHdlnCd>'
elif vocalCheck == 'FZ_W':
vocalCode = '<bVocHdlnCd>HE040</bVocHdlnCd>'
elif vocalCheck == 'HT_Y':
vocalCode = '<bVocHdlnCd>HE041</bVocHdlnCd>'
elif vocalCheck == 'WC_Y':
vocalCode = '<bVocHdlnCd>HE042</bVocHdlnCd>'
elif vocalCheck == 'FR_Y':
vocalCode = '<bVocHdlnCd>HE043</bVocHdlnCd>'
elif vocalCheck == 'EC_A':
vocalCode = '<bVocHdlnCd>HE044</bVocHdlnCd>'
elif vocalCheck == 'EH_A':
vocalCode = '<bVocHdlnCd>HE045</bVocHdlnCd>'
elif vocalCheck == 'HZ_A':
vocalCode = '<bVocHdlnCd>HE046</bVocHdlnCd>'
elif vocalCheck == 'DS_W':
vocalCode = '<bVocHdlnCd>HE047</bVocHdlnCd>'
elif vocalCheck == 'WI_Y':
vocalCode = '<bVocHdlnCd>HE048</bVocHdlnCd>'
elif vocalCheck == 'SU_Y':
vocalCode = '<bVocHdlnCd>HE049</bVocHdlnCd>'
elif vocalCheck == 'AS_Y':
vocalCode = '<bVocHdlnCd>HE050</bVocHdlnCd>'
elif vocalCheck == 'WC_W':
vocalCode = '<bVocHdlnCd>HE051</bVocHdlnCd>'
elif vocalCheck == 'FZ_A':
vocalCode = '<bVocHdlnCd>HE052</bVocHdlnCd>'
elif vocalCheck == 'WC_A':
vocalCode = '<bVocHdlnCd>HE053</bVocHdlnCd>'
elif vocalCheck == 'AF_W':
vocalCode = '<bVocHdlnCd>HE054</bVocHdlnCd>'
elif vocalCheck == 'AF_Y':
vocalCode = '<bVocHdlnCd>HE055</bVocHdlnCd>'
elif vocalCheck == 'DU_Y':
vocalCode = '<bVocHdlnCd>HE056</bVocHdlnCd>'
elif vocalCheck == 'LW_Y':
vocalCode = '<bVocHdlnCd>HE057</bVocHdlnCd>'
elif vocalCheck == 'LS_A':
vocalCode = '<bVocHdlnCd>HE058</bVocHdlnCd>'
elif vocalCheck == 'HF_W':
vocalCode = '<bVocHdlnCd>HE059</bVocHdlnCd>'
elif vocalCheck == 'SR_W':
vocalCode = '<bVocHdlnCd>HE060</bVocHdlnCd>'
elif vocalCheck == 'GL_W':
vocalCode = '<bVocHdlnCd>HE061</bVocHdlnCd>'
elif vocalCheck == 'HF_A':
vocalCode = '<bVocHdlnCd>HE062</bVocHdlnCd>'
elif vocalCheck == 'UP_W':
vocalCode = '<bVocHdlnCd>HE063</bVocHdlnCd>'
elif vocalCheck == 'SE_W':
vocalCode = '<bVocHdlnCd>HE064</bVocHdlnCd>'
elif vocalCheck == 'SR_A':
vocalCode = '<bVocHdlnCd>HE065</bVocHdlnCd>'
elif vocalCheck == 'GL_A':
vocalCode = '<bVocHdlnCd>HE066</bVocHdlnCd>'
elif vocalCheck == 'MF_Y':
vocalCode = '<bVocHdlnCd>HE067</bVocHdlnCd>'
elif vocalCheck == 'MS_Y':
vocalCode = '<bVocHdlnCd>HE068</bVocHdlnCd>'
elif vocalCheck == 'SC_Y':
vocalCode = '<bVocHdlnCd>HE069</bVocHdlnCd>'
elif vocalCheck == 'UP_Y':
vocalCode = '<bVocHdlnCd>HE073</bVocHdlnCd>'
elif vocalCheck == 'LO_Y':
vocalCode = '<bVocHdlnCd>HE074</bVocHdlnCd>'
elif vocalCheck == 'AF_V':
vocalCode = '<bVocHdlnCd>HE075</bVocHdlnCd>'
elif vocalCheck == 'UP_A':
vocalCode = '<bVocHdlnCd>HE076</bVocHdlnCd>'
elif vocalCheck == 'TAV_W':
vocalCode = '<bVocHdlnCd>HE077</bVocHdlnCd>'
elif vocalCheck == 'TAV_A':
vocalCode = '<bVocHdlnCd>HE078</bVocHdlnCd>'
elif vocalCheck == 'TO_W':
vocalCode = '<bVocHdlnCd>HE110</bVocHdlnCd>'
else:
vocalCode = '<bVocHdlnCd />'
#Do some date/time conversions
EndTimeUTCEpoch = x['expireTimeUTC']
EndTimeUTC = datetime.utcfromtimestamp(EndTimeUTCEpoch).strftime('%Y%m%d%H%M')
#EndTimeUTC = EndTimeUTCString.astimezone(pytz.UTC)
#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('&', '&amp;')
description = description.replace('<', '&lt;')
description = description.replace('>', '&gt;')
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 = '<BERecord id="0000" locationKey="' + location + '_' + x['phenomena'] + '_' + x['significance'] + '_' + x['eventTrackingNumber'] + '_' + x['officeCode'] + '" isWxscan="0"><action>NOT_USED</action><BEHdr><bPIL>' + x['productIdentifier'] + '</bPIL><bWMOHdr>NOT_USED</bWMOHdr><bEvent><eActionCd eActionPriority="' + str(x['messageTypeCode']) + '">' + Action + '</eActionCd><eOfficeId eOfficeNm="' + x['officeName'] + '">' + x['officeCode'] + '</eOfficeId><ePhenom>' + x['phenomena'] + '</ePhenom><eSgnfcnc>' + x['significance'] + '</eSgnfcnc><eETN>' + x['eventTrackingNumber'] + '</eETN><eDesc>' + x['eventDescription'] + '</eDesc><eStTmUTC>NOT_USED</eStTmUTC><eEndTmUTC>' + EndTimeUTC + '</eEndTmUTC><eSvrty>' + str(x['severityCode']) + '</eSvrty><eTWCIId>NOT_USED</eTWCIId><eExpTmUTC>' + expireTimeUTC + '</eExpTmUTC></bEvent><bLocations><bLocCd bLoc="' + x['areaName'] + '" bLocTyp="' + locationType + '">' + location + '</bLocCd><bStCd bSt="' + x['adminDistrict'] + '">' + x['adminDistrictCode'] + '</bStCd><bUTCDiff>NOT_USED</bUTCDiff><bTzAbbrv>NOT_USED</bTzAbbrv><bCntryCd>NOT_USED</bCntryCd></bLocations><bSgmtChksum>' + x['identifier'] + '</bSgmtChksum><procTm>' + processTime + '</procTm></BEHdr><BEData><bIssueTmUTC>' + issueTimeUtc + '</bIssueTmUTC><bHdln><bHdlnTxt>' + x['headlineText'] + '</bHdlnTxt>' + vocalCode + '</bHdln><bParameter>NOT_USED</bParameter><bNarrTxt bNarrTxtLang="en-US"><bLn>' + description + '</bLn></bNarrTxt><bSrchRslt>NOT_USED</bSrchRslt></BEData><clientKey>' + location + '_' + x['phenomena'] + '_' + x['significance'] + '_' + x['eventTrackingNumber'] + '_' + x['officeCode'] + '</clientKey></BERecord>'
#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'
#Fix description to replace new lines with space and add XML escape Chars. when needed
description = ' '.join(descriptionRaw.splitlines())
description = description.replace('&', '&amp;')
description = description.replace('<', '&lt;')
description = description.replace('>', '&gt;')
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 = '<BERecord id="0000" locationKey="' + location + '_' + x['phenomena'] + '_' + x['significance'] + '_' + x['eventTrackingNumber'] + '_' + x['officeCode'] + '" isWxscan="0"><action>NOT_USED</action><BEHdr><bPIL>' + x['productIdentifier'] + '</bPIL><bWMOHdr>NOT_USED</bWMOHdr><bEvent><eActionCd eActionPriority="' + str(x['messageTypeCode']) + '">' + Action + '</eActionCd><eOfficeId eOfficeNm="' + x['officeName'] + '">' + x['officeCode'] + '</eOfficeId><ePhenom>' + x['phenomena'] + '</ePhenom><eSgnfcnc>' + x['significance'] + '</eSgnfcnc><eETN>' + x['eventTrackingNumber'] + '</eETN><eDesc>' + x['eventDescription'] + '</eDesc><eStTmUTC>NOT_USED</eStTmUTC><eEndTmUTC>' + EndTimeUTC + '</eEndTmUTC><eSvrty>' + str(x['severityCode']) + '</eSvrty><eTWCIId>NOT_USED</eTWCIId><eExpTmUTC>' + expireTimeUTC + '</eExpTmUTC></bEvent><bLocations><bLocCd bLoc="' + x['areaName'] + '" bLocTyp="' + locationType + '">' + location + '</bLocCd><bStCd bSt="' + x['adminDistrict'] + '">' + x['adminDistrictCode'] + '</bStCd><bUTCDiff>NOT_USED</bUTCDiff><bTzAbbrv>NOT_USED</bTzAbbrv><bCntryCd>NOT_USED</bCntryCd></bLocations><bSgmtChksum>' + x['identifier'] + '</bSgmtChksum><procTm>' + processTime + '</procTm></BEHdr><BEData><bIssueTmUTC>' + issueTimeUtc + '</bIssueTmUTC><bHdln><bHdlnTxt>' + x['headlineText'] + '</bHdlnTxt>' + vocalCode + '</bHdln><bParameter>NOT_USED</bParameter><bNarrTxt bNarrTxtLang="en-US"><bLn>' + description + '</bLn></bNarrTxt><bSrchRslt>NOT_USED</bSrchRslt></BEData><clientKey>' + location + '_' + x['phenomena'] + '_' + x['significance'] + '_' + x['eventTrackingNumber'] + '_' + x['officeCode'] + '</clientKey></BERecord>'
#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()
#Append BERecord
async with aiofiles.open('./.temp/BERecord.xml', "a") as b:
await b.write(alertMsg)
await 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.
async with aiofiles.open('./.temp/alertmanifest.txt', "a") as c:
await c.write('\n' + location + '_' + x['phenomena'] + '_' + x['significance'] + '_' + str(x['processTimeUTC']))
await 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.
def makeRecord():
async def makeRecord():
loop = asyncio.get_running_loop()
global k
with open("./.temp/BERecord.xml", 'a') as BERecord:
BERecord.write('<Data type="BERecord">')
BERecord.close()
for z in alertLocations:
getAlerts(z)
with open('./.temp/BERecord.xml', 'a') as BERecord:
BERecord.write("</Data>")
BERecord.close()
dom = xml.dom.minidom.parse("./.temp/BERecord.xml")
pretty_xml_as_string = dom.toprettyxml(indent = " ")
with open("./.temp/BERecord.i2m", 'w') as h:
h.write(pretty_xml_as_string[23:])
h.close()
# If we don't need to send the i2 an alert, we don't need to gzip it.
# The BERecord XML doesn't need to be written if there's no alerts.
if k > 0:
async with aiofiles.open("./.temp/BERecord.xml", 'a') as BERecord:
await BERecord.write('<Data type="BERecord">')
await BERecord.close()
for z in alertLocations:
await getAlerts(z)
async with aiofiles.open('./.temp/BERecord.xml', 'a') as BERecord:
await BERecord.write("</Data>")
await BERecord.close()
dom = xml.dom.minidom.parse("./.temp/BERecord.xml")
pretty_xml_as_string = dom.toprettyxml(indent = " ")
async with aiofiles.open("./.temp/BERecord.i2m", 'w') as h:
await h.write(pretty_xml_as_string[23:])
await h.close()
l.info("Sending alert(s) to the IntelliStar 2!")
with open("./.temp/BERecord.i2m", 'rb') as f_in:
with gzip.open("./.temp/BERecord.gz", 'wb') as f_out:
@ -354,7 +360,7 @@ def makeRecord():
bit.sendFile(files, commands, 1, 0)
os.remove(gZipFile)
k = 0
os.remove("./.temp/BERecord.xml")
os.remove("./.temp/BERecord.i2m")
os.remove("./.temp/BERecord.xml")
os.remove("./.temp/BERecord.i2m")

View File

@ -6,6 +6,7 @@ import os
import shutil
import xml.dom.minidom
import logging,coloredlogs
import aiohttp, aiofiles, asyncio
sys.path.append("./py2lib")
sys.path.append("./Util")
@ -30,14 +31,14 @@ l.debug(coopIds, geocodes)
apiKey = '21d8a80b3d6b444998a80b3d6b1449d3'
def getData(coopId, geocode):
async def getData(coopId, geocode):
fetchUrl = f"https://api.weather.com/v2/indices/breathing/daypart/7day?geocode={geocode}&language=en-US&format=xml&apiKey={apiKey}"
data = ""
#Fetch data
response = requests.get(fetchUrl)
data = response.text
async with aiohttp.ClientSession() as s:
async with s.get(fetchUrl) as r:
data = await r.text()
newData = data[63:-26]
@ -45,32 +46,33 @@ def getData(coopId, geocode):
#Write to .i2m file
i2Doc = '<Breathing id="000000000" locationKey="' + str(coopId) + '" isWxscan="0">' + '' + newData + '<clientKey>' + str(coopId) + '</clientKey></Breathing>'
f = open("./.temp/Breathing.i2m", "a")
f.write(i2Doc)
f.close()
async with aiofiles.open("./.temp/Breathing.i2m", "a") as f:
await f.write(i2Doc)
await f.close()
def makeDataFile():
async def makeDataFile():
loop = asyncio.get_running_loop()
l.info("Writing a Breathing forecast record.")
header = '<Data type="Breathing">'
footer = '</Data>'
with open("./.temp/Breathing.i2m", 'w') as doc:
doc.write(header)
async with aiofiles.open("./.temp/Breathing.i2m", 'w') as doc:
await doc.write(header)
for x, y in zip(coopIds, geocodes):
getData(x, y)
await getData(x, y)
with open("./.temp/Breathing.i2m", 'a') as end:
end.write(footer)
async with aiofiles.open("./.temp/Breathing.i2m", 'a') as end:
await end.write(footer)
dom = xml.dom.minidom.parse("./.temp/Breathing.i2m")
pretty_xml_as_string = dom.toprettyxml(indent = " ")
with open("./.temp/Breathing.i2m", "w") as g:
g.write(pretty_xml_as_string[23:])
g.close()
async with aiofiles.open("./.temp/Breathing.i2m", "w") as g:
await g.write(pretty_xml_as_string[23:])
await g.close()
files = []
commands = []

View File

@ -6,6 +6,7 @@ import os
import shutil
import xml.dom.minidom
import logging,coloredlogs
import aiohttp, aiofiles, asyncio
import sys
sys.path.append("./py2lib")
@ -34,50 +35,53 @@ for i in MPC.getMetroCities():
apiKey = '21d8a80b3d6b444998a80b3d6b1449d3'
def getData(tecci, zipCode):
async def getData(tecci, zipCode):
l.debug('Gathering data for location id ' + tecci)
fetchUrl = 'https://api.weather.com/v1/location/' + zipCode + ':4:US/observations/current.xml?language=en-US&units=e&apiKey=' + apiKey
data = ""
#Fetch data
response = requests.get(fetchUrl)
data = response.text
async with aiohttp.ClientSession() as s:
async with s.get(fetchUrl) as r:
data = await r.text()
newData = data[67:-30]
l.debug('Gathering data for location id ' + tecci)
#Write to .i2m file
i2Doc = '<CurrentObservations id="000000000" locationKey="' + str(tecci) + '" isWxscan="0">' + '' + newData + '<clientKey>' + str(tecci) + '</clientKey></CurrentObservations>'
async with aiofiles.open("./.temp/CurrentObservations.i2m", 'a') as f:
await f.write(i2Doc)
await f.close()
f = open("./.temp/CurrentObservations.i2m", "a")
f.write(i2Doc)
f.close()
def makeDataFile():
async def makeDataFile():
loop = asyncio.get_running_loop()
l.info("Writing a CurrentObservations record.")
header = '<Data type="CurrentObservations">'
footer = '</Data>'
with open("./.temp/CurrentObservations.i2m", 'w') as doc:
doc.write(header)
async with aiofiles.open("./.temp/CurrentObservations.i2m", 'w') as doc:
await doc.write(header)
for x, y in zip(tecciId, zipCodes):
getData(x, y)
await getData(x, y)
with open("./.temp/CurrentObservations.i2m", 'a') as end:
end.write(footer)
async with aiofiles.open("./.temp/CurrentObservations.i2m", 'a') as end:
await end.write(footer)
dom = xml.dom.minidom.parse("./.temp/CurrentObservations.i2m")
pretty_xml_as_string = dom.toprettyxml(indent = " ")
with open("./.temp/CurrentObservations.i2m", "w") as g:
g.write(pretty_xml_as_string[23:])
g.close()
async with aiofiles.open("./.temp/CurrentObservations.i2m", "w") as g:
await g.write(pretty_xml_as_string[23:])
await g.close()
files = []
commands = []
"""
TODO: This can be ran in a seperate thread using loop.run_in_executor() according to the python discord.
! This should probably be implemented ASAP.
"""
with open("./.temp/CurrentObservations.i2m", 'rb') as f_in:
with gzip.open("./.temp/CurrentObservations.gz", 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)
@ -88,7 +92,7 @@ def makeDataFile():
command = commands.append('<MSG><Exec workRequest="storeData(File={0},QGROUP=__CurrentObservations__,Feed=CurrentObservations)" /><GzipCompressedMsg fname="CurrentObservations" /></MSG>')
numFiles = len(files)
bit.sendFile(files, commands, numFiles, 0)
await loop.run_in_executor(bit.sendFile(files, commands, numFiles, 0))
os.remove("./.temp/CurrentObservations.i2m")
os.remove("./.temp/CurrentObservations.gz")

View File

@ -6,6 +6,7 @@ import os
import shutil
import xml.dom.minidom
import logging,coloredlogs
import aiohttp, aiofiles, asyncio
sys.path.append("./py2lib")
sys.path.append("./Util")
@ -32,14 +33,13 @@ for i in MPC.getMetroCities():
apiKey = '21d8a80b3d6b444998a80b3d6b1449d3'
def getData(tecci, zipCode):
async def getData(tecci, zipCode):
fetchUrl = 'https://api.weather.com/v1/location/' + zipCode + ':4:US/forecast/daily/7day.xml?language=en-US&units=e&apiKey=' + apiKey
data = ""
#Fetch data
response = requests.get(fetchUrl)
data = response.text
async with aiohttp.ClientSession() as s:
async with s.get(fetchUrl) as r:
data = await r.text()
newData = data[61:-24]
@ -47,32 +47,33 @@ def getData(tecci, zipCode):
#Write to .i2m file
i2Doc = '<DailyForecast id="000000000" locationKey="' + str(tecci) + '" isWxscan="0">' + '' + newData + '<clientKey>' + str(tecci) + '</clientKey></DailyForecast>'
f = open("./.temp/DailyForecast.i2m", "a")
f.write(i2Doc)
f.close()
async with aiofiles.open('./.temp/DailyForecast.i2m', 'a') as f:
await f.write(i2Doc)
await f.close()
def makeDataFile():
async def makeDataFile():
loop = asyncio.get_running_loop()
l.info("Writing a DailyForecast record.")
header = '<Data type="DailyForecast">'
footer = '</Data>'
with open("./.temp/DailyForecast.i2m", 'w') as doc:
doc.write(header)
async with aiofiles.open("./.temp/DailyForecast.i2m", 'w') as doc:
await doc.write(header)
for x, y in zip(tecciId, zipCodes):
getData(x, y)
await getData(x, y)
with open("./.temp/DailyForecast.i2m", 'a') as end:
end.write(footer)
async with aiofiles.open("./.temp/DailyForecast.i2m", 'a') as end:
await end.write(footer)
dom = xml.dom.minidom.parse("./.temp/DailyForecast.i2m")
pretty_xml_as_string = dom.toprettyxml(indent = " ")
with open("./.temp/DailyForecast.i2m", "w") as g:
g.write(pretty_xml_as_string[23:])
g.close()
async with aiofiles.open("./.temp/DailyForecast.i2m", "w") as g:
await g.write(pretty_xml_as_string[23:])
await g.close()
files = []
commands = []

View File

@ -7,6 +7,7 @@ import records.LFRecord as LFR
import gzip
from os import remove
import xml.dom.minidom
import aiohttp, aiofiles, asyncio
l = logging.getLogger(__name__)
coloredlogs.install()
@ -20,46 +21,49 @@ for i in MPC.getPrimaryLocations():
apiKey = "21d8a80b3d6b444998a80b3d6b1449d3"
def getData(coopId, geocode):
async def getData(coopId, geocode):
fetchUrl = f"https://api.weather.com/v2/indices/heatCool/daypart/7day?geocode={geocode}&language=en-US&format=xml&apiKey={apiKey}"
res = requests.get(fetchUrl)
if res.status_code != 200:
l.error("DO NOT REPORT THE ERROR BELOW")
l.error(f"Failed to write HeatingAndCooling record -- Status code {res.status_code}")
return
data = ""
data = res.text
async with aiohttp.ClientSession() as s:
async with s.get(fetchUrl) as r:
if r.status != 200:
l.error(f"Failed to write HeatingAndCooling record -- Status code {r.status}")
return
data = await r.text()
# data = res.text
newData = data[63:-26]
i2Doc = f'\n <HeatingAndCooling id="000000000" locationKey="{coopId}" isWxScan="0">\n {newData}\n <clientKey>{coopId}</clientKey>\n </HeatingAndCooling>'
f = open('./.temp/HeatingAndCooling.i2m', 'a')
f.write(i2Doc)
f.close()
async with aiofiles.open('./.temp/HeatingAndCooling.i2m', 'a') as f:
await f.write(i2Doc)
await f.close()
def makeRecord():
async def makeRecord():
loop = asyncio.get_running_loop()
l.info("Writing HeatingAndCooling record.")
header = '<Data type="HeatingAndCooling">'
footer = '</Data>'
with open('./.temp/HeatingAndCooling.i2m', 'a') as doc:
doc.write(header)
async with aiofiles.open('./.temp/HeatingAndCooling.i2m', 'a') as doc:
await doc.write(header)
for (x, y) in zip(coopIds, geocodes):
getData(x,y)
await getData(x,y)
with open('./.temp/HeatingAndCooling.i2m', 'a') as end:
end.write(footer)
async with aiofiles.open('./.temp/HeatingAndCooling.i2m', 'a') as end:
await end.write(footer)
dom = xml.dom.minidom.parse('./.temp/HeatingAndCooling.i2m')
xmlPretty = dom.toprettyxml(indent= " ")
with open('./.temp/HeatingAndCooling.i2m', 'w') as g:
g.write(xmlPretty[23:])
g.close()
async with aiofiles.open('./.temp/HeatingAndCooling.i2m', 'w') as g:
await g.write(xmlPretty[23:])
await g.close()
# Compresss i2m to gzip

View File

@ -5,6 +5,7 @@ import os
import shutil
import xml.dom.minidom
import logging,coloredlogs
import aiohttp, aiofiles, asyncio, asyncio
import sys
sys.path.append("./py2lib")
@ -32,46 +33,49 @@ for i in MPC.getMetroCities():
apiKey = '21d8a80b3d6b444998a80b3d6b1449d3'
def getData(tecci, zipCode):
async def getData(tecci, zipCode):
l.debug('Gathering data for location id ' + tecci)
fetchUrl = 'https://api.weather.com/v1/location/' + zipCode + ':4:US/forecast/hourly/360hour.xml?language=en-US&units=e&apiKey=' + apiKey
data = ""
#Fetch data
response = requests.get(fetchUrl)
data = response.text
async with aiohttp.ClientSession() as s:
async with s.get(fetchUrl) as r:
data = await r.text()
newData = data[48:-11]
l.debug('Gathering data for location id ' + tecci)
#Write to .i2m file
i2Doc = '<HourlyForecast id="000000000" locationKey="' + str(tecci) + '" isWxscan="0">' + '' + newData + '<clientKey>' + str(tecci) + '</clientKey></HourlyForecast>'
f = open("./.temp/HourlyForecast.i2m", "a")
f.write(i2Doc)
f.close()
async with aiofiles.open('./.temp/HourlyForecast.i2m', 'a') as f:
await f.write(i2Doc)
await f.close()
def makeDataFile():
async def makeDataFile():
loop = asyncio.get_running_loop()
l.info("Writing an HourlyForecast record.")
header = '<Data type="HourlyForecast">'
footer = '</Data>'
with open("./.temp/HourlyForecast.i2m", 'w') as doc:
doc.write(header)
async with aiofiles.open("./.temp/HourlyForecast.i2m", 'w') as doc:
await doc.write(header)
for x, y in zip(tecciId, zipCodes):
getData(x, y)
await getData(x, y)
with open("./.temp/HourlyForecast.i2m", 'a') as end:
end.write(footer)
async with aiofiles.open("./.temp/HourlyForecast.i2m", 'a') as end:
await end.write(footer)
dom = xml.dom.minidom.parse("./.temp/HourlyForecast.i2m")
pretty_xml_as_string = dom.toprettyxml(indent = " ")
with open("./.temp/HourlyForecast.i2m", "w") as g:
g.write(pretty_xml_as_string[23:])
g.close()
async with aiofiles.open("./.temp/HourlyForecast.i2m", "w") as g:
await g.write(pretty_xml_as_string[23:])
await g.close()
files = []
commands = []

View File

@ -7,6 +7,7 @@ import records.LFRecord as LFR
import gzip
from os import remove
import xml.dom.minidom
import aiohttp, aiofiles, asyncio
l = logging.getLogger(__name__)
coloredlogs.install()
@ -20,46 +21,49 @@ for i in MPC.getPrimaryLocations():
apiKey = "21d8a80b3d6b444998a80b3d6b1449d3"
def getData(coopId, geocode):
async def getData(coopId, geocode):
fetchUrl = f"https://api.weather.com/v2/indices/mosquito/daily/7day?geocode={geocode}&language=en-US&format=xml&apiKey={apiKey}"
data = ""
async with aiohttp.ClientSession() as s:
async with s.get(fetchUrl) as r:
if r.status != 200:
l.error(f"Failed to write MosquitoActivity record -- status code {r.status}")
return
data = await r.text()
res = requests.get(fetchUrl)
if res.status_code != 200:
l.error("DO NOT REPORT THE ERROR BELOW")
l.error(f"Failed to write MosquitoActivity record -- Status code {res.status_code}")
return
data = res.text
newData = data[63:-26]
i2Doc = f'\n <MosquitoActivity id="000000000" locationKey="{coopId}" isWxScan="0">\n {newData}\n <clientKey>{coopId}</clientKey>\n </MosquitoActivity>'
f = open('./.temp/MosquitoActivity.i2m', 'a')
f.write(i2Doc)
f.close()
async with aiofiles.open('./.temp/MosquitoActivity.i2m', 'a') as f:
await f.write(i2Doc)
await f.close()
def makeRecord():
async def makeRecord():
loop = asyncio.get_running_loop()
l.info("Writing MosquitoActivity record.")
header = '<Data type="MosquitoActivity">'
footer = '</Data>'
with open('./.temp/MosquitoActivity.i2m', 'a') as doc:
doc.write(header)
async with aiofiles.open('./.temp/MosquitoActivity.i2m', 'a') as doc:
await doc.write(header)
for (x, y) in zip(coopIds, geocodes):
getData(x,y)
await getData(x,y)
with open('./.temp/MosquitoActivity.i2m', 'a') as end:
end.write(footer)
async with aiofiles.open('./.temp/MosquitoActivity.i2m', 'a') as end:
await end.write(footer)
dom = xml.dom.minidom.parse('./.temp/MosquitoActivity.i2m')
xmlPretty = dom.toprettyxml(indent= " ")
with open('./.temp/MosquitoActivity.i2m', 'w') as g:
g.write(xmlPretty[23:])
g.close()
async with aiofiles.open('./.temp/MosquitoActivity.i2m', 'w') as g:
await g.write(xmlPretty[23:])
await g.close()
# Compresss i2m to gzip

View File

@ -6,6 +6,7 @@ import os
import shutil
import xml.dom.minidom
import logging, coloredlogs
import aiohttp, aiofiles, asyncio
sys.path.append("./py2lib")
sys.path.append("./Util")
@ -31,14 +32,13 @@ l.debug(pollenIds, geocodes)
apiKey = '21d8a80b3d6b444998a80b3d6b1449d3'
def getData(pollenId, geocode):
async def getData(pollenId, geocode):
fetchUrl = f"https://api.weather.com/v2/indices/pollen/daypart/7day?geocode={geocode}&language=en-US&format=xml&apiKey={apiKey}"
data = ""
#Fetch data
response = requests.get(fetchUrl)
data = response.text
async with aiohttp.ClientSession() as s:
async with s.get(fetchUrl) as r:
data = await r.text()
newData = data[63:-26]
@ -46,32 +46,33 @@ def getData(pollenId, geocode):
#Write to .i2m file
i2Doc = '<PollenForecast id="000000000" locationKey="' + str(pollenId) + '" isWxscan="0">' + '' + newData + '<clientKey>' + str(pollenId) + '</clientKey></PollenForecast>'
f = open("./.temp/PollenForecast.i2m", "a")
f.write(i2Doc)
f.close()
async with aiofiles.open("./.temp/PollenForecast.i2m", "a") as f:
await f.write(i2Doc)
await f.close()
def makeDataFile():
async def makeDataFile():
loop = asyncio.get_running_loop()
l.info("Writing a PollenForecast record.")
header = '<Data type="PollenForecast">'
footer = '</Data>'
with open("./.temp/PollenForecast.i2m", 'w') as doc:
doc.write(header)
async with aiofiles.open("./.temp/PollenForecast.i2m", 'w') as doc:
await doc.write(header)
for x, y in zip(pollenIds, geocodes):
getData(x, y)
await getData(x, y)
with open("./.temp/PollenForecast.i2m", 'a') as end:
end.write(footer)
async with aiofiles.open("./.temp/PollenForecast.i2m", 'a') as end:
await end.write(footer)
dom = xml.dom.minidom.parse("./.temp/PollenForecast.i2m")
pretty_xml_as_string = dom.toprettyxml(indent = " ")
with open("./.temp/PollenForecast.i2m", "w") as g:
g.write(pretty_xml_as_string[23:])
g.close()
async with aiofiles.open("./.temp/PollenForecast.i2m", "w") as g:
await g.write(pretty_xml_as_string[23:])
await g.close()
files = []
commands = []

View File

@ -1,6 +1,4 @@
import shutil
from xmlrpc.client import DateTime
import requests
import logging,coloredlogs
import datetime
from py2Lib import bit
@ -9,6 +7,7 @@ import records.LFRecord as LFR
import gzip
from os import remove
import xml.dom.minidom
import aiohttp, aiofiles, asyncio
l = logging.getLogger(__name__)
coloredlogs.install()
@ -22,31 +21,34 @@ for i in MPC.getTideStations():
apiKey = "21d8a80b3d6b444998a80b3d6b1449d3"
def getData(tideStation, geocode):
async def getData(tideStation, geocode):
today = datetime.date.today()
startDate = today.strftime('%Y%m%d')
endDate_unformatted = datetime.datetime.strptime(startDate, '%Y%m%d') + datetime.timedelta(days=5)
endDate = endDate_unformatted.strftime('%Y%m%d')
data = ""
fetchUrl = f"https://api.weather.com/v1/geocode/{geocode}/forecast/tides.xml?language=en-US&units=e&startDate={startDate}&endDate={endDate}&apiKey={apiKey}"
res = requests.get(fetchUrl)
async with aiohttp.ClientSession() as s:
async with s.get(fetchUrl) as r:
if r.status != 200:
l.error(f"Failed to write TideForecast -- status code {r.status}")
return
data = await r.text()
if res.status_code != 200:
l.error("DO NOT REPORT THE ERROR BELOW")
l.error(f"Failed to write TidesForecast record -- Status code {res.status_code}")
return
data = res.text
newData = data[53:-16]
i2Doc = f'\n <TidesForecast id="000000000" locationKey="{tideStation}" isWxScan="0">\n {newData}\n <clientKey>{tideStation}</clientKey>\n </TidesForecast>'
f = open('./.temp/TidesForecast.i2m', 'a')
f.write(i2Doc)
f.close()
async with aiofiles.open('./.temp/TidesForecast.i2m', 'a') as f:
await f.write(i2Doc)
await f.close()
def makeRecord():
async def makeRecord():
loop = asyncio.get_running_loop()
if len(tideStations) < 1:
l.debug("Skipping TidesForecast -- No locations.")
return
@ -56,21 +58,21 @@ def makeRecord():
header = '<Data type="TidesForecast">'
footer = '</Data>'
with open('./.temp/TidesForecast.i2m', 'a') as doc:
doc.write(header)
async with aiofiles.open('./.temp/TidesForecast.i2m', 'a') as doc:
await doc.write(header)
for (x, y) in zip(tideStations, geocodes):
getData(x,y)
await getData(x,y)
with open('./.temp/TidesForecast.i2m', 'a') as end:
end.write(footer)
async with aiofiles.open('./.temp/TidesForecast.i2m', 'a') as end:
await end.write(footer)
dom = xml.dom.minidom.parse('./.temp/TidesForecast.i2m')
xmlPretty = dom.toprettyxml(indent= " ")
with open('./.temp/TidesForecast.i2m', 'w') as g:
g.write(xmlPretty[23:])
g.close()
async with aiofiles.open('./.temp/TidesForecast.i2m', 'w') as g:
await g.write(xmlPretty[23:])
await g.close()
# Compresss i2m to gzip

View File

@ -7,6 +7,7 @@ import records.LFRecord as LFR
import gzip
from os import remove
import xml.dom.minidom
import aiohttp, aiofiles, asyncio
l = logging.getLogger(__name__)
coloredlogs.install()
@ -20,46 +21,48 @@ for i in MPC.getPrimaryLocations():
apiKey = "21d8a80b3d6b444998a80b3d6b1449d3"
def getData(coopId, geocode):
async def getData(coopId, geocode):
fetchUrl = f"https://api.weather.com/v2/indices/wateringNeeds/daypart/7day?geocode={geocode}&language=en-US&format=xml&apiKey={apiKey}"
res = requests.get(fetchUrl)
if res.status_code != 200:
l.error("DO NOT REPORT THE ERROR BELOW")
l.error(f"Failed to write WateringNeeds record -- Status code {res.status_code}")
return
data = ""
async with aiohttp.ClientSession() as s:
async with s.get(fetchUrl) as r:
if r.status != 200:
l.error(f"Failed to WateringNeeds -- status code {r.status}")
return
data = await r.text()
data = res.text
newData = data[63:-26]
i2Doc = f'\n <WateringNeeds id="000000000" locationKey="{coopId}" isWxScan="0">\n {newData}\n <clientKey>{coopId}</clientKey>\n </WateringNeeds>'
f = open('./.temp/WateringNeeds.i2m', 'a')
f.write(i2Doc)
f.close()
async with aiofiles.open('./.temp/WateringNeeds.i2m', 'a') as f:
await f.write(i2Doc)
await f.close()
def makeRecord():
async def makeRecord():
loop = asyncio.get_running_loop()
l.info("Writing WateringNeeds record.")
header = '<Data type="WateringNeeds">'
footer = '</Data>'
with open('./.temp/WateringNeeds.i2m', 'a') as doc:
doc.write(header)
async with aiofiles.open('./.temp/WateringNeeds.i2m', 'a') as doc:
await doc.write(header)
for (x, y) in zip(coopIds, geocodes):
getData(x,y)
await getData(x,y)
with open('./.temp/WateringNeeds.i2m', 'a') as end:
end.write(footer)
async with aiofiles.open('./.temp/WateringNeeds.i2m', 'a') as end:
await end.write(footer)
dom = xml.dom.minidom.parse('./.temp/WateringNeeds.i2m')
xmlPretty = dom.toprettyxml(indent= " ")
with open('./.temp/WateringNeeds.i2m', 'w') as g:
g.write(xmlPretty[23:])
g.close()
async with aiofiles.open('./.temp/WateringNeeds.i2m', 'w') as g:
await g.write(xmlPretty[23:])
await g.close()
# Compresss i2m to gzip

View File

View File

@ -37,8 +37,4 @@ def getLatLong(locId: str):
return fetched[0] + "/" + fetched[1]
def getLocationInfo(locId: str):
pass
print(getCoopId('USAZ0278'))
print(getZip('USAZ0278'))
print(getLatLong('USAZ0278'))
pass