fix: use Open-Meteo instead of wttr.in (wttr.in response gets truncated in container)
All checks were successful
Deploy to Coolify / deploy (push) Successful in 4s
All checks were successful
Deploy to Coolify / deploy (push) Successful in 4s
This commit is contained in:
@@ -1,63 +1,84 @@
|
|||||||
export const dynamic = 'force-dynamic';
|
export const dynamic = 'force-dynamic';
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
function getWeatherCode(desc: string): string {
|
// Convert WMO weather codes to wttr.in-compatible codes for emoji mapping
|
||||||
const d = desc.toLowerCase();
|
function wmoToWttrCode(wmo: number): string {
|
||||||
if (d.includes("overcast")) return "122";
|
if (wmo === 0) return "113"; // Clear sunny
|
||||||
if (d.includes("partly cloudy") || d.includes("partly") ) return "116";
|
if (wmo === 1) return "116"; // Mainly clear
|
||||||
if (d.includes("cloudy") || d.includes("cloud")) return "119";
|
if (wmo === 2) return "116"; // Partly cloudy
|
||||||
if (d.includes("drizzle")) return "185";
|
if (wmo === 3) return "122"; // Overcast
|
||||||
if (d.includes("rain") || d.includes("shower")) return "305";
|
if (wmo >= 45 && wmo <= 48) return "143"; // Fog
|
||||||
if (d.includes("snow") || d.includes("blizzard")) return "230";
|
if (wmo >= 51 && wmo <= 55) return "185"; // Drizzle
|
||||||
if (d.includes("thunder") || d.includes("storm")) return "200";
|
if (wmo >= 56 && wmo <= 57) return "281"; // Freezing drizzle
|
||||||
if (d.includes("fog") || d.includes("mist")) return "248";
|
if (wmo >= 61 && wmo <= 65) return "305"; // Rain
|
||||||
if (d.includes("sunny") || d.includes("clear")) return "113";
|
if (wmo >= 66 && wmo <= 67) return "281"; // Freezing rain
|
||||||
|
if (wmo >= 71 && wmo <= 77) return "227"; // Snow
|
||||||
|
if (wmo >= 80 && wmo <= 82) return "305"; // Rain showers
|
||||||
|
if (wmo >= 85 && wmo <= 86) return "260"; // Snow showers
|
||||||
|
if (wmo === 95) return "200"; // Thunderstorm
|
||||||
|
if (wmo >= 96 && wmo <= 99) return "389"; // Thunderstorm with hail
|
||||||
return "116";
|
return "116";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function wmoToDesc(wmo: number): string {
|
||||||
|
if (wmo === 0) return "Ясно";
|
||||||
|
if (wmo === 1) return "Преим. ясно";
|
||||||
|
if (wmo === 2) return "Переменная облачность";
|
||||||
|
if (wmo === 3) return "Пасмурно";
|
||||||
|
if (wmo === 45 || wmo === 48) return "Туман";
|
||||||
|
if (wmo >= 51 && wmo <= 55) return "Морось";
|
||||||
|
if (wmo >= 61 && wmo <= 65) return "Дождь";
|
||||||
|
if (wmo >= 71 && wmo <= 77) return "Снег";
|
||||||
|
if (wmo >= 80 && wmo <= 82) return "Ливень";
|
||||||
|
if (wmo >= 85 && wmo <= 86) return "Снегопад";
|
||||||
|
if (wmo === 95) return "Гроза";
|
||||||
|
if (wmo >= 96 && wmo <= 99) return "Гроза с градом";
|
||||||
|
return "Облачно";
|
||||||
|
}
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
try {
|
try {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const timeout = setTimeout(() => controller.abort(), 8000);
|
const timeout = setTimeout(() => controller.abort(), 8000);
|
||||||
|
|
||||||
const res = await fetch(
|
const url = "https://api.open-meteo.com/v1/forecast?" + new URLSearchParams({
|
||||||
"https://wttr.in/Saint+Petersburg?format=j1",
|
latitude: "59.9343",
|
||||||
{
|
longitude: "30.3351",
|
||||||
signal: controller.signal,
|
current: "temperature_2m,relative_humidity_2m,apparent_temperature,weather_code,wind_speed_10m",
|
||||||
cache: "no-store",
|
daily: "weather_code,temperature_2m_max,temperature_2m_min",
|
||||||
headers: {
|
timezone: "Europe/Moscow",
|
||||||
"User-Agent": "SmartHomeDashboard/1.0",
|
forecast_days: "3",
|
||||||
"Accept": "application/json",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
clearTimeout(timeout);
|
|
||||||
|
|
||||||
if (!res.ok) throw new Error(`wttr responded ${res.status}`);
|
|
||||||
const data = await res.json();
|
|
||||||
|
|
||||||
const current = data.current_condition[0];
|
|
||||||
const days = (data.weather || []).slice(0, 3).map((day: any) => {
|
|
||||||
const hourly = day.hourly?.[4] || day.hourly?.[0] || {};
|
|
||||||
const desc = hourly.weatherDesc?.[0]?.value || "";
|
|
||||||
const code = hourly.weatherCode || getWeatherCode(desc);
|
|
||||||
return {
|
|
||||||
date: day.date,
|
|
||||||
maxTemp: day.maxtempC,
|
|
||||||
minTemp: day.mintempC,
|
|
||||||
desc,
|
|
||||||
weatherCode: String(code),
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const res = await fetch(url, {
|
||||||
|
signal: controller.signal,
|
||||||
|
cache: "no-store",
|
||||||
|
headers: { "Accept": "application/json" },
|
||||||
|
});
|
||||||
|
clearTimeout(timeout);
|
||||||
|
|
||||||
|
if (!res.ok) throw new Error(`Open-Meteo responded ${res.status}`);
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
const current = data.current;
|
||||||
|
const daily = data.daily;
|
||||||
|
|
||||||
|
const forecast = (daily.time || []).slice(0, 3).map((date: string, i: number) => ({
|
||||||
|
date,
|
||||||
|
maxTemp: String(Math.round(daily.temperature_2m_max[i])),
|
||||||
|
minTemp: String(Math.round(daily.temperature_2m_min[i])),
|
||||||
|
desc: wmoToDesc(daily.weather_code[i]),
|
||||||
|
weatherCode: wmoToWttrCode(daily.weather_code[i]),
|
||||||
|
}));
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
temp: current.temp_C,
|
temp: String(Math.round(current.temperature_2m)),
|
||||||
feelsLike: current.FeelsLikeC,
|
feelsLike: String(Math.round(current.apparent_temperature)),
|
||||||
humidity: current.humidity,
|
humidity: String(current.relative_humidity_2m),
|
||||||
desc: current.weatherDesc[0]?.value || "",
|
desc: wmoToDesc(current.weather_code),
|
||||||
weatherCode: String(current.weatherCode),
|
weatherCode: wmoToWttrCode(current.weather_code),
|
||||||
windSpeed: current.windspeedKmph,
|
windSpeed: String(Math.round(current.wind_speed_10m)),
|
||||||
forecast: days,
|
forecast,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Weather fetch error:", e);
|
console.error("Weather fetch error:", e);
|
||||||
|
|||||||
Reference in New Issue
Block a user