Skip to content

Commit a95cf27

Browse files
feat: avwx
Update package.json
1 parent b102ec1 commit a95cf27

File tree

5 files changed

+233
-0
lines changed

5 files changed

+233
-0
lines changed

packages/weather/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,8 @@
3737
"@navigraph/auth": "2.5.1",
3838
"geojson": "^0.5.0",
3939
"metar-taf-parser": "^9.0.1"
40+
},
41+
"devDependencies": {
42+
"@types/geojson": "^7946.0.14"
4043
}
4144
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Logger } from "@navigraph/app"
2+
import { isAxiosError, navigraphRequest } from "@navigraph/auth"
3+
import { FeatureCollection, Geometry } from "geojson"
4+
import { getAvwxApiRoot } from "../../constants"
5+
import { AVWXSource, AVWXSourceProperties } from "../types"
6+
7+
export default async function getAvwxReports<S extends AVWXSource>(sources: S[]) {
8+
const result = await navigraphRequest
9+
.get<FeatureCollection<Geometry, AVWXSourceProperties[S]>>(`${getAvwxApiRoot()}/combined`, {
10+
params: { sources: sources.join(",") },
11+
})
12+
.catch((e: unknown) => Logger.err("Failed to AVWX reports. Reason:", isAxiosError(e) ? e.message : e))
13+
14+
return result?.data || null
15+
}

packages/weather/src/api/types.ts

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from "geojson"
12
import { Forecast as IForecast, IForecastContainer, IMetarDated } from "metar-taf-parser"
23

