Compare commits

...

7 Commits

Author SHA1 Message Date
Matt Walsh
f4289e6329 Merge branch 'main' into screen-enahnce/magic-number-code 2026-04-08 22:56:20 -05:00
Matt Walsh
11c54391b2 6.5.7 2026-04-08 22:42:07 -05:00
Matt Walsh
0b47cf79c1 don't overwrite timestamps when enhancing with mapclick 2026-04-08 22:41:42 -05:00
Matt Walsh
ba36904477 6.5.6 2026-04-08 11:39:36 -05:00
Matt Walsh
dae5b20bc6 fix radar round/floor mismatch in calculations close #200 2026-04-08 11:39:25 -05:00
Matt Walsh
ccc936d81a 6.5.5 2026-04-08 09:57:24 -05:00
Matt Walsh
5dc214c6a5 filter station list upon receipt 2026-04-08 09:57:18 -05:00
7 changed files with 38 additions and 25 deletions

View File

@@ -8,13 +8,11 @@ import states from './stations-states.mjs';
import chunk from './chunk.mjs';
import overrides from './stations-overrides.mjs';
import postProcessor from './stations-postprocessor.mjs';
import { stationFilter } from '../server/scripts/modules/utils/string.mjs';
// check for cached flag
const USE_CACHE = process.argv.includes('--use-cache');
// skip stations starting with these letters
const skipStations = ['U', 'C', 'H', 'W', 'Y', 'T', 'S', 'M', 'O', 'L', 'A', 'F', 'B', 'N', 'V', 'R', 'D', 'E', 'I', 'G', 'J'];
// chunk the list of states
const chunkStates = chunk(states, 3);
@@ -41,10 +39,8 @@ if (!USE_CACHE) {
// eslint-disable-next-line no-await-in-loop
const stationsRaw = await https(next);
stations = JSON.parse(stationsRaw);
// filter stations for 4 letter identifiers
const stationsFiltered4 = stations.features.filter((station) => station.properties.stationIdentifier.match(/^[A-Z]{4}$/));
// filter against starting letter
const stationsFiltered = stationsFiltered4.filter((station) => !skipStations.includes(station.properties.stationIdentifier.slice(0, 1)));
const stationsFiltered = stations.filter(stationFilter);
// add each resulting station to the output
stationsFiltered.forEach((station) => {
const id = station.properties.stationIdentifier;

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "ws4kp",
"version": "6.5.4",
"version": "6.5.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ws4kp",
"version": "6.5.4",
"version": "6.5.7",
"license": "MIT",
"dependencies": {
"dotenv": "^17.0.1",

View File

@@ -1,6 +1,6 @@
{
"name": "ws4kp",
"version": "6.5.4",
"version": "6.5.7",
"description": "Welcome to the WeatherStar 4000+ project page!",
"main": "index.mjs",
"type": "module",

View File

@@ -16,9 +16,6 @@ import { isDataStale, enhanceObservationWithMapClick } from './utils/mapclick.mj
import { DateTime } from '../vendor/auto/luxon.mjs';
import settings from './settings.mjs';
// some stations prefixed do not provide all the necessary data
const skipStations = ['U', 'C', 'H', 'W', 'Y', 'T', 'S', 'M', 'O', 'L', 'A', 'F', 'B', 'N', 'V', 'R', 'D', 'E', 'I', 'G', 'J'];
class CurrentWeather extends WeatherDisplay {
constructor(navId, elemId) {
super(navId, elemId, 'Current Conditions', true);
@@ -30,8 +27,8 @@ class CurrentWeather extends WeatherDisplay {
// note: current weather does not use old data on a silent refresh
// this is deliberate because it can pull data from more than one station in sequence
// filter for 4-letter observation stations, only those contain sky conditions and thus an icon
const filteredStations = this.weatherParameters.stations.filter((station) => station?.properties?.stationIdentifier?.length === 4 && !skipStations.includes(station.properties.stationIdentifier.slice(0, 1)));
// get the available stations
const { stations } = this.weatherParameters;
// Load the observations
let observations;
@@ -39,9 +36,9 @@ class CurrentWeather extends WeatherDisplay {
// station number counter
let stationNum = 0;
while (!observations && stationNum < filteredStations.length) {
while (!observations && stationNum < stations.length) {
// get the station
station = filteredStations[stationNum];
station = stations[stationNum];
const stationId = station.properties.stationIdentifier;
stationNum += 1;
@@ -105,7 +102,11 @@ class CurrentWeather extends WeatherDisplay {
debugContext: 'currentweather',
});
// copy enhanced data and restore the timestamp if it was overwritten by older data from mapclick
const { timestamp } = candidateObservation.features[0].properties;
candidateObservation.features[0].properties = enhancedResult.data;
candidateObservation.features[0].properties.timestamp = timestamp;
const { missingFields } = enhancedResult;
const missingRequired = missingFields.filter((fieldName) => {
const field = requiredFields.find((f) => f.name === fieldName && f.required);

View File

@@ -6,6 +6,7 @@ import { safeJson } from './utils/fetch.mjs';
import { getPoint } from './utils/weather.mjs';
import { debugFlag } from './utils/debug.mjs';
import settings from './settings.mjs';
import { stationFilter } from './utils/string.mjs';
document.addEventListener('DOMContentLoaded', () => {
init();
@@ -90,7 +91,15 @@ const getWeather = async (latLon, haveDataCallback) => {
return;
}
const StationId = stations.features[0].properties.stationIdentifier;
// filter stations for proper format
const stationsFiltered = stations.features.filter(stationFilter);
// check for stations available after filtering
if (stationsFiltered.length === 0) {
console.warn('No observation stations left for location after filtering');
return;
}
const StationId = stationsFiltered[0].properties.stationIdentifier;
let { city } = point.properties.relativeLocation.properties;
const { state } = point.properties.relativeLocation.properties;
@@ -113,7 +122,7 @@ const getWeather = async (latLon, haveDataCallback) => {
weatherParameters.timeZone = point.properties.timeZone;
weatherParameters.forecast = point.properties.forecast;
weatherParameters.forecastGridData = point.properties.forecastGridData;
weatherParameters.stations = stations.features;
weatherParameters.stations = stationsFiltered;
weatherParameters.relativeLocation = point.properties.relativeLocation.properties;
// update the main process for display purposes

View File

@@ -9,10 +9,12 @@ const pixelToFile = (xPixel, yPixel) => {
return `${yTile}-${xTile}`;
};
// convert a pixel location in the overall map to a pixel location on the tile
// convert a pixel location in the overall map to a pixel location on the tile set
const modTile = (xPixel, yPixel) => {
const x = Math.round(xPixel) % TILE_SIZE.x;
const y = Math.round(yPixel) % TILE_SIZE.y;
// adjust for additional 1 tile when odd
const x = (Math.floor(xPixel) % (TILE_SIZE.x));
const y = (Math.floor(yPixel) % (TILE_SIZE.y));
return { x, y };
};
@@ -46,11 +48,11 @@ const setTiles = (data) => {
const tileShift = modTile(sourceXY.x, sourceXY.y);
// determine which tiles are used
const secondRow = TILE_SIZE.y - tileShift.y < RADAR_FINAL_SIZE().width;
const secondRow = tileShift.y + TILE_SIZE.y > RADAR_FINAL_SIZE().height;
const usedTiles = [
true,
TILE_SIZE.x - tileShift.x < RADAR_FINAL_SIZE().width,
TILE_SIZE.x - (tileShift.x * 2) < RADAR_FINAL_SIZE().width,
tileShift.x + TILE_SIZE.x > RADAR_FINAL_SIZE.width,
tileShift.x + (TILE_SIZE.x * 2) > RADAR_FINAL_SIZE.width,
secondRow,
];
// second row is a copy of the first row when in use

View File

@@ -13,7 +13,12 @@ const locationCleanup = (input) => {
return regexes.reduce((value, regex) => value.replace(regex, ''), input);
};
// stations must be 4 alpha characters and not start with the provided list
const skipStations = ['U', 'C', 'H', 'W', 'Y', 'T', 'S', 'M', 'O', 'L', 'A', 'F', 'B', 'N', 'V', 'R', 'D', 'E', 'I', 'G', 'J'];
const stationFilter = (station) => station.properties.stationIdentifier.match(/^[A-Z]{4}$/) && !skipStations.includes(station.properties.stationIdentifier.slice(0, 1));
export {
// eslint-disable-next-line import/prefer-default-export
locationCleanup,
stationFilter,
};