From 116c28810ae4130c7f8de16783b51aacbd61f535 Mon Sep 17 00:00:00 2001 From: Mark Bumiller Date: Sun, 21 Dec 2025 19:52:15 -0500 Subject: [PATCH 01/10] Adding Label H1 header 02E20 parser --- lib/MessageDecoder.ts | 1 + lib/plugins/Label_H1_02E20.test.ts | 159 +++++++++++++++++++++++++++++ lib/plugins/Label_H1_02E20.ts | 110 ++++++++++++++++++++ lib/plugins/official.ts | 1 + lib/types/wind.ts | 12 +++ lib/utils/h1_helper.ts | 27 ++--- lib/utils/result_formatter.ts | 20 +++- 7 files changed, 311 insertions(+), 19 deletions(-) create mode 100644 lib/plugins/Label_H1_02E20.test.ts create mode 100644 lib/plugins/Label_H1_02E20.ts create mode 100644 lib/types/wind.ts diff --git a/lib/MessageDecoder.ts b/lib/MessageDecoder.ts index 884f9be..d13e544 100644 --- a/lib/MessageDecoder.ts +++ b/lib/MessageDecoder.ts @@ -56,6 +56,7 @@ export class MessageDecoder { this.registerPlugin(new Plugins.Label_4T_AGFSR(this)); this.registerPlugin(new Plugins.Label_4T_ETA(this)); this.registerPlugin(new Plugins.Label_B6_Forwardslash(this)); + this.registerPlugin(new Plugins.Label_H1_02E20(this)); this.registerPlugin(new Plugins.Label_H1_FLR(this)); this.registerPlugin(new Plugins.Label_H1_OHMA(this)); this.registerPlugin(new Plugins.Label_H1_WRN(this)); diff --git a/lib/plugins/Label_H1_02E20.test.ts b/lib/plugins/Label_H1_02E20.test.ts new file mode 100644 index 0000000..fb446b7 --- /dev/null +++ b/lib/plugins/Label_H1_02E20.test.ts @@ -0,0 +1,159 @@ +import { MessageDecoder } from "../MessageDecoder"; +import { Label_H1_02E20 } from "./Label_H1_02E20"; + +describe("Label_H1 02E20", () => { + let plugin: Label_H1_02E20; + + beforeEach(() => { + const decoder = new MessageDecoder(); + plugin = new Label_H1_02E20(decoder); + }); + test("matches qualifiers", () => { + expect(plugin.decode).toBeDefined(); + expect(plugin.name).toBe("label-h1-02e20"); + expect(plugin.qualifiers).toBeDefined(); + expect(plugin.qualifiers()).toEqual({ + labels: ["H1"], + preambles: ["02E20"], + }); + }); + + test("decodes discord example 1", () => { + const text = + "02E20HEGNLKPRN40359E02208116253601M627259020G QN41179E02134316323599M617247037G QN41591E02100516393603M610266040G QN42393E02026716463602M600276033G QN43197E01954316533598M592299037G QN44023E01929517003596M587313033G Q"; + const decodeResult = plugin.decode({ text: text }); + /* + Route: HEGN-LKPR +1 40°35.9'N, 022°08.1'E 16:25 FL360 36,000 ft -62.7°C 259°/20kts +2 41°17.9'N, 021°34.3'E 16:32 FL359 35,900 ft -61.7°C 247°/37kts +3 41°59.1'N, 021°00.5'E 16:39 FL360 36,000 ft -61.0°C 266°/40kts +4 42°39.3'N, 020°26.7'E 16:46 FL360 36,000 ft -60.0°C 276°/33kts +5 43°19.7'N, 019°54.3'E 16:53 FL359 35,900 ft -59.2°C 299°/37kts +6 44°02.3'N, 019°29.5'E 17:00 FL359 35,900 ft -58.7°C 313°/33kts + */ + expect(decodeResult.decoded).toBe(true); + expect(decodeResult.decoder.decodeLevel).toBe("full"); + expect(decodeResult.formatted.description).toBe("Weather Report"); + expect(decodeResult.message.text).toBe(text); + const weather = decodeResult.raw.wind_data; + expect(weather.length).toBe(6); + expect(decodeResult.formatted.items[0].label).toBe("Origin"); + expect(decodeResult.formatted.items[0].value).toBe("HEGN"); + expect(decodeResult.formatted.items[1].label).toBe("Destination"); + expect(decodeResult.formatted.items[1].value).toBe("LKPR"); + expect(decodeResult.formatted.items[2].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[2].value).toBe( + "N40359E02208(40.598 N, 22.135 E)@16:25:00 at FL360: 259° at 20kt, -62.7°C at FL360" + ); + expect(decodeResult.formatted.items[3].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[3].value).toBe( + "N41179E02134(41.298 N, 21.572 E)@16:32:00 at FL359: 247° at 37kt, -61.7°C at FL359" + ); + expect(decodeResult.formatted.items[4].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[4].value).toBe( + "N41591E02100(41.985 N, 21.008 E)@16:39:00 at FL360: 266° at 40kt, -61°C at FL360" + ); + expect(decodeResult.formatted.items[5].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[5].value).toBe( + "N42393E02026(42.655 N, 20.445 E)@16:46:00 at FL360: 276° at 33kt, -60°C at FL360" + ); + expect(decodeResult.formatted.items[6].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[6].value).toBe( + "N43197E01954(43.328 N, 19.905 E)@16:53:00 at FL359: 299° at 37kt, -59.2°C at FL359" + ); + expect(decodeResult.formatted.items[7].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[7].value).toBe( + "N44023E01929(44.038 N, 19.492 E)@17:00:00 at FL359: 313° at 33kt, -58.7°C at FL359" + ); + }); + + test("decodes discord example 2", () => { + const text = + "02E20EGKKLBSFN45081E01757116493501M577327021G QN44401E01903016563499M575352028G QN44115E02008017033468M550319029G QN43420E02112317103296M525299036G QN43125E02214517172023M277271022G Q"; + const decodeResult = plugin.decode({ text: text }); + + /* + Route: EGKK-LBSF +1 FL350 ~35,000 ft -57.7°C 327°/21kts +2 FL349 ~34,900 ft -57.5°C 352°/28kts +3 FL346 ~34,600 ft -55.0°C 319°/29kts +4 FL329 ~32,900 ft -52.5°C 299°/36kts +5 FL202 ~20,200 ft -27.7°C 271°/22kts +*/ + expect(decodeResult.decoded).toBe(true); + expect(decodeResult.decoder.decodeLevel).toBe("full"); + expect(decodeResult.formatted.description).toBe("Weather Report"); + expect(decodeResult.message.text).toBe(text); + const weather = decodeResult.raw.wind_data; + expect(weather.length).toBe(5); + expect(decodeResult.formatted.items[0].label).toBe("Origin"); + expect(decodeResult.formatted.items[0].value).toBe("EGKK"); + expect(decodeResult.formatted.items[1].label).toBe("Destination"); + expect(decodeResult.formatted.items[1].value).toBe("LBSF"); + expect(decodeResult.formatted.items[2].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[2].value).toBe( + "N45081E01757(45.135 N, 17.952 E)@16:49:00 at FL350: 327° at 21kt, -57.7°C at FL350" + ); + expect(decodeResult.formatted.items[3].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[3].value).toBe( + "N44401E01903(44.668 N, 19.050 E)@16:56:00 at FL349: 352° at 28kt, -57.5°C at FL349" + ); + expect(decodeResult.formatted.items[4].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[4].value).toBe( + "N44115E02008(44.192 N, 20.133 E)@17:03:00 at FL346: 319° at 29kt, -55°C at FL346" + ); + expect(decodeResult.formatted.items[5].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[5].value).toBe( + "N43420E02112(43.700 N, 21.205 E)@17:10:00 at FL329: 299° at 36kt, -52.5°C at FL329" + ); + expect(decodeResult.formatted.items[6].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[6].value).toBe( + "N43125E02214(43.208 N, 22.242 E)@17:17:00 at FL202: 271° at 22kt, -27.7°C at FL202" + ); + }); + + test("decodes website example", () => { + // https://app.airframes.io/messages/6025352132 + const text = + "02E20EIDWKORDN44087W08505523383800M470251091G QN43210W08520623452813M442251113G QN42461W08539523522189M295256121G QN42380W08623723591780M227266100G Q"; + const decodeResult = plugin.decode({ text: text }); + + expect(decodeResult.decoded).toBe(true); + expect(decodeResult.decoder.decodeLevel).toBe("full"); + expect(decodeResult.formatted.description).toBe("Weather Report"); + expect(decodeResult.message.text).toBe(text); + const weather = decodeResult.raw.wind_data; + expect(weather.length).toBe(4); + expect(decodeResult.formatted.items[0].label).toBe("Origin"); + expect(decodeResult.formatted.items[0].value).toBe("EIDW"); + expect(decodeResult.formatted.items[1].label).toBe("Destination"); + expect(decodeResult.formatted.items[1].value).toBe("KORD"); + expect(decodeResult.formatted.items[2].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[2].value).toBe( + "N44087W08505(44.145 N, 85.092 W)@23:38:00 at FL380: 251° at 91kt, -47°C at FL380" + ); + expect(decodeResult.formatted.items[3].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[3].value).toBe( + "N43210W08520(43.350 N, 85.343 W)@23:45:00 at FL281: 251° at 113kt, -44.2°C at FL281" + ); + expect(decodeResult.formatted.items[4].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[4].value).toBe( + "N42461W08539(42.768 N, 85.658 W)@23:52:00 at FL218: 256° at 121kt, -29.5°C at FL218" + ); + expect(decodeResult.formatted.items[5].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[5].value).toBe( + "N42380W08623(42.633 N, 86.395 W)@23:59:00 at FL178: 266° at 100kt, -22.7°C at FL178" + ); + }); + + test("decodes invalid message", () => { + const text = "02E20INVALID MESSAGE TEXT"; + const decodeResult = plugin.decode({ text: text }); + + expect(decodeResult.decoded).toBe(false); + expect(decodeResult.decoder.decodeLevel).toBe("none"); + expect(decodeResult.formatted.description).toBe("Weather Report"); + expect(decodeResult.message.text).toBe(text); + expect(decodeResult.remaining.text).toBe("02E20INVALID MESSAGE TEXT"); + }); +}); diff --git a/lib/plugins/Label_H1_02E20.ts b/lib/plugins/Label_H1_02E20.ts new file mode 100644 index 0000000..2bcedaf --- /dev/null +++ b/lib/plugins/Label_H1_02E20.ts @@ -0,0 +1,110 @@ +import { DateTimeUtils } from '../DateTimeUtils'; +import { DecoderPlugin } from '../DecoderPlugin'; +import { DecodeResult, Message, Options } from '../DecoderPluginInterface'; +import { Wind } from '../types/wind'; +import { CoordinateUtils } from '../utils/coordinate_utils'; +import { ResultFormatter } from '../utils/result_formatter'; + +export class Label_H1_02E20 extends DecoderPlugin { + name = 'label-h1-02e20'; + + qualifiers() { // eslint-disable-line class-methods-use-this + return { + labels: ["H1"], + preambles: ['02E20'], + }; + } + + decode(message: Message, options: Options = {}) : DecodeResult { + let decodeResult = this.defaultResult(); + decodeResult.decoder.name = this.name; + decodeResult.formatted.description = 'Weather Report'; + decodeResult.message = message; + + const parts = message.text.split(' '); + + if(parts[parts.length-1] !== 'Q') { + // not a valid message + decodeResult.remaining.text = message.text; + decodeResult.decoded = false; + decodeResult.decoder.decodeLevel = 'none'; + return decodeResult; + } + + const windData: Wind[] = []; + decodeResult.remaining.text = ''; + + const header = parts[0]; + // header.substring(0,5) is '02E20' + ResultFormatter.departureAirport(decodeResult, header.substring(5,9)); + ResultFormatter.arrivalAirport(decodeResult, header.substring(9,13)); + const firstWind = this.parseWeatherReport(header.substring(13)); + if(firstWind) { + windData.push(firstWind); + } else { + decodeResult.remaining.text += (decodeResult.remaining.text ? ' ' : '') + header.substring(13); + } + + for(let i=1; i { const data = field.split(','); - const waypoint = data[0]; + const waypoint = {name: data[0]}; const windData = data[1]; const windDirection = Number(windData.slice(0, 3)); const windSpeed = Number(windData.slice(3)); @@ -317,7 +317,7 @@ function processWindData(decodeResult: DecodeResult, message: string) { const tempFlightLevel = Number(tempData.slice(0, 3)); const tempString = tempData.slice(3); const tempDegrees = Number(tempString.substring(1)) * (tempString.charAt(0) === 'M' ? -1 : 1); - decodeResult.raw.wind_data.push({ + wind.push({ waypoint: waypoint, flightLevel: flightLevel, windDirection: windDirection, @@ -327,25 +327,16 @@ function processWindData(decodeResult: DecodeResult, message: string) { degreesC: tempDegrees }, }); - decodeResult.formatted.items.push({ - type: 'wind_data', - code: 'WIND', - label: 'Wind Data', - value: `${waypoint} at FL${flightLevel}: ${windDirection}° at ${windSpeed}kt, ${tempDegrees}°C at FL${tempFlightLevel}`, - }); + } else { - decodeResult.raw.wind_data.push({ + wind.push({ waypoint: waypoint, flightLevel: flightLevel, windDirection: windDirection, windSpeed: windSpeed, }); - decodeResult.formatted.items.push({ - type: 'wind_data', - code: 'WIND', - label: 'Wind Data', - value: `${waypoint} at FL${flightLevel}: ${windDirection}° at ${windSpeed}kt`, - }); } }); + + ResultFormatter.wind_data(decodeResult, wind); } diff --git a/lib/utils/result_formatter.ts b/lib/utils/result_formatter.ts index c6bfc2c..8d02591 100644 --- a/lib/utils/result_formatter.ts +++ b/lib/utils/result_formatter.ts @@ -3,8 +3,8 @@ import { DecodeResult } from "../DecoderPluginInterface"; import { CoordinateUtils } from "./coordinate_utils"; import { DateTimeUtils } from "../DateTimeUtils"; import { RouteUtils } from "./route_utils"; -import { Waypoint } from "../types/waypoint"; import { Route } from "../types/route"; +import { Wind } from "../types/wind"; /** * Class to format the results of common fields @@ -393,6 +393,23 @@ export class ResultFormatter { }); } + static windData(decodeResult: DecodeResult, windData: Wind[]) { + decodeResult.raw.wind_data = windData; + for(const wind of windData) { + let text = `${RouteUtils.waypointToString(wind.waypoint)} at FL${wind.flightLevel}: ${wind.windDirection}° at ${wind.windSpeed}kt`; + if (wind.temperature) { + text += `, ${wind.temperature.degreesC}°C at FL${wind.temperature.flightLevel}`; + + } + decodeResult.formatted.items.push({ + type: 'wind_data', + code: 'WIND', + label: 'Wind Data', + value: text, + }); + } + } + static unknown(decodeResult: DecodeResult, value: string, sep: string = ',') { if (!decodeResult.remaining.text) decodeResult.remaining.text = value; @@ -403,4 +420,5 @@ export class ResultFormatter { static unknownArr(decodeResult: DecodeResult, value: string[], sep: string = ',') { this.unknown(decodeResult, value.join(sep), sep); }; + } From 30dc18bfc43f729bd58f110253aabdd83da4e190 Mon Sep 17 00:00:00 2001 From: Mark Bumiller Date: Sun, 21 Dec 2025 19:54:45 -0500 Subject: [PATCH 02/10] Update lib/utils/h1_helper.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- lib/utils/h1_helper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils/h1_helper.ts b/lib/utils/h1_helper.ts index b0feb22..66251b6 100644 --- a/lib/utils/h1_helper.ts +++ b/lib/utils/h1_helper.ts @@ -338,5 +338,5 @@ function processWindData(decodeResult: DecodeResult, message: string) { } }); - ResultFormatter.wind_data(decodeResult, wind); + ResultFormatter.windData(decodeResult, wind); } From 0648bd2cecf33cb7a6bf9f4223109890677a4cf9 Mon Sep 17 00:00:00 2001 From: Mark Bumiller Date: Sun, 21 Dec 2025 19:56:02 -0500 Subject: [PATCH 03/10] PR feedback --- lib/plugins/Label_H1_02E20.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/plugins/Label_H1_02E20.ts b/lib/plugins/Label_H1_02E20.ts index 2bcedaf..baa8015 100644 --- a/lib/plugins/Label_H1_02E20.ts +++ b/lib/plugins/Label_H1_02E20.ts @@ -49,7 +49,7 @@ export class Label_H1_02E20 extends DecoderPlugin { const part = parts[i]; if(part[0] !== 'Q') { decodeResult.remaining.text += (decodeResult.remaining.text ? ' ' : '') + part; - continue + continue; } const wind = this.parseWeatherReport(part.substring(1)); if(wind) { @@ -67,7 +67,7 @@ export class Label_H1_02E20 extends DecoderPlugin { return decodeResult; } - parseWeatherReport(text: string): Wind | null { + private parseWeatherReport(text: string): Wind | null { //N40359E02208116253601M627259020G From b8f2be4ce03478a1d1b69a95428c2c11b8dd6683 Mon Sep 17 00:00:00 2001 From: Mark Bumiller Date: Sun, 21 Dec 2025 20:04:47 -0500 Subject: [PATCH 04/10] fix waypoint name --- lib/plugins/Label_H1_02E20.test.ts | 30 +++++++++++++++--------------- lib/plugins/Label_H1_02E20.ts | 14 +++++--------- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/lib/plugins/Label_H1_02E20.test.ts b/lib/plugins/Label_H1_02E20.test.ts index fb446b7..19bbe0a 100644 --- a/lib/plugins/Label_H1_02E20.test.ts +++ b/lib/plugins/Label_H1_02E20.test.ts @@ -43,27 +43,27 @@ describe("Label_H1 02E20", () => { expect(decodeResult.formatted.items[1].value).toBe("LKPR"); expect(decodeResult.formatted.items[2].label).toBe("Wind Data"); expect(decodeResult.formatted.items[2].value).toBe( - "N40359E02208(40.598 N, 22.135 E)@16:25:00 at FL360: 259° at 20kt, -62.7°C at FL360" + "N40359E022081(40.598 N, 22.135 E)@16:25:00 at FL360: 259° at 20kt, -62.7°C at FL360" ); expect(decodeResult.formatted.items[3].label).toBe("Wind Data"); expect(decodeResult.formatted.items[3].value).toBe( - "N41179E02134(41.298 N, 21.572 E)@16:32:00 at FL359: 247° at 37kt, -61.7°C at FL359" + "N41179E021343(41.298 N, 21.572 E)@16:32:00 at FL359: 247° at 37kt, -61.7°C at FL359" ); expect(decodeResult.formatted.items[4].label).toBe("Wind Data"); expect(decodeResult.formatted.items[4].value).toBe( - "N41591E02100(41.985 N, 21.008 E)@16:39:00 at FL360: 266° at 40kt, -61°C at FL360" + "N41591E021005(41.985 N, 21.008 E)@16:39:00 at FL360: 266° at 40kt, -61°C at FL360" ); expect(decodeResult.formatted.items[5].label).toBe("Wind Data"); expect(decodeResult.formatted.items[5].value).toBe( - "N42393E02026(42.655 N, 20.445 E)@16:46:00 at FL360: 276° at 33kt, -60°C at FL360" + "N42393E020267(42.655 N, 20.445 E)@16:46:00 at FL360: 276° at 33kt, -60°C at FL360" ); expect(decodeResult.formatted.items[6].label).toBe("Wind Data"); expect(decodeResult.formatted.items[6].value).toBe( - "N43197E01954(43.328 N, 19.905 E)@16:53:00 at FL359: 299° at 37kt, -59.2°C at FL359" + "N43197E019543(43.328 N, 19.905 E)@16:53:00 at FL359: 299° at 37kt, -59.2°C at FL359" ); expect(decodeResult.formatted.items[7].label).toBe("Wind Data"); expect(decodeResult.formatted.items[7].value).toBe( - "N44023E01929(44.038 N, 19.492 E)@17:00:00 at FL359: 313° at 33kt, -58.7°C at FL359" + "N44023E019295(44.038 N, 19.492 E)@17:00:00 at FL359: 313° at 33kt, -58.7°C at FL359" ); }); @@ -92,23 +92,23 @@ describe("Label_H1 02E20", () => { expect(decodeResult.formatted.items[1].value).toBe("LBSF"); expect(decodeResult.formatted.items[2].label).toBe("Wind Data"); expect(decodeResult.formatted.items[2].value).toBe( - "N45081E01757(45.135 N, 17.952 E)@16:49:00 at FL350: 327° at 21kt, -57.7°C at FL350" + "N45081E017571(45.135 N, 17.952 E)@16:49:00 at FL350: 327° at 21kt, -57.7°C at FL350" ); expect(decodeResult.formatted.items[3].label).toBe("Wind Data"); expect(decodeResult.formatted.items[3].value).toBe( - "N44401E01903(44.668 N, 19.050 E)@16:56:00 at FL349: 352° at 28kt, -57.5°C at FL349" + "N44401E019030(44.668 N, 19.050 E)@16:56:00 at FL349: 352° at 28kt, -57.5°C at FL349" ); expect(decodeResult.formatted.items[4].label).toBe("Wind Data"); expect(decodeResult.formatted.items[4].value).toBe( - "N44115E02008(44.192 N, 20.133 E)@17:03:00 at FL346: 319° at 29kt, -55°C at FL346" + "N44115E020080(44.192 N, 20.133 E)@17:03:00 at FL346: 319° at 29kt, -55°C at FL346" ); expect(decodeResult.formatted.items[5].label).toBe("Wind Data"); expect(decodeResult.formatted.items[5].value).toBe( - "N43420E02112(43.700 N, 21.205 E)@17:10:00 at FL329: 299° at 36kt, -52.5°C at FL329" + "N43420E021123(43.700 N, 21.205 E)@17:10:00 at FL329: 299° at 36kt, -52.5°C at FL329" ); expect(decodeResult.formatted.items[6].label).toBe("Wind Data"); expect(decodeResult.formatted.items[6].value).toBe( - "N43125E02214(43.208 N, 22.242 E)@17:17:00 at FL202: 271° at 22kt, -27.7°C at FL202" + "N43125E022145(43.208 N, 22.242 E)@17:17:00 at FL202: 271° at 22kt, -27.7°C at FL202" ); }); @@ -130,19 +130,19 @@ describe("Label_H1 02E20", () => { expect(decodeResult.formatted.items[1].value).toBe("KORD"); expect(decodeResult.formatted.items[2].label).toBe("Wind Data"); expect(decodeResult.formatted.items[2].value).toBe( - "N44087W08505(44.145 N, 85.092 W)@23:38:00 at FL380: 251° at 91kt, -47°C at FL380" + "N44087W085055(44.145 N, 85.092 W)@23:38:00 at FL380: 251° at 91kt, -47°C at FL380" ); expect(decodeResult.formatted.items[3].label).toBe("Wind Data"); expect(decodeResult.formatted.items[3].value).toBe( - "N43210W08520(43.350 N, 85.343 W)@23:45:00 at FL281: 251° at 113kt, -44.2°C at FL281" + "N43210W085206(43.350 N, 85.343 W)@23:45:00 at FL281: 251° at 113kt, -44.2°C at FL281" ); expect(decodeResult.formatted.items[4].label).toBe("Wind Data"); expect(decodeResult.formatted.items[4].value).toBe( - "N42461W08539(42.768 N, 85.658 W)@23:52:00 at FL218: 256° at 121kt, -29.5°C at FL218" + "N42461W085395(42.768 N, 85.658 W)@23:52:00 at FL218: 256° at 121kt, -29.5°C at FL218" ); expect(decodeResult.formatted.items[5].label).toBe("Wind Data"); expect(decodeResult.formatted.items[5].value).toBe( - "N42380W08623(42.633 N, 86.395 W)@23:59:00 at FL178: 266° at 100kt, -22.7°C at FL178" + "N42380W086237(42.633 N, 86.395 W)@23:59:00 at FL178: 266° at 100kt, -22.7°C at FL178" ); }); diff --git a/lib/plugins/Label_H1_02E20.ts b/lib/plugins/Label_H1_02E20.ts index baa8015..862ef87 100644 --- a/lib/plugins/Label_H1_02E20.ts +++ b/lib/plugins/Label_H1_02E20.ts @@ -68,16 +68,12 @@ export class Label_H1_02E20 extends DecoderPlugin { } private parseWeatherReport(text: string): Wind | null { - - //N40359E02208116253601M627259020G - - //40°35.9'N, 022°08.1'E 16:25 FL360 36,000 ft -62.7°C 259°/20kts - - const pos = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(0,13)); + const posString = text.substring(0,13); + const pos = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(posString); if (text.length !== 32 || !pos) { return null; } - const hhmm = text.substring(13,17); + const tod = DateTimeUtils.convertHHMMSSToTod(text.substring(13,17)); const flightLevel = parseInt(text.substring(17,20), 10); // const altitude = parseInt(text.substring(17,21), 10) * 10; // use FL instead const tempSign = text[21] === 'M' ? -1 : 1; @@ -91,10 +87,10 @@ export class Label_H1_02E20 extends DecoderPlugin { } return { waypoint: { - name: text.substring(0,12), + name: posString, latitude: pos.latitude, longitude: pos.longitude, - time: DateTimeUtils.convertHHMMSSToTod(hhmm), + time: tod, timeFormat: 'tod', }, flightLevel: flightLevel, From 2cc4fe347a6044f7a2ff9b8f7ce93306daaa5e5c Mon Sep 17 00:00:00 2001 From: Mark Bumiller Date: Tue, 23 Dec 2025 08:35:44 -0500 Subject: [PATCH 05/10] Add Day of Month --- ..._H1_02E20.test.ts => Label_H1_02E.test.ts} | 82 ++++++++++--------- .../{Label_H1_02E20.ts => Label_H1_02E.ts} | 9 +- 2 files changed, 49 insertions(+), 42 deletions(-) rename lib/plugins/{Label_H1_02E20.test.ts => Label_H1_02E.test.ts} (79%) rename lib/plugins/{Label_H1_02E20.ts => Label_H1_02E.ts} (93%) diff --git a/lib/plugins/Label_H1_02E20.test.ts b/lib/plugins/Label_H1_02E.test.ts similarity index 79% rename from lib/plugins/Label_H1_02E20.test.ts rename to lib/plugins/Label_H1_02E.test.ts index 19bbe0a..3072337 100644 --- a/lib/plugins/Label_H1_02E20.test.ts +++ b/lib/plugins/Label_H1_02E.test.ts @@ -1,20 +1,20 @@ import { MessageDecoder } from "../MessageDecoder"; -import { Label_H1_02E20 } from "./Label_H1_02E20"; +import { Label_H1_02E } from "./Label_H1_02E"; describe("Label_H1 02E20", () => { - let plugin: Label_H1_02E20; + let plugin: Label_H1_02E; beforeEach(() => { const decoder = new MessageDecoder(); - plugin = new Label_H1_02E20(decoder); + plugin = new Label_H1_02E(decoder); }); test("matches qualifiers", () => { expect(plugin.decode).toBeDefined(); - expect(plugin.name).toBe("label-h1-02e20"); + expect(plugin.name).toBe("label-h1-02e"); expect(plugin.qualifiers).toBeDefined(); expect(plugin.qualifiers()).toEqual({ labels: ["H1"], - preambles: ["02E20"], + preambles: ["02E"], }); }); @@ -37,32 +37,34 @@ describe("Label_H1 02E20", () => { expect(decodeResult.message.text).toBe(text); const weather = decodeResult.raw.wind_data; expect(weather.length).toBe(6); - expect(decodeResult.formatted.items[0].label).toBe("Origin"); - expect(decodeResult.formatted.items[0].value).toBe("HEGN"); - expect(decodeResult.formatted.items[1].label).toBe("Destination"); - expect(decodeResult.formatted.items[1].value).toBe("LKPR"); - expect(decodeResult.formatted.items[2].label).toBe("Wind Data"); - expect(decodeResult.formatted.items[2].value).toBe( - "N40359E022081(40.598 N, 22.135 E)@16:25:00 at FL360: 259° at 20kt, -62.7°C at FL360" - ); + expect(decodeResult.formatted.items[0].label).toBe("Day of Month"); + expect(typeof decodeResult.formatted.items[0].value).toBe("string"); + expect(decodeResult.formatted.items[1].label).toBe("Origin"); + expect(decodeResult.formatted.items[1].value).toBe("HEGN"); + expect(decodeResult.formatted.items[2].label).toBe("Destination"); + expect(decodeResult.formatted.items[2].value).toBe("LKPR"); expect(decodeResult.formatted.items[3].label).toBe("Wind Data"); expect(decodeResult.formatted.items[3].value).toBe( - "N41179E021343(41.298 N, 21.572 E)@16:32:00 at FL359: 247° at 37kt, -61.7°C at FL359" + "N40359E022081(40.598 N, 22.135 E)@16:25:00 at FL360: 259° at 20kt, -62.7°C at FL360" ); expect(decodeResult.formatted.items[4].label).toBe("Wind Data"); expect(decodeResult.formatted.items[4].value).toBe( - "N41591E021005(41.985 N, 21.008 E)@16:39:00 at FL360: 266° at 40kt, -61°C at FL360" + "N41179E021343(41.298 N, 21.572 E)@16:32:00 at FL359: 247° at 37kt, -61.7°C at FL359" ); expect(decodeResult.formatted.items[5].label).toBe("Wind Data"); expect(decodeResult.formatted.items[5].value).toBe( - "N42393E020267(42.655 N, 20.445 E)@16:46:00 at FL360: 276° at 33kt, -60°C at FL360" + "N41591E021005(41.985 N, 21.008 E)@16:39:00 at FL360: 266° at 40kt, -61°C at FL360" ); expect(decodeResult.formatted.items[6].label).toBe("Wind Data"); expect(decodeResult.formatted.items[6].value).toBe( - "N43197E019543(43.328 N, 19.905 E)@16:53:00 at FL359: 299° at 37kt, -59.2°C at FL359" + "N42393E020267(42.655 N, 20.445 E)@16:46:00 at FL360: 276° at 33kt, -60°C at FL360" ); expect(decodeResult.formatted.items[7].label).toBe("Wind Data"); expect(decodeResult.formatted.items[7].value).toBe( + "N43197E019543(43.328 N, 19.905 E)@16:53:00 at FL359: 299° at 37kt, -59.2°C at FL359" + ); + expect(decodeResult.formatted.items[8].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[8].value).toBe( "N44023E019295(44.038 N, 19.492 E)@17:00:00 at FL359: 313° at 33kt, -58.7°C at FL359" ); }); @@ -86,28 +88,30 @@ describe("Label_H1 02E20", () => { expect(decodeResult.message.text).toBe(text); const weather = decodeResult.raw.wind_data; expect(weather.length).toBe(5); - expect(decodeResult.formatted.items[0].label).toBe("Origin"); - expect(decodeResult.formatted.items[0].value).toBe("EGKK"); - expect(decodeResult.formatted.items[1].label).toBe("Destination"); - expect(decodeResult.formatted.items[1].value).toBe("LBSF"); - expect(decodeResult.formatted.items[2].label).toBe("Wind Data"); - expect(decodeResult.formatted.items[2].value).toBe( - "N45081E017571(45.135 N, 17.952 E)@16:49:00 at FL350: 327° at 21kt, -57.7°C at FL350" - ); + expect(decodeResult.formatted.items[0].label).toBe("Day of Month"); + expect(typeof decodeResult.formatted.items[0].value).toBe("string"); + expect(decodeResult.formatted.items[1].label).toBe("Origin"); + expect(decodeResult.formatted.items[1].value).toBe("EGKK"); + expect(decodeResult.formatted.items[2].label).toBe("Destination"); + expect(decodeResult.formatted.items[2].value).toBe("LBSF"); expect(decodeResult.formatted.items[3].label).toBe("Wind Data"); expect(decodeResult.formatted.items[3].value).toBe( - "N44401E019030(44.668 N, 19.050 E)@16:56:00 at FL349: 352° at 28kt, -57.5°C at FL349" + "N45081E017571(45.135 N, 17.952 E)@16:49:00 at FL350: 327° at 21kt, -57.7°C at FL350" ); expect(decodeResult.formatted.items[4].label).toBe("Wind Data"); expect(decodeResult.formatted.items[4].value).toBe( - "N44115E020080(44.192 N, 20.133 E)@17:03:00 at FL346: 319° at 29kt, -55°C at FL346" + "N44401E019030(44.668 N, 19.050 E)@16:56:00 at FL349: 352° at 28kt, -57.5°C at FL349" ); expect(decodeResult.formatted.items[5].label).toBe("Wind Data"); expect(decodeResult.formatted.items[5].value).toBe( - "N43420E021123(43.700 N, 21.205 E)@17:10:00 at FL329: 299° at 36kt, -52.5°C at FL329" + "N44115E020080(44.192 N, 20.133 E)@17:03:00 at FL346: 319° at 29kt, -55°C at FL346" ); expect(decodeResult.formatted.items[6].label).toBe("Wind Data"); expect(decodeResult.formatted.items[6].value).toBe( + "N43420E021123(43.700 N, 21.205 E)@17:10:00 at FL329: 299° at 36kt, -52.5°C at FL329" + ); + expect(decodeResult.formatted.items[7].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[7].value).toBe( "N43125E022145(43.208 N, 22.242 E)@17:17:00 at FL202: 271° at 22kt, -27.7°C at FL202" ); }); @@ -124,24 +128,26 @@ describe("Label_H1 02E20", () => { expect(decodeResult.message.text).toBe(text); const weather = decodeResult.raw.wind_data; expect(weather.length).toBe(4); - expect(decodeResult.formatted.items[0].label).toBe("Origin"); - expect(decodeResult.formatted.items[0].value).toBe("EIDW"); - expect(decodeResult.formatted.items[1].label).toBe("Destination"); - expect(decodeResult.formatted.items[1].value).toBe("KORD"); - expect(decodeResult.formatted.items[2].label).toBe("Wind Data"); - expect(decodeResult.formatted.items[2].value).toBe( - "N44087W085055(44.145 N, 85.092 W)@23:38:00 at FL380: 251° at 91kt, -47°C at FL380" - ); + expect(decodeResult.formatted.items[0].label).toBe("Day of Month"); + expect(typeof decodeResult.formatted.items[0].value).toBe("string"); + expect(decodeResult.formatted.items[1].label).toBe("Origin"); + expect(decodeResult.formatted.items[1].value).toBe("EIDW"); + expect(decodeResult.formatted.items[2].label).toBe("Destination"); + expect(decodeResult.formatted.items[2].value).toBe("KORD"); expect(decodeResult.formatted.items[3].label).toBe("Wind Data"); expect(decodeResult.formatted.items[3].value).toBe( - "N43210W085206(43.350 N, 85.343 W)@23:45:00 at FL281: 251° at 113kt, -44.2°C at FL281" + "N44087W085055(44.145 N, 85.092 W)@23:38:00 at FL380: 251° at 91kt, -47°C at FL380" ); expect(decodeResult.formatted.items[4].label).toBe("Wind Data"); expect(decodeResult.formatted.items[4].value).toBe( - "N42461W085395(42.768 N, 85.658 W)@23:52:00 at FL218: 256° at 121kt, -29.5°C at FL218" + "N43210W085206(43.350 N, 85.343 W)@23:45:00 at FL281: 251° at 113kt, -44.2°C at FL281" ); expect(decodeResult.formatted.items[5].label).toBe("Wind Data"); expect(decodeResult.formatted.items[5].value).toBe( + "N42461W085395(42.768 N, 85.658 W)@23:52:00 at FL218: 256° at 121kt, -29.5°C at FL218" + ); + expect(decodeResult.formatted.items[6].label).toBe("Wind Data"); + expect(decodeResult.formatted.items[6].value).toBe( "N42380W086237(42.633 N, 86.395 W)@23:59:00 at FL178: 266° at 100kt, -22.7°C at FL178" ); }); diff --git a/lib/plugins/Label_H1_02E20.ts b/lib/plugins/Label_H1_02E.ts similarity index 93% rename from lib/plugins/Label_H1_02E20.ts rename to lib/plugins/Label_H1_02E.ts index 862ef87..d05b154 100644 --- a/lib/plugins/Label_H1_02E20.ts +++ b/lib/plugins/Label_H1_02E.ts @@ -5,13 +5,13 @@ import { Wind } from '../types/wind'; import { CoordinateUtils } from '../utils/coordinate_utils'; import { ResultFormatter } from '../utils/result_formatter'; -export class Label_H1_02E20 extends DecoderPlugin { - name = 'label-h1-02e20'; +export class Label_H1_02E extends DecoderPlugin { + name = 'label-h1-02e'; qualifiers() { // eslint-disable-line class-methods-use-this return { labels: ["H1"], - preambles: ['02E20'], + preambles: ['02E'], }; } @@ -35,7 +35,8 @@ export class Label_H1_02E20 extends DecoderPlugin { decodeResult.remaining.text = ''; const header = parts[0]; - // header.substring(0,5) is '02E20' + // header.substring(0,3) is '02E' + ResultFormatter.day(decodeResult, parseInt(header.substring(3,5))); ResultFormatter.departureAirport(decodeResult, header.substring(5,9)); ResultFormatter.arrivalAirport(decodeResult, header.substring(9,13)); const firstWind = this.parseWeatherReport(header.substring(13)); From b7b0837443f21b7720a774279f630cc395d1b36e Mon Sep 17 00:00:00 2001 From: Mark Bumiller Date: Tue, 23 Dec 2025 08:36:04 -0500 Subject: [PATCH 06/10] missing files --- lib/MessageDecoder.ts | 2 +- lib/plugins/official.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/MessageDecoder.ts b/lib/MessageDecoder.ts index d13e544..69c32d1 100644 --- a/lib/MessageDecoder.ts +++ b/lib/MessageDecoder.ts @@ -56,7 +56,7 @@ export class MessageDecoder { this.registerPlugin(new Plugins.Label_4T_AGFSR(this)); this.registerPlugin(new Plugins.Label_4T_ETA(this)); this.registerPlugin(new Plugins.Label_B6_Forwardslash(this)); - this.registerPlugin(new Plugins.Label_H1_02E20(this)); + this.registerPlugin(new Plugins.Label_H1_02E(this)); this.registerPlugin(new Plugins.Label_H1_FLR(this)); this.registerPlugin(new Plugins.Label_H1_OHMA(this)); this.registerPlugin(new Plugins.Label_H1_WRN(this)); diff --git a/lib/plugins/official.ts b/lib/plugins/official.ts index 1b4e6b7..622fa64 100644 --- a/lib/plugins/official.ts +++ b/lib/plugins/official.ts @@ -47,7 +47,7 @@ export * from './Label_8E'; export * from './Label_B6'; export * from './Label_ColonComma'; export * from './Label_H1'; -export * from './Label_H1_02E20'; +export * from './Label_H1_02E'; export * from './Label_H1_FLR'; export * from './Label_H1_OHMA'; export * from './Label_H1_Slash'; From c66a6a291560752a9ce03b0b716d203143933037 Mon Sep 17 00:00:00 2001 From: Mark Bumiller Date: Tue, 23 Dec 2025 08:37:10 -0500 Subject: [PATCH 07/10] rename --- lib/plugins/Label_H1_02E.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/Label_H1_02E.test.ts b/lib/plugins/Label_H1_02E.test.ts index 3072337..1a961c7 100644 --- a/lib/plugins/Label_H1_02E.test.ts +++ b/lib/plugins/Label_H1_02E.test.ts @@ -1,7 +1,7 @@ import { MessageDecoder } from "../MessageDecoder"; import { Label_H1_02E } from "./Label_H1_02E"; -describe("Label_H1 02E20", () => { +describe("Label_H1 02E", () => { let plugin: Label_H1_02E; beforeEach(() => { From 735359fd122eab65057521820c37100891292ca4 Mon Sep 17 00:00:00 2001 From: Mark Bumiller Date: Tue, 23 Dec 2025 08:45:06 -0500 Subject: [PATCH 08/10] fix label --- lib/MessageDecoder.ts | 2 +- .../{Label_H1_02E.test.ts => Label_H2_02E.test.ts} | 12 ++++++------ lib/plugins/{Label_H1_02E.ts => Label_H2_02E.ts} | 6 +++--- lib/plugins/official.ts | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) rename lib/plugins/{Label_H1_02E.test.ts => Label_H2_02E.test.ts} (97%) rename lib/plugins/{Label_H1_02E.ts => Label_H2_02E.ts} (97%) diff --git a/lib/MessageDecoder.ts b/lib/MessageDecoder.ts index 69c32d1..8ff6dbb 100644 --- a/lib/MessageDecoder.ts +++ b/lib/MessageDecoder.ts @@ -56,7 +56,7 @@ export class MessageDecoder { this.registerPlugin(new Plugins.Label_4T_AGFSR(this)); this.registerPlugin(new Plugins.Label_4T_ETA(this)); this.registerPlugin(new Plugins.Label_B6_Forwardslash(this)); - this.registerPlugin(new Plugins.Label_H1_02E(this)); + this.registerPlugin(new Plugins.Label_H2_02E(this)); this.registerPlugin(new Plugins.Label_H1_FLR(this)); this.registerPlugin(new Plugins.Label_H1_OHMA(this)); this.registerPlugin(new Plugins.Label_H1_WRN(this)); diff --git a/lib/plugins/Label_H1_02E.test.ts b/lib/plugins/Label_H2_02E.test.ts similarity index 97% rename from lib/plugins/Label_H1_02E.test.ts rename to lib/plugins/Label_H2_02E.test.ts index 1a961c7..7ede384 100644 --- a/lib/plugins/Label_H1_02E.test.ts +++ b/lib/plugins/Label_H2_02E.test.ts @@ -1,19 +1,19 @@ import { MessageDecoder } from "../MessageDecoder"; -import { Label_H1_02E } from "./Label_H1_02E"; +import { Label_H2_02E } from "./Label_H2_02E"; -describe("Label_H1 02E", () => { - let plugin: Label_H1_02E; +describe("Label_H2 02E", () => { + let plugin: Label_H2_02E; beforeEach(() => { const decoder = new MessageDecoder(); - plugin = new Label_H1_02E(decoder); + plugin = new Label_H2_02E(decoder); }); test("matches qualifiers", () => { expect(plugin.decode).toBeDefined(); - expect(plugin.name).toBe("label-h1-02e"); + expect(plugin.name).toBe("label-h2-02e"); expect(plugin.qualifiers).toBeDefined(); expect(plugin.qualifiers()).toEqual({ - labels: ["H1"], + labels: ["H2"], preambles: ["02E"], }); }); diff --git a/lib/plugins/Label_H1_02E.ts b/lib/plugins/Label_H2_02E.ts similarity index 97% rename from lib/plugins/Label_H1_02E.ts rename to lib/plugins/Label_H2_02E.ts index d05b154..eabd10f 100644 --- a/lib/plugins/Label_H1_02E.ts +++ b/lib/plugins/Label_H2_02E.ts @@ -5,12 +5,12 @@ import { Wind } from '../types/wind'; import { CoordinateUtils } from '../utils/coordinate_utils'; import { ResultFormatter } from '../utils/result_formatter'; -export class Label_H1_02E extends DecoderPlugin { - name = 'label-h1-02e'; +export class Label_H2_02E extends DecoderPlugin { + name = 'label-h2-02e'; qualifiers() { // eslint-disable-line class-methods-use-this return { - labels: ["H1"], + labels: ["H2"], preambles: ['02E'], }; } diff --git a/lib/plugins/official.ts b/lib/plugins/official.ts index 622fa64..cbd5e7a 100644 --- a/lib/plugins/official.ts +++ b/lib/plugins/official.ts @@ -47,7 +47,7 @@ export * from './Label_8E'; export * from './Label_B6'; export * from './Label_ColonComma'; export * from './Label_H1'; -export * from './Label_H1_02E'; +export * from './Label_H2_02E'; export * from './Label_H1_FLR'; export * from './Label_H1_OHMA'; export * from './Label_H1_Slash'; From 0ad0f48896d93a7d0e8702ad1a1ab8edb58fd07d Mon Sep 17 00:00:00 2001 From: Mark Bumiller Date: Tue, 23 Dec 2025 08:50:39 -0500 Subject: [PATCH 09/10] specify radix --- lib/plugins/Label_H2_02E.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/Label_H2_02E.ts b/lib/plugins/Label_H2_02E.ts index eabd10f..674a172 100644 --- a/lib/plugins/Label_H2_02E.ts +++ b/lib/plugins/Label_H2_02E.ts @@ -36,7 +36,7 @@ export class Label_H2_02E extends DecoderPlugin { const header = parts[0]; // header.substring(0,3) is '02E' - ResultFormatter.day(decodeResult, parseInt(header.substring(3,5))); + ResultFormatter.day(decodeResult, parseInt(header.substring(3,5),10)); ResultFormatter.departureAirport(decodeResult, header.substring(5,9)); ResultFormatter.arrivalAirport(decodeResult, header.substring(9,13)); const firstWind = this.parseWeatherReport(header.substring(13)); From 68250e9ad89f3260ab8568165f3fe642a38a71dd Mon Sep 17 00:00:00 2001 From: Mark Bumiller Date: Tue, 23 Dec 2025 08:53:43 -0500 Subject: [PATCH 10/10] header validation --- lib/plugins/Label_H2_02E.ts | 138 +++++++++++++++++++----------------- 1 file changed, 72 insertions(+), 66 deletions(-) diff --git a/lib/plugins/Label_H2_02E.ts b/lib/plugins/Label_H2_02E.ts index 674a172..dfdee48 100644 --- a/lib/plugins/Label_H2_02E.ts +++ b/lib/plugins/Label_H2_02E.ts @@ -1,107 +1,113 @@ -import { DateTimeUtils } from '../DateTimeUtils'; -import { DecoderPlugin } from '../DecoderPlugin'; -import { DecodeResult, Message, Options } from '../DecoderPluginInterface'; -import { Wind } from '../types/wind'; -import { CoordinateUtils } from '../utils/coordinate_utils'; -import { ResultFormatter } from '../utils/result_formatter'; +import { DateTimeUtils } from "../DateTimeUtils"; +import { DecoderPlugin } from "../DecoderPlugin"; +import { DecodeResult, Message, Options } from "../DecoderPluginInterface"; +import { Wind } from "../types/wind"; +import { CoordinateUtils } from "../utils/coordinate_utils"; +import { ResultFormatter } from "../utils/result_formatter"; export class Label_H2_02E extends DecoderPlugin { - name = 'label-h2-02e'; + name = "label-h2-02e"; - qualifiers() { // eslint-disable-line class-methods-use-this + qualifiers() { + // eslint-disable-line class-methods-use-this return { labels: ["H2"], - preambles: ['02E'], + preambles: ["02E"], }; } - decode(message: Message, options: Options = {}) : DecodeResult { + decode(message: Message, options: Options = {}): DecodeResult { let decodeResult = this.defaultResult(); decodeResult.decoder.name = this.name; - decodeResult.formatted.description = 'Weather Report'; + decodeResult.formatted.description = "Weather Report"; decodeResult.message = message; - const parts = message.text.split(' '); + const parts = message.text.split(" "); - if(parts[parts.length-1] !== 'Q') { + if (parts[parts.length - 1] !== "Q") { // not a valid message decodeResult.remaining.text = message.text; decodeResult.decoded = false; - decodeResult.decoder.decodeLevel = 'none'; + decodeResult.decoder.decodeLevel = "none"; return decodeResult; } const windData: Wind[] = []; - decodeResult.remaining.text = ''; + decodeResult.remaining.text = ""; const header = parts[0]; - // header.substring(0,3) is '02E' - ResultFormatter.day(decodeResult, parseInt(header.substring(3,5),10)); - ResultFormatter.departureAirport(decodeResult, header.substring(5,9)); - ResultFormatter.arrivalAirport(decodeResult, header.substring(9,13)); - const firstWind = this.parseWeatherReport(header.substring(13)); - if(firstWind) { - windData.push(firstWind); - } else { - decodeResult.remaining.text += (decodeResult.remaining.text ? ' ' : '') + header.substring(13); + if (header.length === 45) { + // header.substring(0,3) is '02E' + ResultFormatter.day(decodeResult, parseInt(header.substring(3, 5), 10)); + ResultFormatter.departureAirport(decodeResult, header.substring(5, 9)); + ResultFormatter.arrivalAirport(decodeResult, header.substring(9, 13)); + const firstWind = this.parseWeatherReport(header.substring(13)); + if (firstWind) { + windData.push(firstWind); + } else { + decodeResult.remaining.text += + (decodeResult.remaining.text ? " " : "") + header.substring(13); + } } - for(let i=1; i