34
type Coordinates = {
@@ -43,3 +44,214 @@ export type Forecast = IForecast & WxExtensions<"forecast">
4344
export type Taf = Omit<IForecastContainer, "forecast"> & {
4445
forecast: Forecast[]
4546
} & Coordinates
47+
48+
export type Severity = "NONE" | "LGT" | "MOD" | "SVR"
49+
50+
export interface ISIGMETProperties {
51+
source: "ISIGMET"
52+
raw: string
53+
icaoId: string
54+
firId: string
55+
firName: string
56+
seriesId: string
57+
hazard: "TS" | "TSGR" | "TURB" | "LLWS" | "MTW" | "ICING" | "TC" | "SS" | "DS" | "VA" | "RDOACT CLD"
58+
validTimeFrom: string
59+
validTimeTo: string
60+
qualifier: string // TODO: Find more narrow type
61+
geom: string
62+
coords: string
63+
/** Lowest level SIGMET is valid in feet */
64+
base?: number
65+
/** Highest level SIGMET is valid in feet */
66+
top?: number
67+
/** Direction of movement of hazard in degrees */
68+
dir?: string
69+
/** Speed of movement of hazard in knots */
70+
spd?: string
71+
chng?: "NC" | "WKN" | "INTSF"
72+
}
73+
74+
export interface SIGMETProperties {
75+
source: "SIGMET"
76+
raw: string
77+
icaoId: string
78+
airSigmetType: "OUTLOOK" | "SIGMET"
79+
alphaChar: string
80+
hazard: "CONVECTIVE" | "TURB" | "ICING" | "IFR" | "MTN OBSCN" | "ASH"
81+
validTimeFrom: string
82+
validTimeTo: string
83+
severity: Severity
84+
/** Lowest level SIGMET is valid in feet */
85+
altitudeLow1?: number
86+
/** Secondary lowest level SIGMET is valid in feet */
87+
altitudeLow2?: number
88+
/** Highest level SIGMET is valid in feet */
89+
altitudeHi1?: number
90+
/** Secondary highest level SIGMET is valid in feet */
91+
altitudeHi2?: number
92+
}
93+
94+
export interface CWAProperties {
95+
source: "CWA"
96+
raw: string
97+
cwsu: string
98+
name: string
99+
seriesId: string
100+
validTimeFrom: string
101+
validTimeTo: string
102+
hazard: "TS" | "TURB" | "ICE" | "IFR" | "PCPN"
103+
qualifier: string // TODO: Find more narrow type
104+
/** Lowest level the CWA is valid in feet */
105+
base?: number
106+
/** Highest level the CWA is valid in feet */
107+
top?: number
108+
}
109+
110+
export interface AIRMETProperties {
111+
source: "AIRMET"
112+
raw: string
113+
hazard: "TURB" | "ICING" | "IFR" | "MTN OBSCN"
114+
validTimeFrom: string
115+
validTimeTo: string
116+
severity: Severity
117+
icaoId?: string
118+
/** Lowest level SIGMET is valid in feet */
119+
altitudeLow1?: number
120+
/** Secondary lowest level SIGMET is valid in feet */
121+
altitudeLow2?: number
122+
/** Highest level SIGMET is valid in feet */
123+
altitudeHi1?: number
124+
/** Secondary highest level SIGMET is valid in feet */
125+
altitudeHi2?: number
126+
region?: string
127+
reg_name?: string
128+
}
129+
130+
export type GAIRMETProperties = {
131+
source: "GAIRMET"
132+
product: "SIERRA" | "TANGO" | "ZULU"
133+
hazard: "TURB-HI" | "TURB-LO" | "ICE" | "IFR" | "MT_OBSC" | "SFC_WIND" | "LLWS" | "FZLVL"
134+
issueTime: string
135+
validTime: string
136+
forecast: "0" | "3" | "6" | "9" | "12"
137+
/** The reason for the forecast, similar to a raw format */
138+
dueTo?: string
139+
severity?: Severity
140+
/** Lowest level G-AIRMET is valid in 100s feet, or "FZL" if freezing level is defined */
141+
base?: string
142+
/** Highest level G-AIRMET is valid in 100s feet */
143+
top?: string
144+
} & (
145+
| {
146+
hazard: "FZLVL"
147+
/** Level at which G-AIRMET is valid in 100s feet */
148+
level: string
149+
}
150+
| {
151+
base: "FZL"
152+
top: string
153+
/** Lowest freezing level in 100s feet */
154+
fzlbase: string
155+
/** Highest freezing level in 100s feet */
156+
fzltop: string
157+
}
158+
| object
159+
)
160+
161+
export interface AIREPProperties {
162+
source: "AIREP"
163+
raw: string
164+
airepType: string
165+
/** Observed weather: -RA, -SN, TS, etc */
166+
wxString?: string
167+
icaoId: string
168+
/** ISO 8601 formatted date and time when AIREP/PIREP issued */
169+
obsTime: string
170+
/** Aircraft type or flight number */
171+
acType: string
172+
/** Temperature in Celsius */
173+
temp?: string
174+
/** Wind direction in degrees */
175+
wdir?: string
176+
/** Wind speed in knots */
177+
wspd?: string
178+
179+
cloudCvg1?: "CLR" | "SCT" | "BKN" | "OVC"
180+
/** Cloud layer 1 base in 100s feet */
181+
cloudBas1?: string
182+
/** Cloud layer 1 top in 100s feet */
183+
cloudTop1?: string
184+
cloudCvg2?: "CLR" | "SCT" | "BKN" | "OVC"
185+
/** Cloud layer 2 base in 100s feet */
186+
cloudBas2?: string
187+
/** Cloud layer 2 top in 100s feet */
188+
cloudTop2?: string
189+
190+
/** Flight level in 100s of feet */
191+
fltlvl: string
192+
fltlvlType: "GRND" | "DURC" | "DURD" | "CRUISE" | "OTHER" | "UNKN"
193+
194+
tbInt1?: "NEG" | "SMTH-LGT" | "LGT" | "LGT-MOD" | "MOD" | "MOD-SEV" | "SEV" | "SEV-EXTM" | "EXTM"
195+
tbType1?: "CAT" | "CHOP" | "LLWS" | "MWAVE"
196+
tbFreq1?: "ISOL" | "OCNL" | "CONT"
197+
198+
icgInt1?: "NEG" | "NEGclr" | "TRC" | "TRC-LGT" | "LGT" | "LGT-MOD" | "MOD" | "MOD-SEV" | "HVY" | "SEV"
199+
icgType1?: "RIME" | "CLEAR" | "MIXED"
200+
201+
brkAction?: "GOOD" | "GOOD-MED" | "MED" | "MED-POOR" | "POOR" | "NIL"
202+
}
203+
204+
export interface METARProperties {
205+
source: "METAR"
206+
id: string
207+
site: string
208+
prior: number
209+
obsTime: string
210+
raw: string
211+
temp?: number
212+
dewp?: number
213+
wspd?: number
214+
wdir?: number
215+
cover?: string
216+
cldCvg1?: string
217+
visib?: number
218+
fltcat?: "VFR" | "MVFR" | "IFR" | "LIFR"
219+
altim?: number
220+
slp?: number
221+
ceil?: number
222+
cldBas1?: string
223+
wx?: string
224+
wgst?: number
225+
cldCvg2?: string
226+
cldBas2?: string
227+
cldCvg3?: string
228+
cldBas3?: string
229+
cldCvg4?: string
230+
cldBas4?: string
231+
}
232+
233+
type AnyAVWXProperties =
234+
| ISIGMETProperties
235+
| SIGMETProperties
236+
| CWAProperties
237+
| AIRMETProperties
238+
| GAIRMETProperties
239+
| AIREPProperties
240+
| METARProperties
241+
242+
export type AVWXSource = AnyAVWXProperties["source"]
243+
244+
export interface AVWXSourceProperties extends Record<AVWXSource, GeoJsonProperties> {
245+
SIGMET: SIGMETProperties
246+
ISIGMET: ISIGMETProperties
247+
CWA: CWAProperties
248+
AIRMET: AIRMETProperties
249+
GAIRMET: GAIRMETProperties
250+
AIREP: AIREPProperties
251+
METAR: METARProperties
252+
}
253+
254+
export type AVWXFeature<T extends AVWXSource = AVWXSource> = Feature<Geometry, AVWXSourceProperties[T]>
255+
export type SourceFeatureCollection<S extends AVWXSource> = FeatureCollection<Geometry, AVWXSourceProperties[S]>
256+
257+
export const AVWX_SOURCES: AVWXSource[] = ["AIREP", "AIRMET", "CWA", "GAIRMET", "ISIGMET", "METAR", "SIGMET"]

packages/weather/src/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ import { getDefaultAppDomain } from "@navigraph/app"
33
export const getMetarApiRoot = () => `https://wx.api.${getDefaultAppDomain()}/v1/metar`
44
export const getTafApiRoot = () => `https://wx.api.${getDefaultAppDomain()}/v1/taf`
55
export const getRouteApiRoot = () => `https://wx.api.${getDefaultAppDomain()}/v1/route`
6+
export const getAvwxApiRoot = () => `https://wx.api.${getDefaultAppDomain()}/v1/avwx`

packages/weather/src/lib/getWeatherApi.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { getApp, Logger, NotInitializedError, Scope } from "@navigraph/app"
2+
import getAvwxReports from "../api/avwx/getAvwxReports"
23
import getReportsAlongRoute from "../api/getReportsAlongRoute"
34
import getMetarAtAirport from "../api/metar/getMetarAtAirport"
45
import getMetarsAroundPoint from "../api/metar/getMetarsAroundPoint"
@@ -27,5 +28,6 @@ export const getWeatherApi = () => {
2728
getTafsAtAirport,
2829
getTafsAroundPoint,
2930
getReportsAlongRoute,
31+
getAvwxReports,
3032
}
3133
}

0 commit comments

Comments
 (0)