From b6d2330ad559c05edb8a1449e3ba80374929bc2c Mon Sep 17 00:00:00 2001 From: akrherz Date: Wed, 22 Jan 2025 15:07:52 -0600 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20Aviation=20AFD,=20Recent=20ME?= =?UTF-8?q?TARS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://mesonet.agron.iastate.edu/sites/taf.php?station=DSM&network=IA_ASOS --- htdocs/sites/taf.js | 29 +++++++++++++++++++++++++++++ htdocs/sites/taf.php | 33 +++++++++++++++++---------------- pylib/iemweb/afos/retrieve.py | 30 +++++++++++++++++++++++++++--- 3 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 htdocs/sites/taf.js diff --git a/htdocs/sites/taf.js b/htdocs/sites/taf.js new file mode 100644 index 0000000000..526ae03bf3 --- /dev/null +++ b/htdocs/sites/taf.js @@ -0,0 +1,29 @@ +$(document).ready(() =>{ + const rawtext = $("#rawtext"); + const station3 = rawtext.data("station3"); + $.ajax({ + url: `/cgi-bin/afos/retrieve.py?pil=TAF${station3}&fmt=html`, + success: (data) => { + rawtext.html(data); + } + }); + + const afd = $("#afd"); + const wfo = afd.data("wfo"); + $.ajax({ + url: `/cgi-bin/afos/retrieve.py?pil=AFD${wfo}&fmt=html&aviation_afd=1`, + success: (data) => { + afd.html(data); + } + }); + + const metars = $("#metars"); + const station4 = metars.data("station4"); + $.ajax({ + url: `/cgi-bin/request/asos.py?station=${station4}&hours=4&nometa=1&data=metar&report_type=3,4`, + success: (data) => { + metars.html(`
${data}
`); + } + }); + +}); \ No newline at end of file diff --git a/htdocs/sites/taf.php b/htdocs/sites/taf.php index abf9f45b91..039aad8d38 100644 --- a/htdocs/sites/taf.php +++ b/htdocs/sites/taf.php @@ -13,39 +13,40 @@ $station3 = substr($station4, 1, 3); $t = new MyView(); +$t->refresh = 300; $t->title = "Terminal Aerodome Forecasts"; $t->sites_current = "taf"; $t->jsextra = << -$(document).ready(function(){ - $.ajax({ - url: "/cgi-bin/afos/retrieve.py?pil=TAF{$station3}&fmt=html", - success: function(data){ - $("#rawtext").html(data); - } - }); - -}); - + EOM; -$t->content = <<content = <<Terminal Aerodome Forecasts

The IEM processes the feed of Terminal Aerodome Forecasts from the NWS. This page presents some of the options available for this dataset. A download option exists as well.

-

Raw Text

+

Recent METARs

-
+
-

IEM Visualization

+

Raw TAF Text

+ +
+ +

Current NWS Aviation AFD

+ +
+ + +

IEM TAF Visualization

IEM Autoplot 219 produced this visualization:

-EOF; + +EOM; $t->render('sites.phtml'); diff --git a/pylib/iemweb/afos/retrieve.py b/pylib/iemweb/afos/retrieve.py index 0e219e2025..e2de3b0c25 100644 --- a/pylib/iemweb/afos/retrieve.py +++ b/pylib/iemweb/afos/retrieve.py @@ -13,6 +13,8 @@ Changelog ~~~~~~~~~ +- 2025-01-22: Added `aviation_afd` flag for the specific case of retrieving + the "Aviation" section of an Area Forecast Discussion. - 2025-01-08: Added some caching due to incessant requests for the same data. - 2024-08-25: Add ``order`` parameter to allow for order of the returned products. @@ -58,6 +60,7 @@ """ +import re import zipfile from datetime import datetime, timedelta, timezone from io import BytesIO, StringIO @@ -70,11 +73,20 @@ from sqlalchemy import text WARPIL = "FLS FFS AWW TOR SVR FFW SVS LSR SPS WSW FFA WCN NPW".split() +AVIATION_AFD = re.compile(r"^\.AVIATION[\s\.]", re.IGNORECASE | re.MULTILINE) class MyModel(CGIModel): """See how we are called.""" + aviation_afd: bool = Field( + False, + description=( + "If set to 1, the returned data will be the 'Aviation' section " + "of an Area Forecast Discussion. This requires the PIL to be " + "an AFD product and a limit of 1 set." + ), + ) center: str = Field( "", description=( @@ -324,19 +336,31 @@ def application(environ, start_response): sio.write("
\n")
             else:
                 sio.write("\001\n")
+            payload = row[0]
+            if (
+                len(pils) == 1
+                and pils[0].startswith("AFD")
+                and environ["aviation_afd"]
+            ):
+                # Special case for AFD products, we only want the Aviation
+                # section
+                parts = payload.split("&&")
+                for part in parts:
+                    if AVIATION_AFD.search(part):
+                        payload = part
+                        break
             # Remove control characters from the product as we are including
             # them manually here...
             if fmt == "html":
                 sio.write(
-                    html_escape(row[0])
+                    html_escape(payload)
                     .replace("\003", "")
                     .replace("\001\r\r\n", "")
                     .replace("\r\r\n", "\n")
                 )
             else:
                 sio.write(
-                    (row[0])
-                    .replace("\003", "")
+                    payload.replace("\003", "")
                     .replace("\001\r\r\n", "")
                     .replace("\r\r\n", "\n")
                 )