Skip to main content

Weather API from OpenMeteo.com

My Skynet2.net LCARS sites has a weather page that pulls basic information for the viewer. Here is the script I used to get the API working. You will note FontAwesome icons are indicated, this was to show the "weather image" of the current conditions.

My 25th Century LCARS Site (Picard) - Just because I love the color scheme
My 24th Century LCARS Site (TNG) - This "display" site is used on an old touchscreen computer in our common area

const CACHE_KEY = 'weatherData';
const CACHE_EXPIRATION = 15 * 60 * 1000; // 15 minutes in milliseconds

function updateLocation() {
  if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(position => {
          const latitude = position.coords.latitude;
          const longitude = position.coords.longitude;
          updateWeather(latitude, longitude);
      }, error => console.error(error));
  } else {
      console.error("Geolocation is not supported by this browser.");
  }
}

function getCardinalDirection(windDegrees) {
  const cardinalDirections = [{
          direction: "N",
          degrees: [348.75, 11.25]
      },
      {
          direction: "NE",
          degrees: [11.25, 33.75]
      },
      {
          direction: "E",
          degrees: [33.75, 56.25]
      },
      {
          direction: "SE",
          degrees: [56.25, 78.75]
      },
      {
          direction: "S",
          degrees: [78.75, 101.25]
      },
      {
          direction: "SW",
          degrees: [101.25, 123.75]
      },
      {
          direction: "W",
          degrees: [123.75, 146.25]
      },
      {
          direction: "NW",
          degrees: [146.25, 348.75]
      },
  ];
  for (const direction of cardinalDirections) {
      if (windDegrees >= direction.degrees[0] && windDegrees < direction.degrees[1]) {
          return direction.direction;
      }
  }
  return "N";
}

const isDayDescriptions = {
    "0": "NIGHT",
    "1": "DAY",
  };

const weatherCodeDescriptions = {
  "0": "CLEAR SKY",
  "1": "MOSTLY CLEAR",
  "2": "PARTLY CLOUDY",
  "3": "OVERCAST",
  "45": "FOG",
  "48": "RIME FOG",
  "51": "SLIGHT DRIZZLE",
  "53": "MODERATE DRIZZLE",
  "55": "HEAVY DRIZZLE",
  "61": "LIGHT RAIN",
  "63": "MODERATE RAIN",
  "65": "HEAVY RAIN",
  "66": "LIGHT FREEZING RAIN",
  "67": "HEAVY FREEZING RAIN",
  "71": "LIGHT SNOW",
  "73": "MODERATE SNOW",
  "75": "HEAVY SNOW",
  "77": "SNOW GRAINS",
  "80": "LIGHT SHOWERS",
  "81": "MODERATE SHOWERS",
  "82": "HEAVY SHOWERS",
  "85": "LIGHT SNOW SHOWERS",
  "86": "HEAVY SNOW SHOWERS",
  "95": "THUNDERSTORMS",
  "96": "THUNDERSTORMS W/ LIGHT HAIL",
  "99": "THUNDERSTORMS W/ HEAVY HAIL",
};

const weatherCodeIcons = {
    "0": {
        "DAY": "fa-solid fa-sun",
        "NIGHT": "fa-solid fa-moon",
    },
    "1": {
        "DAY": "fa-solid fa-sun",
        "NIGHT": "fa-solid fa-moon",
    },
    "2": {
        "DAY": "fa-solid fa-cloud-sun",
        "NIGHT": "fa-solid fa-cloud-moon",
    },
    "3": "fa-solid fa-cloud",
    "45": "fa-solid fa-smog",
    "48": "fa-solid fa-smog",
    "51": "fa-solid fa-cloud-rain",
    "53": "fa-solid fa-cloud-rain",
    "55": "fa-solid fa-cloud-rain",
    "61": "fa-solid fa-cloud-rain",
    "63": "fa-solid fa-cloud-rain",
    "65": "fa-solid fa-cloud-showers-heavy",
    "66": "fa-solid fa-cloud-rain",
    "67": "fa-solid fa-cloud-showers-heavy",
    "71": "fa-regular fa-snowflake",
    "73": "fa-solid fa-cloud-meatball",
    "75": "fa-solid fa-cloud-meatball",
    "77": "fa-regular fa-snowflake",
    "80": "fa-solid fa-cloud-rain",
    "81": "fa-solid fa-cloud-rain",
    "82": "fa-solid fa-cloud-showers-heavy",
    "85": "fa-solid fa-cloud-rain",
    "86": "fa-solid fa-cloud-showers-heavy",
    "95": "fa-solid fa-cloud-bolt",
    "96": "fa-solid fa-cloud-bolt",
    "99": "fa-solid fa-cloud-bolt",
};

