ws4kp/server/scripts/modules/currentweather.js

214 lines
7.9 KiB
JavaScript
Raw Normal View History

2020-09-04 18:02:20 +00:00
// current weather conditions display
2022-08-03 02:39:27 +00:00
/* globals WeatherDisplay, utils, STATUS, icons, UNITS, navigation */
2020-09-04 18:02:20 +00:00
// eslint-disable-next-line no-unused-vars
class CurrentWeather extends WeatherDisplay {
2020-10-29 21:44:28 +00:00
constructor(navId, elemId) {
2022-08-03 02:39:27 +00:00
super(navId, elemId, 'Current Conditions', true, true);
2020-09-04 18:02:20 +00:00
// pre-load background image (returns promise)
this.backgroundImage = utils.image.load('images/BackGround1_1.png');
}
2020-10-29 21:44:28 +00:00
async getData(_weatherParameters) {
super.getData(_weatherParameters);
const weatherParameters = _weatherParameters ?? this.weatherParameters;
2020-09-25 14:55:29 +00:00
2020-09-04 18:02:20 +00:00
// Load the observations
2020-10-29 21:44:28 +00:00
let observations; let
station;
// station number counter
let stationNum = 0;
while (!observations && stationNum < weatherParameters.stations.length) {
// get the station
station = weatherParameters.stations[stationNum];
2020-10-29 21:44:28 +00:00
stationNum += 1;
try {
// station observations
2022-03-01 21:54:19 +00:00
// eslint-disable-next-line no-await-in-loop
2020-10-29 21:44:28 +00:00
observations = await utils.fetch.json(`${station.id}/observations`, {
cors: true,
data: {
limit: 2,
},
});
2020-09-04 18:02:20 +00:00
// test data quality
2020-10-29 21:44:28 +00:00
if (observations.features[0].properties.temperature.value === null
|| observations.features[0].properties.windSpeed.value === null
|| observations.features[0].properties.textDescription === null) {
observations = undefined;
throw new Error(`Unable to get observations: ${station.properties.stationIdentifier}, trying next station`);
}
} catch (e) {
console.error(e);
}
}
// test for data received
if (!observations) {
console.error('All current weather stations exhausted');
2020-09-09 19:29:03 +00:00
this.setStatus(STATUS.failed);
2020-09-04 18:02:20 +00:00
return;
}
2020-09-23 16:49:15 +00:00
// preload the icon
2020-09-23 19:10:25 +00:00
utils.image.preload(icons.getWeatherIconFromIconLink(observations.features[0].properties.icon));
2020-09-23 16:49:15 +00:00
2020-09-04 18:02:20 +00:00
// we only get here if there was no error above
2020-10-29 21:44:28 +00:00
this.data = { ...observations, station };
2020-09-17 21:34:38 +00:00
this.setStatus(STATUS.loaded);
2020-10-21 01:04:51 +00:00
this.getDataCallback();
2020-09-04 18:02:20 +00:00
}
2020-09-25 03:44:51 +00:00
// format the data for use outside this function
parseData() {
if (!this.data) return false;
const data = {};
2020-09-04 18:02:20 +00:00
const observations = this.data.features[0].properties;
// values from api are provided in metric
2020-09-25 03:44:51 +00:00
data.observations = observations;
data.Temperature = Math.round(observations.temperature.value);
2020-09-25 14:55:29 +00:00
data.TemperatureUnit = 'C';
2020-09-25 03:44:51 +00:00
data.DewPoint = Math.round(observations.dewpoint.value);
2022-07-29 21:12:42 +00:00
data.Ceiling = Math.round(observations.cloudLayers[0]?.base?.value ?? 0);
2020-09-25 03:44:51 +00:00
data.CeilingUnit = 'm.';
2020-10-29 21:44:28 +00:00
data.Visibility = Math.round(observations.visibility.value / 1000);
2020-09-25 03:44:51 +00:00
data.VisibilityUnit = ' km.';
data.WindSpeed = Math.round(observations.windSpeed.value);
data.WindDirection = utils.calc.directionToNSEW(observations.windDirection.value);
data.Pressure = Math.round(observations.barometricPressure.value);
data.HeatIndex = Math.round(observations.heatIndex.value);
data.WindChill = Math.round(observations.windChill.value);
data.WindGust = Math.round(observations.windGust.value);
2020-09-25 14:55:29 +00:00
data.WindUnit = 'KPH';
2020-09-25 03:44:51 +00:00
data.Humidity = Math.round(observations.relativeHumidity.value);
data.Icon = icons.getWeatherIconFromIconLink(observations.icon);
data.PressureDirection = '';
data.TextConditions = observations.textDescription;
data.station = this.data.station;
2020-09-04 18:02:20 +00:00
// difference since last measurement (pascals, looking for difference of more than 150)
const pressureDiff = (observations.barometricPressure.value - this.data.features[1].properties.barometricPressure.value);
2020-09-25 03:44:51 +00:00
if (pressureDiff > 150) data.PressureDirection = 'R';
if (pressureDiff < -150) data.PressureDirection = 'F';
2020-09-04 18:02:20 +00:00
if (navigation.units() === UNITS.english) {
2020-09-25 03:44:51 +00:00
data.Temperature = utils.units.celsiusToFahrenheit(data.Temperature);
2020-09-25 14:55:29 +00:00
data.TemperatureUnit = 'F';
2020-09-25 03:44:51 +00:00
data.DewPoint = utils.units.celsiusToFahrenheit(data.DewPoint);
2020-10-29 21:44:28 +00:00
data.Ceiling = Math.round(utils.units.metersToFeet(data.Ceiling) / 100) * 100;
2020-09-25 03:44:51 +00:00
data.CeilingUnit = 'ft.';
2020-10-29 21:44:28 +00:00
data.Visibility = utils.units.kilometersToMiles(observations.visibility.value / 1000);
2020-09-25 03:44:51 +00:00
data.VisibilityUnit = ' mi.';
data.WindSpeed = utils.units.kphToMph(data.WindSpeed);
2020-09-25 14:55:29 +00:00
data.WindUnit = 'MPH';
2020-09-25 21:36:43 +00:00
data.Pressure = utils.units.pascalToInHg(data.Pressure).toFixed(2);
2020-09-25 03:44:51 +00:00
data.HeatIndex = utils.units.celsiusToFahrenheit(data.HeatIndex);
data.WindChill = utils.units.celsiusToFahrenheit(data.WindChill);
data.WindGust = utils.units.kphToMph(data.WindGust);
2020-09-04 18:02:20 +00:00
}
2020-09-25 03:44:51 +00:00
return data;
}
2020-10-29 21:44:28 +00:00
async drawCanvas() {
2020-09-25 03:44:51 +00:00
super.drawCanvas();
2022-08-03 02:39:27 +00:00
const fill = {};
2020-09-25 03:44:51 +00:00
// parse each time to deal with a change in units if necessary
const data = this.parseData();
2020-09-04 18:02:20 +00:00
2022-08-03 02:39:27 +00:00
fill.temp = data.Temperature + String.fromCharCode(176);
2020-09-04 18:02:20 +00:00
2020-09-25 03:44:51 +00:00
let Conditions = data.observations.textDescription;
if (Conditions.length > 15) {
2020-09-04 18:02:20 +00:00
Conditions = this.shortConditions(Conditions);
}
2022-08-03 02:39:27 +00:00
fill.condition = Conditions;
fill.wind = data.WindDirection.padEnd(3, '') + data.WindSpeed.toString().padStart(3, ' ');
if (data.WindGust) fill['wind-gusts'] = `Gusts to ${data.WindGust}`;
fill.location = this.data.station.properties.name.substr(0, 20);
fill.humidity = `${data.Humidity}%`;
fill.dewpoint = data.DewPoint + String.fromCharCode(176);
fill.ceiling = (data.Ceiling === 0 ? 'Unlimited' : data.Ceiling + data.CeilingUnit);
fill.visibility = data.Visibility + data.VisibilityUnit;
fill.pressure = `${data.Pressure} ${data.PressureDirection}`;
2022-08-03 02:39:27 +00:00
// switch (data.PressureDirection) {
// case 'R':
// // Shadow
// draw.triangle(this.context, '#000000', 552, 302, 542, 312, 562, 312);
// draw.box(this.context, '#000000', 549, 312, 6, 15);
// // Border
// draw.triangle(this.context, '#000000', 550, 300, 540, 310, 560, 310);
// draw.box(this.context, '#000000', 547, 310, 6, 15);
// // Fill
// draw.triangle(this.context, '#FFFF00', 550, 301, 541, 309, 559, 309);
// draw.box(this.context, '#FFFF00', 548, 309, 4, 15);
// break;
// case 'F':
// // Shadow
// draw.triangle(this.context, '#000000', 552, 327, 542, 317, 562, 317);
// draw.box(this.context, '#000000', 549, 302, 6, 15);
// // Border
// draw.triangle(this.context, '#000000', 550, 325, 540, 315, 560, 315);
// draw.box(this.context, '#000000', 547, 300, 6, 15);
// // Fill
// draw.triangle(this.context, '#FFFF00', 550, 324, 541, 314, 559, 314);
// draw.box(this.context, '#FFFF00', 548, 301, 4, 15);
// break;
// default:
// }
2020-09-04 18:02:20 +00:00
2020-09-25 03:44:51 +00:00
if (data.observations.heatIndex.value && data.HeatIndex !== data.Temperature) {
2022-08-03 02:39:27 +00:00
fill['heat-index-label'] = 'Heat Index:';
fill['heat-index'] = data.HeatIndex + String.fromCharCode(176);
2020-09-25 03:44:51 +00:00
} else if (data.observations.windChill.value && data.WindChill !== '' && data.WindChill < data.Temperature) {
2022-08-03 02:39:27 +00:00
fill['heat-index-label'] = 'Wind Chill:';
fill['heat-index'] = data.WindChill + String.fromCharCode(176);
2020-09-04 18:02:20 +00:00
}
2020-09-04 18:38:58 +00:00
2022-08-03 02:39:27 +00:00
fill.icon = { type: 'img', src: data.Icon };
const area = this.elem.querySelector('.main');
area.innerHTML = '';
area.append(this.fillTemplate('weather', fill));
2020-09-04 18:38:58 +00:00
2020-09-04 18:02:20 +00:00
this.finishDraw();
}
2020-10-21 01:04:51 +00:00
// make data available outside this class
// promise allows for data to be requested before it is available
async getCurrentWeather() {
return new Promise((resolve) => {
if (this.data) resolve(this.parseData());
// data not available, put it into the data callback queue
this.getDataCallbacks.push(() => resolve(this.parseData()));
});
2020-09-25 03:44:51 +00:00
}
2020-10-29 21:44:28 +00:00
static shortConditions(_condition) {
let condition = _condition;
2020-09-04 18:02:20 +00:00
condition = condition.replace(/Light/g, 'L');
condition = condition.replace(/Heavy/g, 'H');
condition = condition.replace(/Partly/g, 'P');
condition = condition.replace(/Mostly/g, 'M');
condition = condition.replace(/Few/g, 'F');
condition = condition.replace(/Thunderstorm/g, 'T\'storm');
condition = condition.replace(/ in /g, '');
condition = condition.replace(/Vicinity/g, '');
condition = condition.replace(/ and /g, ' ');
condition = condition.replace(/Freezing Rain/g, 'Frz Rn');
condition = condition.replace(/Freezing/g, 'Frz');
condition = condition.replace(/Unknown Precip/g, '');
condition = condition.replace(/L Snow Fog/g, 'L Snw/Fog');
condition = condition.replace(/ with /g, '/');
return condition;
}
2020-10-29 21:44:28 +00:00
}