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
10 changes: 8 additions & 2 deletions homeassistant/components/smhi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
)
from homeassistant.core import HomeAssistant

from .coordinator import SMHIConfigEntry, SMHIDataUpdateCoordinator
from .coordinator import (
SMHIConfigEntry,
SMHIDataUpdateCoordinator,
SMHIFireDataUpdateCoordinator,
)

PLATFORMS = [Platform.SENSOR, Platform.WEATHER]

Expand All @@ -24,7 +28,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: SMHIConfigEntry) -> bool

coordinator = SMHIDataUpdateCoordinator(hass, entry)
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator
fire_coordinator = SMHIFireDataUpdateCoordinator(hass, entry)
await fire_coordinator.async_config_entry_first_refresh()
entry.runtime_data = (coordinator, fire_coordinator)

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
Expand Down
67 changes: 65 additions & 2 deletions homeassistant/components/smhi/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@
import asyncio
from dataclasses import dataclass

from pysmhi import SMHIForecast, SmhiForecastException, SMHIPointForecast
from pysmhi import (
SMHIFireForecast,
SmhiFireForecastException,
SMHIFirePointForecast,
SMHIForecast,
SmhiForecastException,
SMHIPointForecast,
)

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_LATITUDE, CONF_LOCATION, CONF_LONGITUDE
Expand All @@ -15,7 +22,9 @@

from .const import DEFAULT_SCAN_INTERVAL, DOMAIN, LOGGER, TIMEOUT

type SMHIConfigEntry = ConfigEntry[SMHIDataUpdateCoordinator]
type SMHIConfigEntry = ConfigEntry[
tuple[SMHIDataUpdateCoordinator, SMHIFireDataUpdateCoordinator]
]


@dataclass
Expand All @@ -27,6 +36,14 @@ class SMHIForecastData:
twice_daily: list[SMHIForecast]


@dataclass
class SMHIFireForecastData:
"""Dataclass for SMHI fire data."""

fire_daily: list[SMHIFireForecast]
fire_hourly: list[SMHIFireForecast]


class SMHIDataUpdateCoordinator(DataUpdateCoordinator[SMHIForecastData]):
"""A SMHI Data Update Coordinator."""

Expand Down Expand Up @@ -71,3 +88,49 @@ async def _async_update_data(self) -> SMHIForecastData:
def current(self) -> SMHIForecast:
"""Return the current metrics."""
return self.data.daily[0]


class SMHIFireDataUpdateCoordinator(DataUpdateCoordinator[SMHIFireForecastData]):
"""A SMHI Fire Data Update Coordinator."""

config_entry: SMHIConfigEntry

def __init__(self, hass: HomeAssistant, config_entry: SMHIConfigEntry) -> None:
"""Initialize the SMHI coordinator."""
super().__init__(
hass,
LOGGER,
config_entry=config_entry,
name=DOMAIN,
update_interval=DEFAULT_SCAN_INTERVAL,
)
self._smhi_fire_api = SMHIFirePointForecast(
config_entry.data[CONF_LOCATION][CONF_LONGITUDE],
config_entry.data[CONF_LOCATION][CONF_LATITUDE],
session=aiohttp_client.async_get_clientsession(hass),
)

async def _async_update_data(self) -> SMHIFireForecastData:
"""Fetch data from SMHI."""
try:
async with asyncio.timeout(TIMEOUT):
_forecast_fire_daily = (
await self._smhi_fire_api.async_get_daily_forecast()
)
_forecast_fire_hourly = (
await self._smhi_fire_api.async_get_hourly_forecast()
)
except SmhiFireForecastException as ex:
raise UpdateFailed(
"Failed to retrieve the forecast from the SMHI API"
) from ex

return SMHIFireForecastData(
fire_daily=_forecast_fire_daily,
fire_hourly=_forecast_fire_hourly,
)

@property
def fire_current(self) -> SMHIFireForecast:
"""Return the current fire metrics."""
return self.data.fire_daily[0]
51 changes: 44 additions & 7 deletions homeassistant/components/smhi/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@

from homeassistant.core import callback
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from .const import DOMAIN
from .coordinator import SMHIDataUpdateCoordinator
from .coordinator import SMHIDataUpdateCoordinator, SMHIFireDataUpdateCoordinator


class SmhiWeatherBaseEntity(CoordinatorEntity[SMHIDataUpdateCoordinator]):
class SmhiWeatherBaseEntity(Entity):
"""Representation of a base weather entity."""

_attr_attribution = "Swedish weather institute (SMHI)"
Expand All @@ -22,10 +23,8 @@ def __init__(
self,
latitude: str,
longitude: str,
coordinator: SMHIDataUpdateCoordinator,
) -> None:
"""Initialize the SMHI base weather entity."""
super().__init__(coordinator)
self._attr_unique_id = f"{latitude}, {longitude}"
self._attr_device_info = DeviceInfo(
entry_type=DeviceEntryType.SERVICE,
Expand All @@ -36,12 +35,50 @@ def __init__(
)
self.update_entity_data()

@abstractmethod
def update_entity_data(self) -> None:
"""Refresh the entity data."""


class SmhiWeatherEntity(
CoordinatorEntity[SMHIDataUpdateCoordinator], SmhiWeatherBaseEntity
):
"""Representation of a weather entity."""

def __init__(
self,
latitude: str,
longitude: str,
coordinator: SMHIDataUpdateCoordinator,
) -> None:
"""Initialize the SMHI base weather entity."""
super().__init__(coordinator)
SmhiWeatherBaseEntity.__init__(self, latitude, longitude)

@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self.update_entity_data()
super()._handle_coordinator_update()

@abstractmethod
def update_entity_data(self) -> None:
"""Refresh the entity data."""

class SmhiFireEntity(
CoordinatorEntity[SMHIFireDataUpdateCoordinator], SmhiWeatherBaseEntity
):
"""Representation of a weather entity."""

def __init__(
self,
latitude: str,
longitude: str,
coordinator: SMHIFireDataUpdateCoordinator,
) -> None:
"""Initialize the SMHI base weather entity."""
super().__init__(coordinator)
SmhiWeatherBaseEntity.__init__(self, latitude, longitude)

@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self.update_entity_data()
super()._handle_coordinator_update()
33 changes: 33 additions & 0 deletions homeassistant/components/smhi/icons.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,42 @@
{
"entity": {
"sensor": {
"build_up_index": {
"default": "mdi:grass"
},
"drought_code": {
"default": "mdi:grass"
},
"duff_moisture_code": {
"default": "mdi:grass"
},
"fine_fuel_moisture_code": {
"default": "mdi:grass"
},
"fire_weather_index": {
"default": "mdi:pine-tree-fire"
},
"forestdry": {
"default": "mdi:forest"
},
"frozen_precipitation": {
"default": "mdi:weather-snowy-rainy"
},
"fwi": {
"default": "mdi:pine-tree-fire"
},
"fwiindex": {
"default": "mdi:pine-tree-fire"
},
"grassfire": {
"default": "mdi:fire-circle"
},
"high_cloud": {
"default": "mdi:cloud-arrow-up"
},
"initial_spread_index": {
"default": "mdi:grass"
},
"low_cloud": {
"default": "mdi:cloud-arrow-down"
},
Expand All @@ -16,6 +46,9 @@
"precipitation_category": {
"default": "mdi:weather-pouring"
},
"rate_of_spread": {
"default": "mdi:grass"
},
"thunder": {
"default": "mdi:weather-lightning"
},
Expand Down
Loading
Loading