k-donn / plasmoid-wunderground

A Plasma 5/6 widget for showing data from Wunderground PWS
https://store.kde.org/p/2135799
GNU General Public License v2.0
39 stars 14 forks source link

Weather API access denied when getting forecast data #65

Open dniminenn opened 1 month ago

dniminenn commented 1 month ago

Describe the bug The "Forecast" stays loading forever and the top bar says "Loading..." indefinitely

To Reproduce The 7-day v1 endpoint was seemingly closed... /v3 5-day endpoint is still working.

Screenshots image image

Desktop (output of `plasmashell --version): plasmashell 6.1.3

Additional context Suggest switching to the new endpoint to resolve the issue. image

k-donn commented 1 month ago

I believe this issue is when there is a delay in the getCurrentData function in pws-api.js, the coordinates do not get set in time for the getForecastData function to fire. Then, the widget calls the v1 endpoint with no coordinates and the API doesn't return a helpful error message and the widget stays Loading....

From my tests, the v1 endpoint is still functioning (though I should migrate to v3). Upcoming changes will fix the timing issue by using callbacks instead of hack-ishly hoping the functions fire correctly.

Thanks for the input and using the widget!

dniminenn commented 1 month ago

Interesting, when I try hitting the v1 endpoint with cURL I am getting 403s Access Denied. This may be a regional thing as I am in Canada. I do have valid API keys as I have my own PWS but I tried using the baked-in ones as well to no avail. Interesting.

For now I have adapted to v3 using the following lazily put together code.

function getForecastData() {
    var req = new XMLHttpRequest();

    var lat = plasmoid.configuration.latitude;
    var lon = plasmoid.configuration.longitude;
    var url = "https://api.weather.com/v3/wx/forecast/daily/5day";
    console.log("lat: " + lat + " lon: " + lon);
    url += "?geocode=" + lat + "," + lon;
    url += "&format=json";
    url += "&units=" + (unitsChoice === UNITS_SYSTEM.METRIC ? "m" : "e");
    url += "&language=" + Qt.locale().name.replace("_", "-");
    url += "&apiKey=" + API_KEY;

    printDebug("[pws-api.js] " + url);

    req.open("GET", url);

    req.onreadystatechange = function () {
        if (req.readyState === 4) {
            if (req.status === 200) {
                forecastModel.clear();

                var res = JSON.parse(req.responseText);
                var dayPart = res.daypart[0];

                for (var i = 0; i < res.dayOfWeek.length; i++) {
                    var high = res.calendarDayTemperatureMax[i];
                    var low = res.calendarDayTemperatureMin[i];

                    var dayIndex = dayPart.dayOrNight[0] === null ? 2 * i + 1 : 2 * i;

                    // Ensure that the day part is "D" for day
                    if (dayPart.dayOrNight[dayIndex] === "D") {
                        var narrativeDay = dayPart.narrative[dayIndex] || "";
                        var iconCodeDay = iconThemeMap[dayPart.iconCode[dayIndex]] || "";

                        var date = new Date(res.validTimeLocal[i]).toLocaleDateString(Qt.locale().name, {
                            weekday: "short",
                            month: "short",
                            day: "numeric",
                        });

                        // Append day part
                        forecastModel.append({
                            date: date,
                            dayOfWeek: res.dayOfWeek[i],
                            iconCode: iconCodeDay,
                            high: high,
                            low: low,
                            feelsLike: dayPart.temperature[dayIndex],
                            shortDesc: dayPart.wxPhraseLong[dayIndex],
                            longDesc: narrativeDay,
                            thunderDesc: dayPart.thunderCategory[dayIndex] || "No thunder",
                            windDesc: dayPart.windPhrase[dayIndex],
                            uvDesc: dayPart.uvDescription[dayIndex],
                            snowDesc: dayPart.snowRange[dayIndex] || "No snow",
                            golfDesc: "Good day for golf",
                        });
                    }
                }

                currDayHigh = forecastModel.get(0).high;
                currDayLow = forecastModel.get(0).low;

                printDebug("[pws-api.js] Got new forecast data");
                showForecast = true;
            } else {
                var errorStr = "Could not fetch forecast data";
                printDebug("[pws-api.js] " + errorStr);
                appState = showERROR;
            }
        }
    };

    req.send();
}

Haven't handled the translations and I'm not convinced I did the icons correctly, but I'm getting my data so that's good enough for now :laughing:

Hope it helps you