function updateWeather(latitude, longitude) {
    const cachedData = JSON.parse(localStorage.getItem(CACHE_KEY));
    const currentTime = new Date().getTime();
  
    if (cachedData && currentTime - cachedData.timestamp < CACHE_EXPIRATION) {
      console.log('Using cached data');
      displayWeather(cachedData.data);
    } else {
      console.log('Fetching new data');
      const url = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,precipitation,rain,weather_code,cloud_cover,wind_speed_10m,wind_direction_10m,wind_gusts_10m&hourly=dew_point_2m,precipitation_probability&temperature_unit=fahrenheit&wind_speed_unit=mph&precipitation_unit=inch&timezone=auto&forecast_days=1`;
  
      fetch(url)
        .then(response => response.json())
        .then(data => {
          localStorage.setItem(CACHE_KEY, JSON.stringify({ timestamp: currentTime, data }));
          displayWeather(data);
        })
        .catch(error => console.error(error));
    }
  }
  
  function displayWeather(data) {
    const isDayCode = data.current.is_day;
    const isDayDescription = isDayDescriptions[isDayCode];
    const weatherCode = data.current.weather_code;
    const weatherCodeStr = weatherCode.toString();
    console.log("Weather Code String:", weatherCodeStr);
    console.log("Is Day Code:", isDayCode);
    const weatherDescription = weatherCodeDescriptions[weatherCodeStr];
    const dewpoint = data.hourly.dew_point_2m[0];
    const precipProbability = data.hourly.precipitation_probability[0];
    let weatherIconClass;
        if (typeof weatherCodeIcons[weatherCodeStr] === "object") {
            // If the value is an object, use the day or night key
            weatherIconClass = weatherCodeIcons[weatherCodeStr][isDayDescriptions[isDayCode]];
        } else {
            // If the value is a string, use that directly
            weatherIconClass = weatherCodeIcons[weatherCodeStr];
        }

    console.log("Weather Icon Class:", weatherIconClass);  // Debug log
  
    document.getElementById("lat").textContent = data.latitude;
    document.getElementById("lon").textContent = data.longitude;
    document.getElementById("timezone").textContent = data.timezone;
    document.getElementById("elevation").textContent = data.elevation;
    document.getElementById("time").textContent = data.current.time;
    document.getElementById("interval").textContent = data.current.interval;
    document.getElementById("current-temp").textContent = data.current.temperature_2m;
    document.getElementById("humidity").textContent = data.current.relative_humidity_2m;
    document.getElementById("dewpoint").textContent = dewpoint;
    document.getElementById("apparent-temp").textContent = data.current.apparent_temperature;
    document.getElementById("precipitation").textContent = data.current.precipitation;
    document.getElementById("precip-probability").textContent = precipProbability;
    document.getElementById("rain").textContent = data.current.rain;
    document.getElementById("wx-icon").innerHTML = ``;
    document.getElementById("wx-code").textContent = weatherDescription || "Unknown code";
    document.getElementById("isday").textContent = isDayDescription || "Unknown";
    document.getElementById("cloud").textContent = data.current.cloud_cover;
    document.getElementById("wind-speed").textContent = data.current.wind_speed_10m;
    document.getElementById("wind-direct").textContent = data.current.wind_direction_10m;
    document.getElementById("wind-gusts").textContent = data.current.wind_gusts_10m;
    
    const windDirection = getCardinalDirection(data.current.wind_direction_10m);
    document.getElementById("wind-direct").textContent = windDirection;
    
    fetch(`https://nominatim.openstreetmap.org/reverse?lat=${data.latitude}&lon=${data.longitude}&format=json`)
      .then(response => response.json())
      .then(data => {
          if (data.address) {
              const city = data.address.city || data.address.town || "";
              const state = data.address.state || "";
              const locationString = `${city}, ${state}`;
              document.getElementById("location").textContent = locationString;
          } else {
              console.error("Location not found");
          }
      })
      .catch(error => console.error(error));
  }

// Call the updateLocation function to start the process
updateLocation();
setInterval(updateLocation, CACHE_EXPIRATION);