Compare commits

...

9 Commits

Author SHA1 Message Date
Matt Walsh
471d322cde 5.14.3 2025-03-08 13:39:44 -06:00
Matt Walsh
8f9be046ac fix metric conversion on regional forecast map 2025-03-08 13:39:36 -06:00
Matt Walsh
c34dc1ff25 capture dist 2025-02-25 09:51:29 -06:00
Matt Walsh
9b4eed7332 5.14.2 2025-02-25 09:50:46 -06:00
Matt Walsh
ef1477f9eb fix hourly forecast temperature double-converted 2025-02-25 09:49:12 -06:00
Matt Walsh
e2876df177 5.14.1 2025-02-25 09:44:32 -06:00
Matt Walsh
d6335b2878 fix time zones on hourly and almanac close #67 2025-02-25 09:44:24 -06:00
mwood77
781128100e Update README to include ws4kp-international (#66)
* Update README to include `ws4kp-international`

* adjust grammar in readme

* tidy links
2025-02-24 14:16:30 -06:00
Matt Walsh
56261ded4b capture dist 2025-02-23 23:35:05 -06:00
10 changed files with 43 additions and 29 deletions

View File

@@ -16,6 +16,13 @@ This project is based on the work of [Mike Battaglia](https://github.com/vbguyny
* [Icon](https://twcclassics.com/downloads.html) sets
* Countless photos and videos of WeatherStar 4000 forecasts used as references.
## Does WeatherStar 4000+ work outside of the USA?
This project is tightly coupled to [NOAA's Weather API](https://www.weather.gov/documentation/services-web-api), which is exclsuive to the United States. Using NOAA's Weather API is a crucial requirement to provide an authentic WeatherStar 4000+ experience.
If you would like to display weather information for international locations (outside of the USA), please checkout a fork of this project created by [@mwood77](https://github.com/mwood77):
- [`ws4kp-international`](https://github.com/mwood77/ws4kp-international)
## Run Your WeatherStar
There are a lot of CORS considerations and issues with api.weather.gov that are easiest to deal with by running a local server to see this in action (or use the live link above). You'll need Node.js >12.0 to run the local server.

2
dist/index.html vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "ws4kp",
"version": "5.14.0",
"version": "5.14.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ws4kp",
"version": "5.14.0",
"version": "5.14.3",
"license": "MIT",
"dependencies": {
"ejs": "^3.1.5",

View File

@@ -1,6 +1,6 @@
{
"name": "ws4kp",
"version": "5.14.0",
"version": "5.14.3",
"description": "Welcome to the WeatherStar 4000+ project page!",
"main": "index.js",
"scripts": {

View File

@@ -3,7 +3,7 @@ import { loadImg, preloadImg } from './utils/image.mjs';
import { DateTime } from '../vendor/auto/luxon.mjs';
import STATUS from './status.mjs';
import WeatherDisplay from './weatherdisplay.mjs';
import { registerDisplay } from './navigation.mjs';
import { registerDisplay, timeZone } from './navigation.mjs';
class Almanac extends WeatherDisplay {
constructor(navId, elemId) {
@@ -123,10 +123,10 @@ class Almanac extends WeatherDisplay {
// sun and moon data
this.elem.querySelector('.day-1').innerHTML = Today.toLocaleString({ weekday: 'long' });
this.elem.querySelector('.day-2').innerHTML = Tomorrow.toLocaleString({ weekday: 'long' });
this.elem.querySelector('.rise-1').innerHTML = DateTime.fromJSDate(info.sun[0].sunrise).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase();
this.elem.querySelector('.rise-2').innerHTML = DateTime.fromJSDate(info.sun[1].sunrise).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase();
this.elem.querySelector('.set-1').innerHTML = DateTime.fromJSDate(info.sun[0].sunset).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase();
this.elem.querySelector('.set-2').innerHTML = DateTime.fromJSDate(info.sun[1].sunset).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase();
this.elem.querySelector('.rise-1').innerHTML = DateTime.fromJSDate(info.sun[0].sunrise).setZone(timeZone()).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase();
this.elem.querySelector('.rise-2').innerHTML = DateTime.fromJSDate(info.sun[1].sunrise).setZone(timeZone()).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase();
this.elem.querySelector('.set-1').innerHTML = DateTime.fromJSDate(info.sun[0].sunset).setZone(timeZone()).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase();
this.elem.querySelector('.set-2').innerHTML = DateTime.fromJSDate(info.sun[1].sunset).setZone(timeZone()).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase();
const days = info.moon.map((MoonPhase) => {
const fill = {};

View File

@@ -3,7 +3,7 @@
import STATUS from './status.mjs';
import getHourlyData from './hourly.mjs';
import WeatherDisplay from './weatherdisplay.mjs';
import { registerDisplay } from './navigation.mjs';
import { registerDisplay, timeZone } from './navigation.mjs';
import { DateTime } from '../vendor/auto/luxon.mjs';
class HourlyGraph extends WeatherDisplay {
@@ -145,7 +145,7 @@ const drawPath = (path, ctx, options) => {
};
// format as 1p, 12a, etc.
const formatTime = (time) => time.toFormat('ha').slice(0, -1);
const formatTime = (time) => time.setZone(timeZone()).toFormat('ha').slice(0, -1);
// register display
registerDisplay(new HourlyGraph(4, 'hourly-graph'));

View File

@@ -7,7 +7,7 @@ import { temperature as temperatureUnit, distanceKilometers } from './utils/unit
import { getHourlyIcon } from './icons.mjs';
import { directionToNSEW } from './utils/calc.mjs';
import WeatherDisplay from './weatherdisplay.mjs';
import { registerDisplay } from './navigation.mjs';
import { registerDisplay, timeZone } from './navigation.mjs';
import getSun from './almanac.mjs';
class Hourly extends WeatherDisplay {
@@ -56,10 +56,7 @@ class Hourly extends WeatherDisplay {
const list = this.elem.querySelector('.hourly-lines');
list.innerHTML = '';
// get a unit converter
const temperatureConverter = temperatureUnit();
const startingHour = DateTime.local();
const startingHour = DateTime.local().setZone(timeZone());
const lines = this.data.map((data, index) => {
const fillValues = {};
@@ -69,8 +66,8 @@ class Hourly extends WeatherDisplay {
fillValues.hour = formattedHour;
// temperatures, convert to strings with no decimal
const temperature = temperatureConverter(data.temperature).toString().padStart(3);
const feelsLike = Math.round(data.apparentTemperature).toString().padStart(3);
const temperature = data.temperature.toString().padStart(3);
const feelsLike = data.apparentTemperature.toString().padStart(3);
fillValues.temp = temperature;
// only plot apparent temperature if there is a difference
// if (temperature !== feelsLike) line.querySelector('.like').innerHTML = feelsLike;

View File

@@ -1,16 +1,21 @@
import { getWeatherRegionalIconFromIconLink } from './icons.mjs';
import { preloadImg } from './utils/image.mjs';
import { json } from './utils/fetch.mjs';
import { temperature as temperatureUnit } from './utils/units.mjs';
const buildForecast = (forecast, city, cityXY) => ({
daytime: forecast.isDaytime,
temperature: forecast.temperature || 0,
name: formatCity(city.city),
icon: forecast.icon,
x: cityXY.x,
y: cityXY.y,
time: forecast.startTime,
});
const buildForecast = (forecast, city, cityXY) => {
// get a unit converter
const temperatureConverter = temperatureUnit('us');
return {
daytime: forecast.isDaytime,
temperature: temperatureConverter(forecast.temperature || 0),
name: formatCity(city.city),
icon: forecast.icon,
x: cityXY.x,
y: cityXY.y,
time: forecast.startTime,
};
};
const getRegionalObservation = async (point, city) => {
try {

View File

@@ -7,6 +7,7 @@ const round2 = (value, decimals) => Math.trunc(value * 10 ** decimals) / 10 ** d
const kphToMph = (Kph) => Math.round(Kph / 1.609_34);
const celsiusToFahrenheit = (Celsius) => Math.round((Celsius * 9) / 5 + 32);
const fahrenheitToCelsius = (Fahrenheit) => Math.round((Fahrenheit - 32) * 5 / 9);
const kilometersToMiles = (Kilometers) => Math.round(Kilometers / 1.609_34);
const metersToFeet = (Meters) => Math.round(Meters / 0.3048);
const pascalToInHg = (Pascal) => round2(Pascal * 0.000_295_3, 2);
@@ -35,7 +36,11 @@ const temperature = (defaultUnit = 'si') => {
let converter = (passthru) => Math.round(passthru);
// change the converter if there is a mismatch
if (defaultUnit !== settings.units.value) {
converter = celsiusToFahrenheit;
if (defaultUnit === 'us') {
converter = fahrenheitToCelsius;
} else {
converter = celsiusToFahrenheit;
}
}
// append units
if (settings.units.value === 'si') {