Add sensor platform to SMHI

This commit is contained in:
G Johansson 2025-02-25 21:15:03 +00:00
parent 75533463f7
commit 720c0c4936
7 changed files with 208 additions and 3 deletions

View File

@ -11,7 +11,7 @@ from homeassistant.core import HomeAssistant
from .coordinator import SMHIConfigEntry, SMHIDataUpdateCoordinator
PLATFORMS = [Platform.WEATHER]
PLATFORMS = [Platform.SENSOR, Platform.WEATHER]
async def async_setup_entry(hass: HomeAssistant, entry: SMHIConfigEntry) -> bool:

View File

@ -61,3 +61,8 @@ class SMHIDataUpdateCoordinator(DataUpdateCoordinator[SMHIForecastData]):
daily=_forecast_daily,
hourly=_forecast_hourly,
)
@property
def current(self) -> SMHIForecast:
"""Return the current metrics."""
return self.data.daily[0]

View File

@ -16,7 +16,6 @@ class SmhiWeatherBaseEntity(CoordinatorEntity[SMHIDataUpdateCoordinator]):
_attr_attribution = "Swedish weather institute (SMHI)"
_attr_has_entity_name = True
_attr_name = None
def __init__(
self,
@ -26,7 +25,7 @@ class SmhiWeatherBaseEntity(CoordinatorEntity[SMHIDataUpdateCoordinator]):
) -> None:
"""Initialize the SMHI base weather entity."""
super().__init__(coordinator)
self._attr_unique_id = f"{latitude}, {longitude}"
self._attr_unique_id: str = f"{latitude}, {longitude}"
self._attr_device_info = DeviceInfo(
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, f"{latitude}, {longitude}")},

View File

@ -0,0 +1,27 @@
{
"entity": {
"sensor": {
"thunder": {
"default": "mdi:lightning-bolt"
},
"total_cloud": {
"default": "mdi:cloud"
},
"low_cloud": {
"default": "mdi:cloud-arrow-down"
},
"medium_cloud": {
"default": "mdi:cloud-arrow-right"
},
"high_cloud": {
"default": "mdi:cloud-arrow-up"
},
"precipitation_category": {
"default": "mdi:weather-pouring"
},
"frozen_precipitation": {
"default": "mdi:weather-snowy-rainy"
}
}
}
}

View File

@ -0,0 +1,139 @@
"""Sensor platform for SMHI integration."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.const import CONF_LATITUDE, CONF_LOCATION, CONF_LONGITUDE, PERCENTAGE
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import StateType
from .coordinator import SMHIConfigEntry, SMHIDataUpdateCoordinator
from .entity import SmhiWeatherBaseEntity
PARALLEL_UPDATES = 0
def get_percentage_values(entity: SMHISensor, key: str) -> int | None:
"""Return percentage values in correct range."""
value: int | None = entity.coordinator.current.get(key) # type: ignore[assignment]
if value and 0 <= value <= 100:
return value
if value:
return 0
return None
@dataclass(frozen=True, kw_only=True)
class SMHISensorEntityDescription(SensorEntityDescription):
"""Describes SMHI sensor entity."""
value_fn: Callable[[SMHISensor], StateType | datetime]
SENSOR_DESCRIPTIONS: tuple[SMHISensorEntityDescription, ...] = (
SMHISensorEntityDescription(
key="thunder",
translation_key="thunder",
value_fn=lambda entity: get_percentage_values(entity, "thunder"),
native_unit_of_measurement=PERCENTAGE,
),
SMHISensorEntityDescription(
key="total_cloud",
translation_key="total_cloud",
value_fn=lambda entity: get_percentage_values(entity, "total_cloud"),
native_unit_of_measurement=PERCENTAGE,
entity_registry_enabled_default=False,
),
SMHISensorEntityDescription(
key="low_cloud",
translation_key="low_cloud",
value_fn=lambda entity: get_percentage_values(entity, "low_cloud"),
native_unit_of_measurement=PERCENTAGE,
entity_registry_enabled_default=False,
),
SMHISensorEntityDescription(
key="medium_cloud",
translation_key="medium_cloud",
value_fn=lambda entity: get_percentage_values(entity, "medium_cloud"),
native_unit_of_measurement=PERCENTAGE,
entity_registry_enabled_default=False,
),
SMHISensorEntityDescription(
key="high_cloud",
translation_key="high_cloud",
value_fn=lambda entity: get_percentage_values(entity, "high_cloud"),
native_unit_of_measurement=PERCENTAGE,
entity_registry_enabled_default=False,
),
SMHISensorEntityDescription(
key="precipitation_category",
translation_key="precipitation_category",
value_fn=lambda entity: str(
get_percentage_values(entity, "precipitation_category")
),
device_class=SensorDeviceClass.ENUM,
options=["0", "1", "2", "3", "4", "5", "6"],
),
SMHISensorEntityDescription(
key="frozen_precipitation",
translation_key="frozen_precipitation",
value_fn=lambda entity: get_percentage_values(entity, "frozen_precipitation"),
native_unit_of_measurement=PERCENTAGE,
),
)
async def async_setup_entry(
hass: HomeAssistant,
entry: SMHIConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up SMHI sensor platform."""
coordinator = entry.runtime_data
location = entry.data
async_add_entities(
SMHISensor(
location[CONF_LOCATION][CONF_LATITUDE],
location[CONF_LOCATION][CONF_LONGITUDE],
coordinator=coordinator,
entity_description=description,
)
for description in SENSOR_DESCRIPTIONS
)
class SMHISensor(SmhiWeatherBaseEntity, SensorEntity):
"""Representation of a SMHI Sensor."""
entity_description: SMHISensorEntityDescription
def __init__(
self,
latitude: str,
longitude: str,
coordinator: SMHIDataUpdateCoordinator,
entity_description: SMHISensorEntityDescription,
) -> None:
"""Initiate SMHI Sensor."""
self.entity_description = entity_description
super().__init__(
latitude,
longitude,
coordinator,
)
self._attr_unique_id += f"-{entity_description.key}"
def update_entity_data(self) -> None:
"""Refresh the entity data."""
if self.coordinator.data.daily:
self._attr_native_value = self.entity_description.value_fn(self)

View File

@ -23,5 +23,39 @@
"error": {
"wrong_location": "Location Sweden only"
}
},
"entity": {
"sensor": {
"thunder": {
"name": "Thunder probability"
},
"total_cloud": {
"name": "Total cloud coverage"
},
"low_cloud": {
"name": "Low cloud coverage"
},
"medium_cloud": {
"name": "Medium cloud coverage"
},
"high_cloud": {
"name": "High cloud coverage"
},
"precipitation_category": {
"name": "Precipitation category",
"state": {
"0": "No precipitation",
"1": "Snow",
"2": "Snow and rain",
"3": "Rain",
"4": "Drizzle",
"5": "Freezing rain",
"6": "Freezing drizzle"
}
},
"frozen_precipitation": {
"name": "Frozen precipitation"
}
}
}
}

View File

@ -118,6 +118,7 @@ class SmhiWeather(SmhiWeatherBaseEntity, SingleCoordinatorWeatherEntity):
_attr_supported_features = (
WeatherEntityFeature.FORECAST_DAILY | WeatherEntityFeature.FORECAST_HOURLY
)
_attr_name = None
def update_entity_data(self) -> None:
"""Refresh the entity data."""