Restore US Hazard/severe weather behavior
Some checks are pending
build-docker / Build Image (push) Waiting to run
Some checks are pending
build-docker / Build Image (push) Waiting to run
This commit is contained in:
parent
97b59a6bd4
commit
952872ab92
3 changed files with 55 additions and 15 deletions
|
|
@ -189,11 +189,35 @@ const init = async () => {
|
||||||
|
|
||||||
const normalizeArcGisLocation = (rawLocation = {}, fallbackLabel = '') => {
|
const normalizeArcGisLocation = (rawLocation = {}, fallbackLabel = '') => {
|
||||||
const attributes = rawLocation.attributes ?? rawLocation.address ?? {};
|
const attributes = rawLocation.attributes ?? rawLocation.address ?? {};
|
||||||
const countryCode = attributes.CountryCode ?? attributes.countryCode ?? attributes.country_code ?? null;
|
const label = fallbackLabel || rawLocation.name || attributes.LongLabel || attributes.Match_addr || '';
|
||||||
const country = attributes.Country ?? attributes.countryName ?? attributes.country ?? null;
|
const labelParts = label.split(',').map((part) => part.trim()).filter(Boolean);
|
||||||
const state = attributes.RegionAbbr ?? attributes.Region ?? attributes.Subregion ?? attributes.region ?? '';
|
const fallbackCountryCode = labelParts[labelParts.length - 1] === 'USA' ? 'USA' : null;
|
||||||
const city = attributes.City ?? attributes.CityName ?? attributes.MetroArea ?? rawLocation.name ?? '';
|
const fallbackCountry = fallbackCountryCode ? 'United States' : null;
|
||||||
const label = fallbackLabel || rawLocation.name || [city, state || country].filter(Boolean).join(', ');
|
const fallbackState = labelParts.length >= 2 && /^[A-Z]{2,3}$/.test(labelParts[labelParts.length - 2]) ? labelParts[labelParts.length - 2] : '';
|
||||||
|
const fallbackCity = labelParts[0] ?? rawLocation.name ?? '';
|
||||||
|
|
||||||
|
const countryCode = attributes.CountryCode
|
||||||
|
?? attributes.countryCode
|
||||||
|
?? attributes.country_code
|
||||||
|
?? fallbackCountryCode
|
||||||
|
?? null;
|
||||||
|
const country = attributes.CntryName
|
||||||
|
?? attributes.Country
|
||||||
|
?? attributes.countryName
|
||||||
|
?? attributes.country
|
||||||
|
?? fallbackCountry
|
||||||
|
?? null;
|
||||||
|
const state = attributes.RegionAbbr
|
||||||
|
?? attributes.Region
|
||||||
|
?? attributes.Subregion
|
||||||
|
?? attributes.region
|
||||||
|
?? fallbackState;
|
||||||
|
const city = attributes.City
|
||||||
|
?? attributes.CityName
|
||||||
|
?? attributes.PlaceName
|
||||||
|
?? attributes.MetroArea
|
||||||
|
?? rawLocation.name
|
||||||
|
?? fallbackCity;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
city,
|
city,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ const hazardModifiers = {
|
||||||
'Severe Thunderstorm Warning': 1,
|
'Severe Thunderstorm Warning': 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getAlertSignature = (alerts = []) => alerts.map((alert) => alert.id).sort().join('|');
|
||||||
|
|
||||||
class Hazards extends WeatherDisplay {
|
class Hazards extends WeatherDisplay {
|
||||||
constructor(navId, elemId, defaultActive) {
|
constructor(navId, elemId, defaultActive) {
|
||||||
// special height and width for scrolling
|
// special height and width for scrolling
|
||||||
|
|
@ -34,6 +36,7 @@ class Hazards extends WeatherDisplay {
|
||||||
// take note of the already-shown alert ids
|
// take note of the already-shown alert ids
|
||||||
this.viewedAlerts = new Set();
|
this.viewedAlerts = new Set();
|
||||||
this.viewedGetCount = 0;
|
this.viewedGetCount = 0;
|
||||||
|
this.alertSignature = '';
|
||||||
|
|
||||||
// cache for scroll calculations
|
// cache for scroll calculations
|
||||||
// This cache is essential because baseCountChange() is called 25 times per second (every 40ms)
|
// This cache is essential because baseCountChange() is called 25 times per second (every 40ms)
|
||||||
|
|
@ -52,7 +55,7 @@ class Hazards extends WeatherDisplay {
|
||||||
async getData(weatherParameters, refresh) {
|
async getData(weatherParameters, refresh) {
|
||||||
// super checks for enabled
|
// super checks for enabled
|
||||||
const superResult = super.getData(weatherParameters, refresh);
|
const superResult = super.getData(weatherParameters, refresh);
|
||||||
if (!this.weatherParameters?.supportsNoaaDisplays) {
|
if (!this.weatherParameters?.supportsNoaaAlerts) {
|
||||||
this.data = [];
|
this.data = [];
|
||||||
this.timing.totalScreens = 0;
|
this.timing.totalScreens = 0;
|
||||||
this.getDataCallback();
|
this.getDataCallback();
|
||||||
|
|
@ -75,6 +78,7 @@ class Hazards extends WeatherDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const previousSignature = this.alertSignature;
|
||||||
// get the forecast using centralized safe handling
|
// get the forecast using centralized safe handling
|
||||||
const url = new URL('https://api.weather.gov/alerts/active');
|
const url = new URL('https://api.weather.gov/alerts/active');
|
||||||
url.searchParams.append('point', `${this.weatherParameters.latitude},${this.weatherParameters.longitude}`);
|
url.searchParams.append('point', `${this.weatherParameters.latitude},${this.weatherParameters.longitude}`);
|
||||||
|
|
@ -94,6 +98,14 @@ class Hazards extends WeatherDisplay {
|
||||||
const filteredAlerts = sortedAlerts.filter((hazard) => hazard.properties.severity !== 'Unknown' && (!hasImmediate || (hazard.properties.urgency === 'Immediate')));
|
const filteredAlerts = sortedAlerts.filter((hazard) => hazard.properties.severity !== 'Unknown' && (!hasImmediate || (hazard.properties.urgency === 'Immediate')));
|
||||||
this.data = filteredAlerts;
|
this.data = filteredAlerts;
|
||||||
}
|
}
|
||||||
|
this.alertSignature = getAlertSignature(this.data);
|
||||||
|
const alertsChanged = previousSignature !== this.alertSignature;
|
||||||
|
if (alertsChanged) {
|
||||||
|
this.viewedAlerts.clear();
|
||||||
|
if (this.data.length > 0) {
|
||||||
|
postMessage({ type: 'current-weather-scroll', method: 'reload' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// every 10 times through the get process (10 minutes), reset the viewed messages
|
// every 10 times through the get process (10 minutes), reset the viewed messages
|
||||||
if (this.viewedGetCount >= 10) {
|
if (this.viewedGetCount >= 10) {
|
||||||
|
|
@ -137,10 +149,11 @@ class Hazards extends WeatherDisplay {
|
||||||
const list = this.elem.querySelector('.hazard-lines');
|
const list = this.elem.querySelector('.hazard-lines');
|
||||||
list.innerHTML = '';
|
list.innerHTML = '';
|
||||||
|
|
||||||
// filter viewed alerts
|
// Prefer new alerts, but keep active alerts visible even after they've been viewed once.
|
||||||
const unViewed = this.data.filter((data) => !this.viewedAlerts.has(data.id));
|
const unViewed = this.data.filter((data) => !this.viewedAlerts.has(data.id));
|
||||||
|
const alertsToDisplay = unViewed.length > 0 ? unViewed : this.data;
|
||||||
|
|
||||||
const lines = unViewed.map((data) => {
|
const lines = alertsToDisplay.map((data) => {
|
||||||
const fillValues = {};
|
const fillValues = {};
|
||||||
const description = data.properties.description
|
const description = data.properties.description
|
||||||
.replaceAll('\n\n', '<br/><br/>')
|
.replaceAll('\n\n', '<br/><br/>')
|
||||||
|
|
@ -230,8 +243,6 @@ class Hazards extends WeatherDisplay {
|
||||||
const superValue = super.screenIndexFromBaseCount();
|
const superValue = super.screenIndexFromBaseCount();
|
||||||
// false is returned when we reach the end of the scroll
|
// false is returned when we reach the end of the scroll
|
||||||
if (superValue === false) {
|
if (superValue === false) {
|
||||||
// set total screens to zero to take this out of the rotation
|
|
||||||
this.timing.totalScreens = 0;
|
|
||||||
// note the ids shown
|
// note the ids shown
|
||||||
this?.data?.forEach((alert) => this.viewedAlerts.add(alert.id));
|
this?.data?.forEach((alert) => this.viewedAlerts.add(alert.id));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,18 +95,22 @@ const getWeather = async (latLon, haveDataCallback) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const supportsNoaaDisplays = isUsLocation(location);
|
const supportsNoaaDisplays = isUsLocation(location);
|
||||||
|
const shouldTryNoaaPoint = supportsNoaaDisplays || !location.countryCode;
|
||||||
let point = null;
|
let point = null;
|
||||||
let stations = null;
|
let stations = null;
|
||||||
let stationId = '';
|
let stationId = '';
|
||||||
|
|
||||||
if (supportsNoaaDisplays) {
|
if (shouldTryNoaaPoint) {
|
||||||
point = await getPoint(latLon.lat, latLon.lon);
|
point = await getPoint(latLon.lat, latLon.lon);
|
||||||
if (point?.properties?.observationStations) {
|
|
||||||
stations = await safeJson(point.properties.observationStations);
|
|
||||||
stationId = stations?.features?.[0]?.properties?.stationIdentifier ?? '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (supportsNoaaDisplays && point?.properties?.observationStations) {
|
||||||
|
stations = await safeJson(point.properties.observationStations);
|
||||||
|
stationId = stations?.features?.[0]?.properties?.stationIdentifier ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const supportsNoaaAlerts = !!(isUsLocation(location) || point);
|
||||||
|
|
||||||
const state = location.state || point?.properties?.relativeLocation?.properties?.state || '';
|
const state = location.state || point?.properties?.relativeLocation?.properties?.state || '';
|
||||||
let city = location.city || point?.properties?.relativeLocation?.properties?.city || localStorage.getItem('latLonQuery') || '';
|
let city = location.city || point?.properties?.relativeLocation?.properties?.city || localStorage.getItem('latLonQuery') || '';
|
||||||
if (stationId && stationId in StationInfo) {
|
if (stationId && stationId in StationInfo) {
|
||||||
|
|
@ -124,6 +128,7 @@ const getWeather = async (latLon, haveDataCallback) => {
|
||||||
weatherParameters.countryCode = location.countryCode ?? '';
|
weatherParameters.countryCode = location.countryCode ?? '';
|
||||||
weatherParameters.timeZone = openMeteoForecast.timezone;
|
weatherParameters.timeZone = openMeteoForecast.timezone;
|
||||||
weatherParameters.forecast = aggregatedForecast;
|
weatherParameters.forecast = aggregatedForecast;
|
||||||
|
weatherParameters.supportsNoaaAlerts = supportsNoaaAlerts;
|
||||||
weatherParameters.supportsNoaaDisplays = !!(supportsNoaaDisplays && point && stations?.features?.length);
|
weatherParameters.supportsNoaaDisplays = !!(supportsNoaaDisplays && point && stations?.features?.length);
|
||||||
weatherParameters.zoneId = point?.properties?.forecastZone?.substr(-6) ?? '';
|
weatherParameters.zoneId = point?.properties?.forecastZone?.substr(-6) ?? '';
|
||||||
weatherParameters.radarId = point?.properties?.radarStation?.substr(-3) ?? '';
|
weatherParameters.radarId = point?.properties?.radarStation?.substr(-3) ?? '';
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue