Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion homeassistant/components/nws/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"iot_class": "cloud_polling",
"loggers": ["metar", "pynws"],
"quality_scale": "platinum",
"requirements": ["pynws==1.4.1"]
"requirements": ["pynws==1.5.0"]
}
39 changes: 24 additions & 15 deletions homeassistant/components/nws/weather.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
ATTR_CONDITION_CLEAR_NIGHT,
ATTR_CONDITION_SUNNY,
ATTR_FORECAST_CONDITION,
ATTR_FORECAST_HUMIDITY,
ATTR_FORECAST_NATIVE_DEW_POINT,
ATTR_FORECAST_NATIVE_TEMP,
ATTR_FORECAST_NATIVE_WIND_SPEED,
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
Expand Down Expand Up @@ -52,16 +54,13 @@
PARALLEL_UPDATES = 0


def convert_condition(
time: str, weather: tuple[tuple[str, int | None], ...]
) -> tuple[str, int | None]:
def convert_condition(time: str, weather: tuple[tuple[str, int | None], ...]) -> str:
"""Convert NWS codes to HA condition.

Choose first condition in CONDITION_CLASSES that exists in weather code.
If no match is found, return first condition from NWS
"""
conditions: list[str] = [w[0] for w in weather]
prec_probs = [w[1] or 0 for w in weather]

# Choose condition with highest priority.
cond = next(
Expand All @@ -75,10 +74,10 @@ def convert_condition(

if cond == "clear":
if time == "day":
return ATTR_CONDITION_SUNNY, max(prec_probs)
return ATTR_CONDITION_SUNNY
if time == "night":
return ATTR_CONDITION_CLEAR_NIGHT, max(prec_probs)
return cond, max(prec_probs)
return ATTR_CONDITION_CLEAR_NIGHT
Comment thread
lymanepp marked this conversation as resolved.
return cond


async def async_setup_entry(
Expand Down Expand Up @@ -219,8 +218,7 @@ def condition(self) -> str | None:
time = self.observation.get("iconTime")

if weather:
cond, _ = convert_condition(time, weather)
return cond
return convert_condition(time, weather)
return None

@property
Expand Down Expand Up @@ -256,16 +254,27 @@ def forecast(self) -> list[Forecast] | None:
else:
data[ATTR_FORECAST_NATIVE_TEMP] = None

data[ATTR_FORECAST_PRECIPITATION_PROBABILITY] = forecast_entry.get(
"probabilityOfPrecipitation"
)

if (dewp := forecast_entry.get("dewpoint")) is not None:
data[ATTR_FORECAST_NATIVE_DEW_POINT] = TemperatureConverter.convert(
dewp, UnitOfTemperature.FAHRENHEIT, UnitOfTemperature.CELSIUS
)
else:
data[ATTR_FORECAST_NATIVE_DEW_POINT] = None

data[ATTR_FORECAST_HUMIDITY] = forecast_entry.get("relativeHumidity")

if self.mode == DAYNIGHT:
data[ATTR_FORECAST_DAYTIME] = forecast_entry.get("isDaytime")

time = forecast_entry.get("iconTime")
weather = forecast_entry.get("iconWeather")
if time and weather:
cond, precip = convert_condition(time, weather)
else:
cond, precip = None, None
data[ATTR_FORECAST_CONDITION] = cond
data[ATTR_FORECAST_PRECIPITATION_PROBABILITY] = precip
data[ATTR_FORECAST_CONDITION] = (
convert_condition(time, weather) if time and weather else None
)

data[ATTR_FORECAST_WIND_BEARING] = forecast_entry.get("windBearing")
wind_speed = forecast_entry.get("windSpeedAvg")
Expand Down
2 changes: 1 addition & 1 deletion requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1861,7 +1861,7 @@ pynuki==1.6.2
pynut2==2.1.2

# homeassistant.components.nws
pynws==1.4.1
pynws==1.5.0

# homeassistant.components.nx584
pynx584==0.5
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1377,7 +1377,7 @@ pynuki==1.6.2
pynut2==2.1.2

# homeassistant.components.nws
pynws==1.4.1
pynws==1.5.0

# homeassistant.components.nx584
pynx584==0.5
Expand Down
21 changes: 19 additions & 2 deletions tests/components/nws/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from homeassistant.components.weather import (
ATTR_CONDITION_LIGHTNING_RAINY,
ATTR_FORECAST_CONDITION,
ATTR_FORECAST_DEW_POINT,
ATTR_FORECAST_HUMIDITY,
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
ATTR_FORECAST_TEMP,
ATTR_FORECAST_TIME,
Expand Down Expand Up @@ -59,6 +61,9 @@
"windGust": 20,
}

CLEAR_NIGHT_OBSERVATION = DEFAULT_OBSERVATION.copy()
CLEAR_NIGHT_OBSERVATION["iconTime"] = "night"

SENSOR_EXPECTED_OBSERVATION_METRIC = {
"dewpoint": "5",
"temperature": "10",
Expand Down Expand Up @@ -183,6 +188,9 @@
"timestamp": "2019-08-12T23:53:00+00:00",
"iconTime": "night",
"iconWeather": (("lightning-rainy", 40), ("lightning-rainy", 90)),
"probabilityOfPrecipitation": 89,
"dewpoint": 4,
"relativeHumidity": 75,
},
]

Expand All @@ -192,7 +200,9 @@
ATTR_FORECAST_TEMP: 10,
ATTR_FORECAST_WIND_SPEED: 10,
ATTR_FORECAST_WIND_BEARING: 180,
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 90,
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 89,
ATTR_FORECAST_DEW_POINT: 4,
ATTR_FORECAST_HUMIDITY: 75,
}

EXPECTED_FORECAST_METRIC = {
Expand All @@ -211,7 +221,14 @@
2,
),
ATTR_FORECAST_WIND_BEARING: 180,
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 90,
ATTR_FORECAST_PRECIPITATION_PROBABILITY: 89,
ATTR_FORECAST_DEW_POINT: round(
TemperatureConverter.convert(
4, UnitOfTemperature.FAHRENHEIT, UnitOfTemperature.CELSIUS
),
1,
),
ATTR_FORECAST_HUMIDITY: 75,
}

