joeldueckdotcom

File site/windfinger.js from the latest check-in


async function updateWeatherDiv() {
    const weatherDiv = document.getElementById('weather');
    weatherDiv.innerHTML = 'Getting weather…';
    try {
        const weather = await loadWeather();
        
        // The temperature → hue formula
        let tempHue = 210 - (weather.temp * 2);
        if(tempHue < 0) tempHue = 360 - tempHue;
        
        document.documentElement.style.setProperty('--base-temp', tempHue);
        weatherDiv.innerHTML = `Robbinsdale, MN: ${weather.temp}º F; ${weather.conditions}`;
    } catch (e) {
        weatherDiv.innerHTML = e.message;
    }
}

async function loadWeather() {
    let w = JSON.parse(localStorage.getItem('weather'));
    if(w === null || Date.now() - w.timestamp > 3600000) {
        w = await fetchWeather();
        localStorage.setItem('weather', JSON.stringify(w));
    }
    return w;
}

const delay = (retryCount) => new Promise((res) => setTimeout(res, 10 ** retryCount));

async function fetchWeather(retryCount = 0) {
    console.log('Updating weather data cache…');
    try {
        const response = await fetch('https://api.weather.gov/gridpoints/MPX/105,74/forecast/hourly?units=us');
        if(!response.ok) { throw Error(response.statusText); }
        
        const weatherJson = await response.json()
        const weather = weatherJson.properties.periods[0];
        return { 
            "timestamp" : Date.now(),
            "temp" : weather.temperature,
            "conditions" : weather.shortForecast };
    } catch (e) {
        console.log(`Attempt ${retryCount} failed: ${e.message}`);
        if(retryCount > 4) { throw e; }
        await delay(retryCount + 1);
        return fetchWeather(retryCount + 1);
    }
}

updateWeatherDiv();