atmosx-nwws-parser 1.0.1915 → 1.0.1917
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bootstrap.ts +13 -0
- package/dist/bootstrap.js +13 -0
- package/dist/src/events.js +112 -8
- package/dist/src/helper.js +1 -0
- package/dist/src/stanza.js +8 -5
- package/dist/src/ugc.js +15 -2
- package/package.json +1 -1
- package/src/events.ts +70 -1
- package/src/helper.ts +1 -0
- package/src/stanza.ts +6 -5
- package/src/ugc.ts +18 -4
package/bootstrap.ts
CHANGED
|
@@ -63,12 +63,25 @@ export const definitions = {
|
|
|
63
63
|
events: { "AF": "Ashfall", "AS": "Air Stagnation", "BH": "Beach Hazard", "BW": "Brisk Wind", "BZ": "Blizzard", "CF": "Coastal Flood", "DF": "Debris Flow", "DS": "Dust Storm", "EC": "Extreme Cold", "EH": "Excessive Heat", "XH": "Extreme Heat", "EW": "Extreme Wind", "FA": "Areal Flood", "FF": "Flash Flood", "FG": "Dense Fog", "FL": "Flood", "FR": "Frost", "FW": "Fire Weather", "FZ": "Freeze", "GL": "Gale", "HF": "Hurricane Force Wind", "HT": "Heat", "HU": "Hurricane", "HW": "High Wind", "HY": "Hydrologic", "HZ": "Hard Freeze", "IS": "Ice Storm", "LE": "Lake Effect Snow", "LO": "Low Water", "LS": "Lakeshore Flood", "LW": "Lake Wind", "MA": "Special Marine", "MF": "Dense Fog", "MH": "Ashfall", "MS": "Dense Smoke", "RB": "Small Craft for Rough Bar", "RP": "Rip Current Risk", "SC": "Small Craft", "SE": "Hazardous Seas", "SI": "Small Craft for Winds", "SM": "Dense Smoke", "SQ": "Snow Squall", "SR": "Storm", "SS": "Storm Surge", "SU": "High Surf", "SV": "Severe Thunderstorm", "SW": "Small Craft for Hazardous Seas", "TO": "Tornado", "TR": "Tropical Storm", "TS": "Tsunami", "TY": "Typhoon", "UP": "Heavy Freezing Spray", "WC": "Wind Chill", "WI": "Wind", "WS": "Winter Storm", "WW": "Winter Weather", "ZF": "Freezing Fog", "ZR": "Freezing Rain", "ZY": "Freezing Spray" },
|
|
64
64
|
actions: { "W": "Warning", "F": "Forecast", "A": "Watch", "O": "Outlook", "Y": "Advisory", "N": "Synopsis", "S": "Statement"},
|
|
65
65
|
status: { "NEW": "Issued", "CON": "Updated", "EXT": "Extended", "EXA": "Extended", "EXB": "Extended", "UPG": "Upgraded", "COR": "Correction", "ROU": "Routine", "CAN": "Cancelled", "EXP": "Expired" },
|
|
66
|
+
offshore: {
|
|
67
|
+
"Special Weather Statement": "Special Weather Statement",
|
|
68
|
+
"Hurricane Warning": "Hurricane Warning",
|
|
69
|
+
"Hurricane Force Wind Warning": "Hurricane Force Wind Warning",
|
|
70
|
+
"Hurricane Watch": "Hurricane Watch",
|
|
71
|
+
"Tropical Storm Warning": "Tropical Storm Warning",
|
|
72
|
+
"Tropical Storm Watch": "Tropical Storm Watch",
|
|
73
|
+
"High Wind Warning": "High Wind Warning",
|
|
74
|
+
"Gale Warning": "Gale Warning",
|
|
75
|
+
"Small Craft Advisory": "Small Craft Advisory",
|
|
76
|
+
"Small Craft Warning": "Small Craft Warning",
|
|
77
|
+
},
|
|
66
78
|
awips: { SWOMCD: `mesoscale-discussion`, LSR: `local-storm-report`, SPS: `special-weather-statement`},
|
|
67
79
|
expressions: {
|
|
68
80
|
vtec: `[OTEX].(NEW|CON|EXT|EXA|EXB|UPG|CAN|EXP|COR|ROU).[A-Z]{4}.[A-Z]{2}.[WAYSFON].[0-9]{4}.[0-9]{6}T[0-9]{4}Z-[0-9]{6}T[0-9]{4}Z`,
|
|
69
81
|
wmo: `[A-Z0-9]{6}\\s[A-Z]{4}\\s\\d{6}`,
|
|
70
82
|
ugc1: `(\\w{2}[CZ](\\d{3}((-|>)\\s?(\n\n)?))+)`,
|
|
71
83
|
ugc2: `(\\d{6}(-|>)\\s?(\n\n)?)`,
|
|
84
|
+
ugc3: `(\\d{6})(?=-|$)`,
|
|
72
85
|
dateline: `/\d{3,4}\s*(AM|PM)?\s*[A-Z]{2,4}\s+[A-Z]{3,}\s+[A-Z]{3,}\s+\d{1,2}\s+\d{4}`
|
|
73
86
|
},
|
|
74
87
|
tags: {
|
package/dist/bootstrap.js
CHANGED
|
@@ -94,12 +94,25 @@ exports.definitions = {
|
|
|
94
94
|
events: { "AF": "Ashfall", "AS": "Air Stagnation", "BH": "Beach Hazard", "BW": "Brisk Wind", "BZ": "Blizzard", "CF": "Coastal Flood", "DF": "Debris Flow", "DS": "Dust Storm", "EC": "Extreme Cold", "EH": "Excessive Heat", "XH": "Extreme Heat", "EW": "Extreme Wind", "FA": "Areal Flood", "FF": "Flash Flood", "FG": "Dense Fog", "FL": "Flood", "FR": "Frost", "FW": "Fire Weather", "FZ": "Freeze", "GL": "Gale", "HF": "Hurricane Force Wind", "HT": "Heat", "HU": "Hurricane", "HW": "High Wind", "HY": "Hydrologic", "HZ": "Hard Freeze", "IS": "Ice Storm", "LE": "Lake Effect Snow", "LO": "Low Water", "LS": "Lakeshore Flood", "LW": "Lake Wind", "MA": "Special Marine", "MF": "Dense Fog", "MH": "Ashfall", "MS": "Dense Smoke", "RB": "Small Craft for Rough Bar", "RP": "Rip Current Risk", "SC": "Small Craft", "SE": "Hazardous Seas", "SI": "Small Craft for Winds", "SM": "Dense Smoke", "SQ": "Snow Squall", "SR": "Storm", "SS": "Storm Surge", "SU": "High Surf", "SV": "Severe Thunderstorm", "SW": "Small Craft for Hazardous Seas", "TO": "Tornado", "TR": "Tropical Storm", "TS": "Tsunami", "TY": "Typhoon", "UP": "Heavy Freezing Spray", "WC": "Wind Chill", "WI": "Wind", "WS": "Winter Storm", "WW": "Winter Weather", "ZF": "Freezing Fog", "ZR": "Freezing Rain", "ZY": "Freezing Spray" },
|
|
95
95
|
actions: { "W": "Warning", "F": "Forecast", "A": "Watch", "O": "Outlook", "Y": "Advisory", "N": "Synopsis", "S": "Statement" },
|
|
96
96
|
status: { "NEW": "Issued", "CON": "Updated", "EXT": "Extended", "EXA": "Extended", "EXB": "Extended", "UPG": "Upgraded", "COR": "Correction", "ROU": "Routine", "CAN": "Cancelled", "EXP": "Expired" },
|
|
97
|
+
offshore: {
|
|
98
|
+
"Special Weather Statement": "Special Weather Statement",
|
|
99
|
+
"Hurricane Warning": "Hurricane Warning",
|
|
100
|
+
"Hurricane Force Wind Warning": "Hurricane Force Wind Warning",
|
|
101
|
+
"Hurricane Watch": "Hurricane Watch",
|
|
102
|
+
"Tropical Storm Warning": "Tropical Storm Warning",
|
|
103
|
+
"Tropical Storm Watch": "Tropical Storm Watch",
|
|
104
|
+
"High Wind Warning": "High Wind Warning",
|
|
105
|
+
"Gale Warning": "Gale Warning",
|
|
106
|
+
"Small Craft Advisory": "Small Craft Advisory",
|
|
107
|
+
"Small Craft Warning": "Small Craft Warning",
|
|
108
|
+
},
|
|
97
109
|
awips: { SWOMCD: "mesoscale-discussion", LSR: "local-storm-report", SPS: "special-weather-statement" },
|
|
98
110
|
expressions: {
|
|
99
111
|
vtec: "[OTEX].(NEW|CON|EXT|EXA|EXB|UPG|CAN|EXP|COR|ROU).[A-Z]{4}.[A-Z]{2}.[WAYSFON].[0-9]{4}.[0-9]{6}T[0-9]{4}Z-[0-9]{6}T[0-9]{4}Z",
|
|
100
112
|
wmo: "[A-Z0-9]{6}\\s[A-Z]{4}\\s\\d{6}",
|
|
101
113
|
ugc1: "(\\w{2}[CZ](\\d{3}((-|>)\\s?(\n\n)?))+)",
|
|
102
114
|
ugc2: "(\\d{6}(-|>)\\s?(\n\n)?)",
|
|
115
|
+
ugc3: "(\\d{6})(?=-|$)",
|
|
103
116
|
dateline: "/d{3,4}s*(AM|PM)?s*[A-Z]{2,4}s+[A-Z]{3,}s+[A-Z]{3,}s+d{1,2}s+d{4}"
|
|
104
117
|
},
|
|
105
118
|
tags: {
|
package/dist/src/events.js
CHANGED
|
@@ -385,6 +385,110 @@ var mEvents = /** @class */ (function () {
|
|
|
385
385
|
});
|
|
386
386
|
});
|
|
387
387
|
};
|
|
388
|
+
/**
|
|
389
|
+
* @function newUnknownAlert
|
|
390
|
+
* @description Emits the 'onAlert' event with parsed unknown alert objects. (Non-CAP, Non-VTEC)
|
|
391
|
+
* The alert objects contain various properties such as id, tracking, action, area description, expiration time,
|
|
392
|
+
* issue time, event type, sender information, description, geocode, and parameters like WMO identifier,
|
|
393
|
+
* tornado detection, max hail size, max wind gust, and thunderstorm damage threat.
|
|
394
|
+
*
|
|
395
|
+
* @param {Object} stanza - The XMPP stanza containing the raw alert message.
|
|
396
|
+
*
|
|
397
|
+
* @emits onAlert - Emitted when a new raw alert is received and parsed.
|
|
398
|
+
*/
|
|
399
|
+
mEvents.newUnknownAlert = function (stanza) {
|
|
400
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
401
|
+
var messages, defaultWMO, alerts, _loop_1, i;
|
|
402
|
+
return __generator(this, function (_a) {
|
|
403
|
+
switch (_a.label) {
|
|
404
|
+
case 0:
|
|
405
|
+
messages = stanza.message.split(/(?=\$\$)/g).map(function (msg) { return msg.trim(); });
|
|
406
|
+
defaultWMO = stanza.message.match(new RegExp(loader.definitions.expressions.wmo, 'gimu'));
|
|
407
|
+
alerts = [];
|
|
408
|
+
_loop_1 = function (i) {
|
|
409
|
+
var pStartTime, message, mUgc, isOffshoreEvent, getForecastOffice, getPolygonCoordinates, getDescription, getTimeIssued, alert_3, ugcCoordinates;
|
|
410
|
+
return __generator(this, function (_b) {
|
|
411
|
+
switch (_b.label) {
|
|
412
|
+
case 0:
|
|
413
|
+
pStartTime = new Date().getTime();
|
|
414
|
+
message = messages[i];
|
|
415
|
+
return [4 /*yield*/, ugc_1.default.getUGC(message)];
|
|
416
|
+
case 1:
|
|
417
|
+
mUgc = _b.sent();
|
|
418
|
+
isOffshoreEvent = Object.keys(loader.definitions.offshore).some(function (event) { return message.toLowerCase().includes(event.toLowerCase()); });
|
|
419
|
+
if (mUgc != null && isOffshoreEvent != false) {
|
|
420
|
+
getForecastOffice = text_parser_1.default.getForecastOffice(message) || "NWS";
|
|
421
|
+
getPolygonCoordinates = text_parser_1.default.getPolygonCoordinates(message);
|
|
422
|
+
getDescription = text_parser_1.default.getCleanDescription(message, null);
|
|
423
|
+
getTimeIssued = text_parser_1.default.getString(message, "ISSUED TIME...");
|
|
424
|
+
if (getTimeIssued == null) {
|
|
425
|
+
getTimeIssued = new Date(stanza.attributes.issue).getTime();
|
|
426
|
+
}
|
|
427
|
+
if (getTimeIssued == null) {
|
|
428
|
+
getTimeIssued = new Date().getTime();
|
|
429
|
+
}
|
|
430
|
+
if (getTimeIssued != null) {
|
|
431
|
+
getTimeIssued = new Date(getTimeIssued).toLocaleString();
|
|
432
|
+
}
|
|
433
|
+
alert_3 = {
|
|
434
|
+
hitch: "".concat(new Date().getTime() - pStartTime, "ms"),
|
|
435
|
+
id: defaultWMO ? "".concat(defaultWMO[0], "-").concat(mUgc.zones.join("-")) : "N/A",
|
|
436
|
+
tracking: defaultWMO ? "".concat(defaultWMO[0], "-").concat(mUgc.zones.join("-")) : "N/A",
|
|
437
|
+
action: "Issued",
|
|
438
|
+
history: [{ description: getDescription, action: "Issued", issued: getTimeIssued }],
|
|
439
|
+
properties: {
|
|
440
|
+
areaDesc: mUgc.locations.join("; ") || 'N/A',
|
|
441
|
+
expires: new Date(mUgc.expiry != null ? mUgc.expiry : new Date().getTime() + 1 * 60 * 60 * 1000),
|
|
442
|
+
sent: new Date(getTimeIssued),
|
|
443
|
+
messageType: "Issued",
|
|
444
|
+
event: Object.keys(loader.definitions.offshore).find(function (event) { return message.toLowerCase().includes(event.toLowerCase()); }) || 'Unknown Event',
|
|
445
|
+
sender: getForecastOffice,
|
|
446
|
+
senderName: getForecastOffice,
|
|
447
|
+
description: getDescription || 'No description available.',
|
|
448
|
+
geocode: {
|
|
449
|
+
UGC: mUgc.zones || [],
|
|
450
|
+
},
|
|
451
|
+
parameters: {
|
|
452
|
+
WMOidentifier: (defaultWMO === null || defaultWMO === void 0 ? void 0 : defaultWMO[0]) ? [defaultWMO[0]] : ["N/A"],
|
|
453
|
+
tornadoDetection: "N/A",
|
|
454
|
+
maxHailSize: "N/A",
|
|
455
|
+
maxWindGust: "N/A",
|
|
456
|
+
thunderstormDamageThreat: ["N/A"],
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
geometry: { type: 'Polygon', coordinates: [getPolygonCoordinates] }
|
|
460
|
+
};
|
|
461
|
+
if (loader.settings.alertSettings.ugcPolygons) {
|
|
462
|
+
ugcCoordinates = ugc_1.default.getCoordinates(mUgc.zones);
|
|
463
|
+
if (ugcCoordinates.length > 0) {
|
|
464
|
+
alert_3.geometry = { type: 'Polygon', coordinates: [ugcCoordinates] };
|
|
465
|
+
}
|
|
466
|
+
;
|
|
467
|
+
}
|
|
468
|
+
alerts.push(alert_3);
|
|
469
|
+
}
|
|
470
|
+
return [2 /*return*/];
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
};
|
|
474
|
+
i = 0;
|
|
475
|
+
_a.label = 1;
|
|
476
|
+
case 1:
|
|
477
|
+
if (!(i < messages.length)) return [3 /*break*/, 4];
|
|
478
|
+
return [5 /*yield**/, _loop_1(i)];
|
|
479
|
+
case 2:
|
|
480
|
+
_a.sent();
|
|
481
|
+
_a.label = 3;
|
|
482
|
+
case 3:
|
|
483
|
+
i++;
|
|
484
|
+
return [3 /*break*/, 1];
|
|
485
|
+
case 4:
|
|
486
|
+
this.onFinished(alerts);
|
|
487
|
+
return [2 /*return*/];
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
};
|
|
388
492
|
/**
|
|
389
493
|
* @function newSpecialWeatherStatement
|
|
390
494
|
* @description Emits the 'onAlert' event with parsed special weather statement alert objects.
|
|
@@ -399,7 +503,7 @@ var mEvents = /** @class */ (function () {
|
|
|
399
503
|
*/
|
|
400
504
|
mEvents.newSpecialWeatherStatement = function (stanza) {
|
|
401
505
|
return __awaiter(this, void 0, void 0, function () {
|
|
402
|
-
var messages, defaultWMO, alerts, i, pStartTime, message, mUgc, getTornado, getHailSize, getWindGusts, getDamageThreat, getForecastOffice, getPolygonCoordinates, getDescription, getTimeIssued,
|
|
506
|
+
var messages, defaultWMO, alerts, i, pStartTime, message, mUgc, getTornado, getHailSize, getWindGusts, getDamageThreat, getForecastOffice, getPolygonCoordinates, getDescription, getTimeIssued, alert_4, ugcCoordinates;
|
|
403
507
|
return __generator(this, function (_a) {
|
|
404
508
|
switch (_a.label) {
|
|
405
509
|
case 0:
|
|
@@ -433,7 +537,7 @@ var mEvents = /** @class */ (function () {
|
|
|
433
537
|
if (getTimeIssued != null) {
|
|
434
538
|
getTimeIssued = new Date(getTimeIssued).toLocaleString();
|
|
435
539
|
}
|
|
436
|
-
|
|
540
|
+
alert_4 = {
|
|
437
541
|
hitch: "".concat(new Date().getTime() - pStartTime, "ms"),
|
|
438
542
|
id: defaultWMO ? "".concat(defaultWMO[0], "-").concat(mUgc.zones.join("-")) : "N/A",
|
|
439
543
|
tracking: defaultWMO ? "".concat(defaultWMO[0], "-").concat(mUgc.zones.join("-")) : "N/A",
|
|
@@ -441,7 +545,7 @@ var mEvents = /** @class */ (function () {
|
|
|
441
545
|
history: [{ description: getDescription, action: "Issued", issued: getTimeIssued }],
|
|
442
546
|
properties: {
|
|
443
547
|
areaDesc: mUgc.locations.join("; ") || 'N/A',
|
|
444
|
-
expires: new Date(new Date().getTime() + 1 * 60 * 60 * 1000),
|
|
548
|
+
expires: new Date(mUgc.expiry != null ? mUgc.expiry : new Date().getTime() + 1 * 60 * 60 * 1000),
|
|
445
549
|
sent: new Date(getTimeIssued),
|
|
446
550
|
messageType: "Issued",
|
|
447
551
|
event: "Special Weather Statement",
|
|
@@ -464,11 +568,11 @@ var mEvents = /** @class */ (function () {
|
|
|
464
568
|
if (loader.settings.alertSettings.ugcPolygons) {
|
|
465
569
|
ugcCoordinates = ugc_1.default.getCoordinates(mUgc.zones);
|
|
466
570
|
if (ugcCoordinates.length > 0) {
|
|
467
|
-
|
|
571
|
+
alert_4.geometry = { type: 'Polygon', coordinates: [ugcCoordinates] };
|
|
468
572
|
}
|
|
469
573
|
;
|
|
470
574
|
}
|
|
471
|
-
alerts.push(
|
|
575
|
+
alerts.push(alert_4);
|
|
472
576
|
}
|
|
473
577
|
_a.label = 3;
|
|
474
578
|
case 3:
|
|
@@ -494,7 +598,7 @@ var mEvents = /** @class */ (function () {
|
|
|
494
598
|
*/
|
|
495
599
|
mEvents.newMesoscaleDiscussion = function (stanza) {
|
|
496
600
|
return __awaiter(this, void 0, void 0, function () {
|
|
497
|
-
var messages, defaultWMO, i, pStartTime, message, mUgc, getForecastOffice, getDescription, getTornadoIntensity, getPeakWindGust, getPeakHailSize, getTimeIssued,
|
|
601
|
+
var messages, defaultWMO, i, pStartTime, message, mUgc, getForecastOffice, getDescription, getTornadoIntensity, getPeakWindGust, getPeakHailSize, getTimeIssued, alert_5;
|
|
498
602
|
return __generator(this, function (_a) {
|
|
499
603
|
switch (_a.label) {
|
|
500
604
|
case 0:
|
|
@@ -525,7 +629,7 @@ var mEvents = /** @class */ (function () {
|
|
|
525
629
|
if (getTimeIssued != null) {
|
|
526
630
|
getTimeIssued = new Date(getTimeIssued).toLocaleString();
|
|
527
631
|
}
|
|
528
|
-
|
|
632
|
+
alert_5 = {
|
|
529
633
|
hitch: "".concat(new Date().getTime() - pStartTime, "ms"),
|
|
530
634
|
id: defaultWMO ? "".concat(defaultWMO[0], "-").concat(mUgc.zones.join("-")) : "N/A",
|
|
531
635
|
tracking: defaultWMO ? "".concat(defaultWMO[0], "-").concat(mUgc.zones.join("-")) : "N/A",
|
|
@@ -551,7 +655,7 @@ var mEvents = /** @class */ (function () {
|
|
|
551
655
|
},
|
|
552
656
|
}
|
|
553
657
|
};
|
|
554
|
-
loader.statics.events.emit('onMesoscaleDiscussion',
|
|
658
|
+
loader.statics.events.emit('onMesoscaleDiscussion', alert_5);
|
|
555
659
|
}
|
|
556
660
|
_a.label = 3;
|
|
557
661
|
case 3:
|
package/dist/src/helper.js
CHANGED
|
@@ -313,6 +313,7 @@ var AtmosXWireParser = /** @class */ (function () {
|
|
|
313
313
|
var dict = [
|
|
314
314
|
{ file: "".concat(dir, "/category-defaults-raw-vtec.bin"), attributes: { awipsid: 'alert', isCap: false, raw: true, issue: undefined } },
|
|
315
315
|
{ file: "".concat(dir, "/category-defaults-cap-vtec.bin"), attributes: { awipsid: 'alert', isCap: true, raw: false, issue: undefined } },
|
|
316
|
+
{ file: "".concat(dir, "/category-defaults-raw.bin"), attributes: { awipsid: 'alert', isCap: false, raw: true, issue: undefined } },
|
|
316
317
|
{ file: "".concat(dir, "/category-special-weather-statements-raw.bin"), attributes: { awipsid: 'SPS001', isCap: false, raw: true, issue: undefined } },
|
|
317
318
|
{ file: "".concat(dir, "/category-mesoscale-discussions-raw.bin"), attributes: { awipsid: 'SWOMCD001', isCap: false, raw: true, issue: undefined } },
|
|
318
319
|
{ file: "".concat(dir, "/category-local-storm-reports.bin"), attributes: { awipsid: 'LSR001', isCap: false, raw: true, issue: undefined } },
|
package/dist/src/stanza.js
CHANGED
|
@@ -114,19 +114,22 @@ var mStanza = /** @class */ (function () {
|
|
|
114
114
|
*/
|
|
115
115
|
mStanza.create = function (stanzaData) {
|
|
116
116
|
if (stanzaData.getAwipsType == "default" && stanzaData.hasVTEC && stanzaData.isCap) {
|
|
117
|
-
events_1.default.newCapAlerts(stanzaData);
|
|
117
|
+
return events_1.default.newCapAlerts(stanzaData);
|
|
118
118
|
} // Default alert - CAP Only
|
|
119
119
|
if (stanzaData.getAwipsType == "default" && stanzaData.hasVTEC && !stanzaData.isCap) {
|
|
120
|
-
events_1.default.newRawAlerts(stanzaData);
|
|
120
|
+
return events_1.default.newRawAlerts(stanzaData);
|
|
121
121
|
} // Default alert - NonCAP
|
|
122
|
+
if (stanzaData.getAwipsType == "default" && !stanzaData.hasVTEC && !stanzaData.isCap) {
|
|
123
|
+
return events_1.default.newUnknownAlert(stanzaData);
|
|
124
|
+
} // Default alert - NonCAP, NonVTEC
|
|
122
125
|
if (stanzaData.getAwipsType == "special-weather-statement") {
|
|
123
|
-
events_1.default.newSpecialWeatherStatement(stanzaData);
|
|
126
|
+
return events_1.default.newSpecialWeatherStatement(stanzaData);
|
|
124
127
|
} // SPW (Special Weather Statement)
|
|
125
128
|
if (stanzaData.getAwipsType == "mesoscale-discussion") {
|
|
126
|
-
events_1.default.newMesoscaleDiscussion(stanzaData);
|
|
129
|
+
return events_1.default.newMesoscaleDiscussion(stanzaData);
|
|
127
130
|
} // MD (Mesoscale Discussion)
|
|
128
131
|
if (stanzaData.getAwipsType == "local-storm-report") {
|
|
129
|
-
events_1.default.newLocalStormReport(stanzaData);
|
|
132
|
+
return events_1.default.newLocalStormReport(stanzaData);
|
|
130
133
|
} // LSR (Local Storm Report)
|
|
131
134
|
};
|
|
132
135
|
/**
|
package/dist/src/ugc.js
CHANGED
|
@@ -94,16 +94,17 @@ var mUgcParser = /** @class */ (function () {
|
|
|
94
94
|
*/
|
|
95
95
|
mUgcParser.getUGC = function (message) {
|
|
96
96
|
return __awaiter(this, void 0, void 0, function () {
|
|
97
|
-
var header, zones, locations, ugc;
|
|
97
|
+
var header, zones, expiry, locations, ugc;
|
|
98
98
|
return __generator(this, function (_a) {
|
|
99
99
|
switch (_a.label) {
|
|
100
100
|
case 0:
|
|
101
101
|
header = this.getHeader(message);
|
|
102
102
|
zones = this.getZones(header);
|
|
103
|
+
expiry = this.getExpiry(message);
|
|
103
104
|
return [4 /*yield*/, this.getLocations(zones)];
|
|
104
105
|
case 1:
|
|
105
106
|
locations = _a.sent();
|
|
106
|
-
ugc = zones.length > 0 ? { zones: zones, locations: locations } : null;
|
|
107
|
+
ugc = zones.length > 0 ? { zones: zones, locations: locations, expiry: expiry } : null;
|
|
107
108
|
return [2 /*return*/, ugc];
|
|
108
109
|
}
|
|
109
110
|
});
|
|
@@ -121,6 +122,18 @@ var mUgcParser = /** @class */ (function () {
|
|
|
121
122
|
var full = message.substring(start, start + end).replace(/\s+/g, '').slice(0, -1);
|
|
122
123
|
return full;
|
|
123
124
|
};
|
|
125
|
+
mUgcParser.getExpiry = function (message) {
|
|
126
|
+
var start = message.match(new RegExp(loader.definitions.expressions.ugc3, "gimu"));
|
|
127
|
+
if (start != null) {
|
|
128
|
+
var day = parseInt(start[0].substring(0, 2), 10);
|
|
129
|
+
var hour = parseInt(start[0].substring(2, 4), 10);
|
|
130
|
+
var minute = parseInt(start[0].substring(4, 6), 10);
|
|
131
|
+
var now = new Date();
|
|
132
|
+
var expires = new Date(now.getUTCFullYear(), now.getUTCMonth(), day, hour, minute, 0);
|
|
133
|
+
return expires;
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
};
|
|
124
137
|
/**
|
|
125
138
|
* @function getLocations
|
|
126
139
|
* @description Retrieves location names from a database based on UGC zone codes.
|
package/package.json
CHANGED
package/src/events.ts
CHANGED
|
@@ -244,6 +244,75 @@ export class mEvents {
|
|
|
244
244
|
this.onFinished(alerts);
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* @function newUnknownAlert
|
|
250
|
+
* @description Emits the 'onAlert' event with parsed unknown alert objects. (Non-CAP, Non-VTEC)
|
|
251
|
+
* The alert objects contain various properties such as id, tracking, action, area description, expiration time,
|
|
252
|
+
* issue time, event type, sender information, description, geocode, and parameters like WMO identifier,
|
|
253
|
+
* tornado detection, max hail size, max wind gust, and thunderstorm damage threat.
|
|
254
|
+
*
|
|
255
|
+
* @param {Object} stanza - The XMPP stanza containing the raw alert message.
|
|
256
|
+
*
|
|
257
|
+
* @emits onAlert - Emitted when a new raw alert is received and parsed.
|
|
258
|
+
*/
|
|
259
|
+
|
|
260
|
+
static async newUnknownAlert (stanza: any) {
|
|
261
|
+
const messages = stanza.message.split(/(?=\$\$)/g).map(msg => msg.trim());
|
|
262
|
+
let defaultWMO = stanza.message.match(new RegExp(loader.definitions.expressions.wmo, 'gimu'));
|
|
263
|
+
let alerts: any[] = [];
|
|
264
|
+
for (let i = 0; i < messages.length; i++) {
|
|
265
|
+
const pStartTime = new Date().getTime()
|
|
266
|
+
const message = messages[i];
|
|
267
|
+
const mUgc = await mUgcParser.getUGC(message);
|
|
268
|
+
const isOffshoreEvent = Object.keys(loader.definitions.offshore).some(event => message.toLowerCase().includes(event.toLowerCase()));
|
|
269
|
+
if (mUgc != null && isOffshoreEvent != false) {
|
|
270
|
+
const getForecastOffice = mTextParser.getForecastOffice(message) || `NWS`;
|
|
271
|
+
const getPolygonCoordinates = mTextParser.getPolygonCoordinates(message);
|
|
272
|
+
const getDescription = mTextParser.getCleanDescription(message, null);
|
|
273
|
+
let getTimeIssued : any = mTextParser.getString(message, `ISSUED TIME...`)
|
|
274
|
+
if (getTimeIssued == null) { getTimeIssued = new Date(stanza.attributes.issue).getTime(); }
|
|
275
|
+
if (getTimeIssued == null) { getTimeIssued = new Date().getTime(); }
|
|
276
|
+
if (getTimeIssued != null) { getTimeIssued = new Date(getTimeIssued).toLocaleString(); }
|
|
277
|
+
let alert = {
|
|
278
|
+
hitch: `${new Date().getTime() - pStartTime}ms`,
|
|
279
|
+
id: defaultWMO ? `${defaultWMO[0]}-${mUgc.zones.join(`-`)}` : `N/A`,
|
|
280
|
+
tracking: defaultWMO ? `${defaultWMO[0]}-${mUgc.zones.join(`-`)}` : `N/A`,
|
|
281
|
+
action: `Issued`,
|
|
282
|
+
history: [{description: getDescription, action: `Issued`, issued: getTimeIssued}],
|
|
283
|
+
properties: {
|
|
284
|
+
areaDesc: mUgc.locations.join(`; `) || 'N/A',
|
|
285
|
+
expires: new Date(mUgc.expiry != null ? mUgc.expiry : new Date().getTime() + 1 * 60 * 60 * 1000),
|
|
286
|
+
sent: new Date(getTimeIssued),
|
|
287
|
+
messageType: `Issued`,
|
|
288
|
+
event: Object.keys(loader.definitions.offshore).find(event => message.toLowerCase().includes(event.toLowerCase())) || 'Unknown Event',
|
|
289
|
+
sender: getForecastOffice,
|
|
290
|
+
senderName: getForecastOffice,
|
|
291
|
+
description: getDescription || 'No description available.',
|
|
292
|
+
geocode: {
|
|
293
|
+
UGC: mUgc.zones || [],
|
|
294
|
+
},
|
|
295
|
+
parameters: {
|
|
296
|
+
WMOidentifier: defaultWMO?.[0] ? [defaultWMO[0]] : [`N/A`],
|
|
297
|
+
tornadoDetection: `N/A`,
|
|
298
|
+
maxHailSize: `N/A`,
|
|
299
|
+
maxWindGust: `N/A`,
|
|
300
|
+
thunderstormDamageThreat: [`N/A`],
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
geometry: { type: 'Polygon', coordinates: [getPolygonCoordinates] }
|
|
304
|
+
};
|
|
305
|
+
if (loader.settings.alertSettings.ugcPolygons) {
|
|
306
|
+
const ugcCoordinates = mUgcParser.getCoordinates(mUgc.zones);
|
|
307
|
+
if (ugcCoordinates.length > 0) { alert.geometry = { type: 'Polygon', coordinates: [ugcCoordinates] }; };
|
|
308
|
+
}
|
|
309
|
+
alerts.push(alert);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
this.onFinished(alerts);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
|
|
247
316
|
/**
|
|
248
317
|
* @function newSpecialWeatherStatement
|
|
249
318
|
* @description Emits the 'onAlert' event with parsed special weather statement alert objects.
|
|
@@ -285,7 +354,7 @@ export class mEvents {
|
|
|
285
354
|
history: [{description: getDescription, action: `Issued`, issued: getTimeIssued}],
|
|
286
355
|
properties: {
|
|
287
356
|
areaDesc: mUgc.locations.join(`; `) || 'N/A',
|
|
288
|
-
expires: new Date(new Date().getTime() + 1 * 60 * 60 * 1000),
|
|
357
|
+
expires: new Date(mUgc.expiry != null ? mUgc.expiry : new Date().getTime() + 1 * 60 * 60 * 1000),
|
|
289
358
|
sent: new Date(getTimeIssued),
|
|
290
359
|
messageType: `Issued`,
|
|
291
360
|
event: `Special Weather Statement`,
|
package/src/helper.ts
CHANGED
|
@@ -183,6 +183,7 @@ export class AtmosXWireParser {
|
|
|
183
183
|
let dict = [
|
|
184
184
|
{ file: `${dir}/category-defaults-raw-vtec.bin`, attributes: { awipsid: 'alert', isCap: false, raw: true, issue: undefined }},
|
|
185
185
|
{ file: `${dir}/category-defaults-cap-vtec.bin`, attributes: { awipsid: 'alert', isCap: true, raw: false, issue: undefined }},
|
|
186
|
+
{ file: `${dir}/category-defaults-raw.bin`, attributes: { awipsid: 'alert', isCap: false, raw: true, issue: undefined }},
|
|
186
187
|
{ file: `${dir}/category-special-weather-statements-raw.bin`, attributes: { awipsid: 'SPS001', isCap: false, raw: true, issue: undefined }},
|
|
187
188
|
{ file: `${dir}/category-mesoscale-discussions-raw.bin`, attributes: { awipsid: 'SWOMCD001', isCap: false, raw: true, issue: undefined }},
|
|
188
189
|
{ file: `${dir}/category-local-storm-reports.bin`, attributes: { awipsid: 'LSR001', isCap: false, raw: true, issue: undefined }},
|
package/src/stanza.ts
CHANGED
|
@@ -77,11 +77,12 @@ export class mStanza {
|
|
|
77
77
|
*/
|
|
78
78
|
|
|
79
79
|
static create (stanzaData: any) {
|
|
80
|
-
if (stanzaData.getAwipsType == `default` && stanzaData.hasVTEC && stanzaData.isCap) { mEvents.newCapAlerts(stanzaData) } // Default alert - CAP Only
|
|
81
|
-
if (stanzaData.getAwipsType == `default` && stanzaData.hasVTEC && !stanzaData.isCap) { mEvents.newRawAlerts(stanzaData) } // Default alert - NonCAP
|
|
82
|
-
if (stanzaData.getAwipsType == `
|
|
83
|
-
if (stanzaData.getAwipsType == `
|
|
84
|
-
if (stanzaData.getAwipsType == `
|
|
80
|
+
if (stanzaData.getAwipsType == `default` && stanzaData.hasVTEC && stanzaData.isCap) { return mEvents.newCapAlerts(stanzaData) } // Default alert - CAP Only
|
|
81
|
+
if (stanzaData.getAwipsType == `default` && stanzaData.hasVTEC && !stanzaData.isCap) { return mEvents.newRawAlerts(stanzaData) } // Default alert - NonCAP
|
|
82
|
+
if (stanzaData.getAwipsType == `default` && !stanzaData.hasVTEC && !stanzaData.isCap) { return mEvents.newUnknownAlert(stanzaData) } // Default alert - NonCAP, NonVTEC
|
|
83
|
+
if (stanzaData.getAwipsType == `special-weather-statement`) { return mEvents.newSpecialWeatherStatement(stanzaData) } // SPW (Special Weather Statement)
|
|
84
|
+
if (stanzaData.getAwipsType == `mesoscale-discussion`) { return mEvents.newMesoscaleDiscussion(stanzaData) } // MD (Mesoscale Discussion)
|
|
85
|
+
if (stanzaData.getAwipsType == `local-storm-report`) { return mEvents.newLocalStormReport(stanzaData) } // LSR (Local Storm Report)
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
/**
|
package/src/ugc.ts
CHANGED
|
@@ -26,8 +26,9 @@ export class mUgcParser {
|
|
|
26
26
|
static async getUGC (message: string) {
|
|
27
27
|
const header = this.getHeader(message);
|
|
28
28
|
const zones = this.getZones(header);
|
|
29
|
+
const expiry = this.getExpiry(message)
|
|
29
30
|
const locations = await this.getLocations(zones);
|
|
30
|
-
const ugc = zones.length > 0 ? { zones, locations} : null;
|
|
31
|
+
const ugc = zones.length > 0 ? { zones, locations, expiry } : null;
|
|
31
32
|
return ugc;
|
|
32
33
|
}
|
|
33
34
|
|
|
@@ -39,12 +40,25 @@ export class mUgcParser {
|
|
|
39
40
|
*/
|
|
40
41
|
|
|
41
42
|
static getHeader (message: string) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
const start = message.search(new RegExp(loader.definitions.expressions.ugc1, "gimu"));
|
|
44
|
+
const end = message.substring(start).search(new RegExp(loader.definitions.expressions.ugc2, "gimu"));
|
|
45
|
+
const full = message.substring(start, start + end).replace(/\s+/g, '').slice(0, -1);
|
|
45
46
|
return full;
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
static getExpiry (message: string) {
|
|
50
|
+
const start = message.match(new RegExp(loader.definitions.expressions.ugc3, "gimu"));
|
|
51
|
+
if (start != null) {
|
|
52
|
+
const day = parseInt(start[0].substring(0, 2), 10);
|
|
53
|
+
const hour = parseInt(start[0].substring(2, 4), 10);
|
|
54
|
+
const minute = parseInt(start[0].substring(4, 6), 10);
|
|
55
|
+
const now = new Date();
|
|
56
|
+
const expires = new Date(now.getUTCFullYear(), now.getUTCMonth(), day, hour, minute, 0);
|
|
57
|
+
return expires;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
48
62
|
/**
|
|
49
63
|
* @function getLocations
|
|
50
64
|
* @description Retrieves location names from a database based on UGC zone codes.
|