NONE_FORECAST = [{key: None for key in DEFAULT_FORECAST[0]}]
19 changes: 19 additions & 0 deletions tests/components/nws/test_weather.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from homeassistant.components import nws
from homeassistant.components.weather import (
ATTR_CONDITION_CLEAR_NIGHT,
ATTR_CONDITION_SUNNY,
ATTR_FORECAST,
DOMAIN as WEATHER_DOMAIN,
Expand All @@ -19,6 +20,7 @@
from homeassistant.util.unit_system import METRIC_SYSTEM, US_CUSTOMARY_SYSTEM

from .const import (
CLEAR_NIGHT_OBSERVATION,
EXPECTED_FORECAST_IMPERIAL,
EXPECTED_FORECAST_METRIC,
NONE_FORECAST,
Expand Down Expand Up @@ -97,6 +99,23 @@ async def test_imperial_metric(
assert forecast[0].get(key) == value


async def test_night_clear(hass: HomeAssistant, mock_simple_nws, no_sensor) -> None:
"""Test with clear-night in observation."""
instance = mock_simple_nws.return_value
instance.observation = CLEAR_NIGHT_OBSERVATION

entry = MockConfigEntry(
domain=nws.DOMAIN,
data=NWS_CONFIG,
)
entry.add_to_hass(hass)
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()

state = hass.states.get("weather.abc_daynight")
assert state.state == ATTR_CONDITION_CLEAR_NIGHT


async def test_none_values(hass: HomeAssistant, mock_simple_nws, no_sensor) -> None:
"""Test with none values in observation and forecast dicts."""
instance = mock_simple_nws.return_value
Expand Down