diff --git a/defaultmodules/weather/providers/weatherapi.js b/defaultmodules/weather/providers/weatherapi.js index 83b7399a64..a435b4a65e 100644 --- a/defaultmodules/weather/providers/weatherapi.js +++ b/defaultmodules/weather/providers/weatherapi.js @@ -203,6 +203,14 @@ class WeatherAPIProvider extends WeatherProvider { return Number.isFinite(number) ? number : null; } + #maxPrecipitationProbability (rainProbability, snowProbability) { + const probabilities = [rainProbability, snowProbability] + .map((probability) => this.#toNumber(probability)) + .filter((probability) => probability !== null); + + return probabilities.length > 0 ? Math.max(...probabilities) : null; + } + #generateCurrent (data) { const weather = data.forecast.forecastday[0] ?? {}; const current = data.current ?? {}; @@ -263,13 +271,10 @@ class WeatherAPIProvider extends WeatherProvider { ? new Date(forecastDay.date_epoch * 1000) : new Date(`${forecastDay.date}T00:00:00`); - const precipitationProbability = forecastDay.hour?.length > 0 - ? (forecastDay.hour.reduce((sum, hourData) => { - const rain = this.#toNumber(hourData.will_it_rain) ?? 0; - const snow = this.#toNumber(hourData.will_it_snow) ?? 0; - return sum + ((rain + snow) / 2); - }, 0) / forecastDay.hour.length) * 100 - : null; + const precipitationProbability = this.#maxPrecipitationProbability( + forecastDay.day?.daily_chance_of_rain, + forecastDay.day?.daily_chance_of_snow + ); const avgWindDegree = forecastDay.hour?.length > 0 ? forecastDay.hour.reduce((sum, hourData) => { @@ -366,9 +371,13 @@ class WeatherAPIProvider extends WeatherProvider { weather.temperature = this.#toNumber(hourData.temp_c); weather.precipitationAmount = this.#toNumber(hourData.precip_mm); - const willRain = this.#toNumber(hourData.will_it_rain) ?? 0; - const willSnow = this.#toNumber(hourData.will_it_snow) ?? 0; - weather.precipitationProbability = (willRain + willSnow) * 50; + const precipitationProbability = this.#maxPrecipitationProbability( + hourData.chance_of_rain, + hourData.chance_of_snow + ); + if (precipitationProbability !== null) { + weather.precipitationProbability = precipitationProbability; + } weather.uvIndex = this.#toNumber(hourData.uv); diff --git a/tests/mocks/weather_openmeteo_current.json b/tests/mocks/weather_openmeteo_current.json index 478ee1d161..a04a7337f2 100644 --- a/tests/mocks/weather_openmeteo_current.json +++ b/tests/mocks/weather_openmeteo_current.json @@ -205,7 +205,7 @@ 3.9, 4.9, 6.0, 7.3, 9.7, 14.1, 17.1, 16.9, 15.1, 14.0, 14.7, 16.4, 17.4, 18.0, 18.1, 17.6, 15.5, 12.9, 11.9, 13.2, 15.8, 18.2, 19.0, 19.2, 19.2, 19.5, 19.7, 19.7, 19.0, 18.0, 17.4, 17.4, 17.6, 17.9, 18.1 ] }, - "daily_units": { "time": "iso8601", "weather_code": "wmo code", "temperature_2m_max": "°C", "temperature_2m_min": "°C", "sunrise": "iso8601", "sunset": "iso8601", "precipitation_sum": "mm" }, + "daily_units": { "time": "iso8601", "weather_code": "wmo code", "temperature_2m_max": "°C", "temperature_2m_min": "°C", "sunrise": "iso8601", "sunset": "iso8601", "precipitation_sum": "mm", "precipitation_probability_max": "%" }, "daily": { "time": ["2026-02-06", "2026-02-07", "2026-02-08", "2026-02-09", "2026-02-10", "2026-02-11", "2026-02-12"], "weather_code": [3, 71, 3, 3, 3, 71, 3], @@ -213,6 +213,7 @@ "temperature_2m_min": [-9.2, -17.7, -21.5, -18.1, -11.0, -5.3, -5.3], "sunrise": ["2026-02-06T07:00", "2026-02-07T06:59", "2026-02-08T06:58", "2026-02-09T06:56", "2026-02-10T06:55", "2026-02-11T06:54", "2026-02-12T06:53"], "sunset": ["2026-02-06T17:19", "2026-02-07T17:20", "2026-02-08T17:21", "2026-02-09T17:23", "2026-02-10T17:24", "2026-02-11T17:25", "2026-02-12T17:26"], - "precipitation_sum": [0.0, 0.4, 0.0, 0.0, 0.0, 2.6, 0.0] + "precipitation_sum": [0.0, 0.4, 0.0, 0.0, 0.0, 2.6, 0.0], + "precipitation_probability_max": [25, 75, 0, 10, 0, 60, 0] } } diff --git a/tests/unit/modules/default/weather/providers/openmeteo_spec.js b/tests/unit/modules/default/weather/providers/openmeteo_spec.js index 225a970c88..9d6fbe84eb 100644 --- a/tests/unit/modules/default/weather/providers/openmeteo_spec.js +++ b/tests/unit/modules/default/weather/providers/openmeteo_spec.js @@ -111,6 +111,7 @@ describe("OpenMeteoProvider", () => { const params = url.searchParams; expect(params.get("forecast_days")).toBe("6"); // 5 days + 1 + expect(params.get("daily").split(",")).toContain("precipitation_probability_max"); expect(params.has("start_date")).toBe(false); expect(params.has("end_date")).toBe(false); }); @@ -220,6 +221,7 @@ describe("OpenMeteoProvider", () => { expect(firstDay.minTemperature).toBe(-9.2); expect(firstDay.maxTemperature).toBe(-0.2); expect(firstDay.temperature).toBeCloseTo(-4.7, 0); // (-0.2+-9.2)/2 + expect(firstDay.precipitationProbability).toBe(25); expect(firstDay.sunrise).toBeInstanceOf(Date); expect(firstDay.sunset).toBeInstanceOf(Date); diff --git a/tests/unit/modules/default/weather/providers/weatherapi_spec.js b/tests/unit/modules/default/weather/providers/weatherapi_spec.js index 5242d2f439..a121219b74 100644 --- a/tests/unit/modules/default/weather/providers/weatherapi_spec.js +++ b/tests/unit/modules/default/weather/providers/weatherapi_spec.js @@ -49,6 +49,8 @@ const buildWeatherApiResponse = () => { avghumidity: 81, totalsnow_cm: 0.6, totalprecip_mm: 2, + daily_chance_of_rain: 80, + daily_chance_of_snow: 20, maxwind_kph: 22, uv: 1, condition: { code: 1183 } @@ -68,6 +70,8 @@ const buildWeatherApiResponse = () => { precip_mm: 0.5, will_it_rain: 1, will_it_snow: 0, + chance_of_rain: 75, + chance_of_snow: 25, uv: 0 }, { @@ -84,6 +88,8 @@ const buildWeatherApiResponse = () => { precip_mm: 0.2, will_it_rain: 0, will_it_snow: 0, + chance_of_rain: 30, + chance_of_snow: 65, uv: 0 }, { @@ -100,6 +106,8 @@ const buildWeatherApiResponse = () => { precip_mm: 0, will_it_rain: 0, will_it_snow: 0, + chance_of_rain: 10, + chance_of_snow: 0, uv: 0 } ] @@ -118,6 +126,8 @@ const buildWeatherApiResponse = () => { avghumidity: 78, totalsnow_cm: 0, totalprecip_mm: 0.4, + daily_chance_of_rain: 35, + daily_chance_of_snow: 55, maxwind_kph: 20, uv: 2, condition: { code: 1006 } @@ -240,6 +250,8 @@ describe("WeatherAPIProvider", () => { expect(result[0].minTemperature).toBe(-8); expect(result[0].maxTemperature).toBe(-1); expect(result[0].weatherType).toBe("day-sprinkle"); + expect(result[0].precipitationProbability).toBe(80); + expect(result[1].precipitationProbability).toBe(55); expect(result[0].uvIndex).toBe(1); expect(result[0].sunrise).toBeInstanceOf(Date); expect(result[0].sunset).toBeInstanceOf(Date); @@ -277,7 +289,7 @@ describe("WeatherAPIProvider", () => { expect(result[0].windFromDirection).toBe(210); expect(result[0].weatherType).toBe("night-sprinkle"); expect(result[0].uvIndex).toBe(0); - expect(result[0].precipitationProbability).toBe(50); + expect(result[0].precipitationProbability).toBe(75); }); });