1 """Support for Met.no weather service."""
3 from __future__
import annotations
5 from types
import MappingProxyType
6 from typing
import TYPE_CHECKING, Any
9 ATTR_FORECAST_CONDITION,
11 ATTR_WEATHER_CLOUD_COVERAGE,
12 ATTR_WEATHER_DEW_POINT,
13 ATTR_WEATHER_HUMIDITY,
14 ATTR_WEATHER_PRESSURE,
15 ATTR_WEATHER_TEMPERATURE,
16 ATTR_WEATHER_UV_INDEX,
17 ATTR_WEATHER_WIND_BEARING,
18 ATTR_WEATHER_WIND_GUST_SPEED,
19 ATTR_WEATHER_WIND_SPEED,
20 DOMAIN
as WEATHER_DOMAIN,
22 SingleCoordinatorWeatherEntity,
29 UnitOfPrecipitationDepth,
40 from .
import MetWeatherConfigEntry
42 ATTR_CONDITION_CLEAR_NIGHT,
50 from .coordinator
import MetDataUpdateCoordinator
52 DEFAULT_NAME =
"Met.no"
57 config_entry: MetWeatherConfigEntry,
58 async_add_entities: AddEntitiesCallback,
60 """Add a weather entity from a config_entry."""
61 coordinator = config_entry.runtime_data
62 entity_registry = er.async_get(hass)
65 is_metric = hass.config.units
is METRIC_SYSTEM
66 if config_entry.data.get(CONF_TRACK_HOME,
False):
67 name = hass.config.location_name
69 name = config_entry.data.get(CONF_NAME, DEFAULT_NAME)
71 assert isinstance(name, str)
73 entities = [
MetWeather(coordinator, config_entry, name, is_metric)]
76 if hourly_entity_id := entity_registry.async_get_entity_id(
81 entity_registry.async_remove(hourly_entity_id)
87 """Calculate unique ID."""
90 name_appendix =
"-hourly"
91 if config.get(CONF_TRACK_HOME):
92 return f
"home{name_appendix}"
94 return f
"{config[CONF_LATITUDE]}-{config[CONF_LONGITUDE]}{name_appendix}"
98 """Return condition from dict CONDITIONS_MAP."""
99 for key, value
in CONDITIONS_MAP.items():
100 if condition
in value:
106 """Implementation of a Met.no weather condition."""
108 _attr_attribution = (
109 "Weather forecast from met.no, delivered by the Norwegian "
110 "Meteorological Institute."
112 _attr_has_entity_name =
True
113 _attr_native_temperature_unit = UnitOfTemperature.CELSIUS
114 _attr_native_precipitation_unit = UnitOfPrecipitationDepth.MILLIMETERS
115 _attr_native_pressure_unit = UnitOfPressure.HPA
116 _attr_native_wind_speed_unit = UnitOfSpeed.KILOMETERS_PER_HOUR
117 _attr_supported_features = (
118 WeatherEntityFeature.FORECAST_DAILY | WeatherEntityFeature.FORECAST_HOURLY
123 coordinator: MetDataUpdateCoordinator,
124 config_entry: MetWeatherConfigEntry,
128 """Initialise the platform with a data instance and site."""
135 entry_type=DeviceEntryType.SERVICE,
136 identifiers={(DOMAIN, config_entry.entry_id)},
137 manufacturer=
"Met.no",
139 configuration_url=
"https://www.met.no/en",
146 """Return the current condition."""
147 condition = self.coordinator.data.current_weather_data.get(
"condition")
148 if condition
is None:
151 if condition == ATTR_CONDITION_SUNNY
and not sun.is_up(self.
hasshasshasshass):
152 condition = ATTR_CONDITION_CLEAR_NIGHT
158 """Return the temperature."""
159 return self.coordinator.data.current_weather_data.get(
160 ATTR_MAP[ATTR_WEATHER_TEMPERATURE]
165 """Return the pressure."""
166 return self.coordinator.data.current_weather_data.get(
167 ATTR_MAP[ATTR_WEATHER_PRESSURE]
172 """Return the humidity."""
173 return self.coordinator.data.current_weather_data.get(
174 ATTR_MAP[ATTR_WEATHER_HUMIDITY]
179 """Return the wind speed."""
180 return self.coordinator.data.current_weather_data.get(
181 ATTR_MAP[ATTR_WEATHER_WIND_SPEED]
186 """Return the wind direction."""
187 return self.coordinator.data.current_weather_data.get(
188 ATTR_MAP[ATTR_WEATHER_WIND_BEARING]
193 """Return the wind gust speed in native units."""
194 return self.coordinator.data.current_weather_data.get(
195 ATTR_MAP[ATTR_WEATHER_WIND_GUST_SPEED]
200 """Return the cloud coverage."""
201 return self.coordinator.data.current_weather_data.get(
202 ATTR_MAP[ATTR_WEATHER_CLOUD_COVERAGE]
207 """Return the dew point."""
208 return self.coordinator.data.current_weather_data.get(
209 ATTR_MAP[ATTR_WEATHER_DEW_POINT]
214 """Return the uv index."""
215 return self.coordinator.data.current_weather_data.get(
216 ATTR_MAP[ATTR_WEATHER_UV_INDEX]
219 def _forecast(self, hourly: bool) -> list[Forecast] |
None:
220 """Return the forecast array."""
222 met_forecast = self.coordinator.data.hourly_forecast
224 met_forecast = self.coordinator.data.daily_forecast
225 required_keys = {
"temperature", ATTR_FORECAST_TIME}
226 ha_forecast: list[Forecast] = []
227 for met_item
in met_forecast:
228 if not set(met_item).issuperset(required_keys):
232 for k, v
in FORECAST_MAP.items()
233 if met_item.get(v)
is not None
235 if ha_item.get(ATTR_FORECAST_CONDITION):
237 ha_item[ATTR_FORECAST_CONDITION]
239 ha_forecast.append(ha_item)
244 """Return the daily forecast in native units."""
249 """Return the hourly forecast in native units."""
float|None native_wind_gust_speed(self)
float|None native_dew_point(self)
float|None native_temperature(self)
float|None native_pressure(self)
float|str|None wind_bearing(self)
float|None uv_index(self)
list[Forecast]|None _async_forecast_daily(self)
None __init__(self, MetDataUpdateCoordinator coordinator, MetWeatherConfigEntry config_entry, str name, bool is_metric)
float|None humidity(self)
list[Forecast]|None _forecast(self, bool hourly)
list[Forecast]|None _async_forecast_hourly(self)
float|None cloud_coverage(self)
float|None native_wind_speed(self)
web.Response get(self, web.Request request, str config_key)
str format_condition(str condition)
None async_setup_entry(HomeAssistant hass, MetWeatherConfigEntry config_entry, AddEntitiesCallback async_add_entities)
str _calculate_unique_id(MappingProxyType[str, Any] config, bool hourly)