856 lines
26 KiB
Python
856 lines
26 KiB
Python
"""Support for Buienradar.nl weather service."""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from buienradar.constants import (
|
|
ATTRIBUTION,
|
|
CONDCODE,
|
|
CONDITION,
|
|
DETAILED,
|
|
EXACT,
|
|
EXACTNL,
|
|
FORECAST,
|
|
IMAGE,
|
|
MEASURED,
|
|
PRECIPITATION_FORECAST,
|
|
STATIONNAME,
|
|
TIMEFRAME,
|
|
VISIBILITY,
|
|
WINDGUST,
|
|
WINDSPEED,
|
|
)
|
|
|
|
from homeassistant.components.sensor import (
|
|
SensorDeviceClass,
|
|
SensorEntity,
|
|
SensorEntityDescription,
|
|
)
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.const import (
|
|
ATTR_ATTRIBUTION,
|
|
CONF_LATITUDE,
|
|
CONF_LONGITUDE,
|
|
CONF_NAME,
|
|
DEGREE,
|
|
IRRADIATION_WATTS_PER_SQUARE_METER,
|
|
LENGTH_KILOMETERS,
|
|
LENGTH_MILLIMETERS,
|
|
PERCENTAGE,
|
|
PRECIPITATION_MILLIMETERS_PER_HOUR,
|
|
PRESSURE_HPA,
|
|
SPEED_KILOMETERS_PER_HOUR,
|
|
TEMP_CELSIUS,
|
|
)
|
|
from homeassistant.core import HomeAssistant, callback
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
from homeassistant.util import dt as dt_util
|
|
|
|
from .const import CONF_TIMEFRAME, DEFAULT_TIMEFRAME
|
|
from .util import BrData
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
MEASURED_LABEL = "Measured"
|
|
TIMEFRAME_LABEL = "Timeframe"
|
|
SYMBOL = "symbol"
|
|
|
|
# Schedule next call after (minutes):
|
|
SCHEDULE_OK = 10
|
|
# When an error occurred, new call after (minutes):
|
|
SCHEDULE_NOK = 2
|
|
|
|
STATIONNAME_LABEL = "Stationname"
|
|
|
|
SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
|
SensorEntityDescription(
|
|
key="stationname",
|
|
name=STATIONNAME_LABEL,
|
|
),
|
|
# new in json api (>1.0.0):
|
|
SensorEntityDescription(
|
|
key="barometerfc",
|
|
name="Barometer value",
|
|
icon="mdi:gauge",
|
|
),
|
|
# new in json api (>1.0.0):
|
|
SensorEntityDescription(
|
|
key="barometerfcname",
|
|
name="Barometer",
|
|
icon="mdi:gauge",
|
|
),
|
|
# new in json api (>1.0.0):
|
|
SensorEntityDescription(
|
|
key="barometerfcnamenl",
|
|
name="Barometer",
|
|
icon="mdi:gauge",
|
|
),
|
|
SensorEntityDescription(
|
|
key="condition",
|
|
name="Condition",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditioncode",
|
|
name="Condition code",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditiondetailed",
|
|
name="Detailed condition",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditionexact",
|
|
name="Full condition",
|
|
),
|
|
SensorEntityDescription(
|
|
key="symbol",
|
|
name="Symbol",
|
|
),
|
|
# new in json api (>1.0.0):
|
|
SensorEntityDescription(
|
|
key="feeltemperature",
|
|
name="Feel temperature",
|
|
native_unit_of_measurement=TEMP_CELSIUS,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
),
|
|
SensorEntityDescription(
|
|
key="humidity",
|
|
name="Humidity",
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
icon="mdi:water-percent",
|
|
),
|
|
SensorEntityDescription(
|
|
key="temperature",
|
|
name="Temperature",
|
|
native_unit_of_measurement=TEMP_CELSIUS,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
),
|
|
SensorEntityDescription(
|
|
key="groundtemperature",
|
|
name="Ground temperature",
|
|
native_unit_of_measurement=TEMP_CELSIUS,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
),
|
|
SensorEntityDescription(
|
|
key="windspeed",
|
|
name="Wind speed",
|
|
native_unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
|
|
icon="mdi:weather-windy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windforce",
|
|
name="Wind force",
|
|
native_unit_of_measurement="Bft",
|
|
icon="mdi:weather-windy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="winddirection",
|
|
name="Wind direction",
|
|
icon="mdi:compass-outline",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windazimuth",
|
|
name="Wind direction azimuth",
|
|
native_unit_of_measurement=DEGREE,
|
|
icon="mdi:compass-outline",
|
|
),
|
|
SensorEntityDescription(
|
|
key="pressure",
|
|
name="Pressure",
|
|
native_unit_of_measurement=PRESSURE_HPA,
|
|
icon="mdi:gauge",
|
|
),
|
|
SensorEntityDescription(
|
|
key="visibility",
|
|
name="Visibility",
|
|
native_unit_of_measurement=LENGTH_KILOMETERS,
|
|
),
|
|
SensorEntityDescription(
|
|
key="windgust",
|
|
name="Wind gust",
|
|
native_unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
|
|
icon="mdi:weather-windy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="precipitation",
|
|
name="Precipitation",
|
|
native_unit_of_measurement=PRECIPITATION_MILLIMETERS_PER_HOUR,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="irradiance",
|
|
name="Irradiance",
|
|
native_unit_of_measurement=IRRADIATION_WATTS_PER_SQUARE_METER,
|
|
icon="mdi:sunglasses",
|
|
),
|
|
SensorEntityDescription(
|
|
key="precipitation_forecast_average",
|
|
name="Precipitation forecast average",
|
|
native_unit_of_measurement=PRECIPITATION_MILLIMETERS_PER_HOUR,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="precipitation_forecast_total",
|
|
name="Precipitation forecast total",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
# new in json api (>1.0.0):
|
|
SensorEntityDescription(
|
|
key="rainlast24hour",
|
|
name="Rain last 24h",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
# new in json api (>1.0.0):
|
|
SensorEntityDescription(
|
|
key="rainlasthour",
|
|
name="Rain last hour",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="temperature_1d",
|
|
name="Temperature 1d",
|
|
native_unit_of_measurement=TEMP_CELSIUS,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
),
|
|
SensorEntityDescription(
|
|
key="temperature_2d",
|
|
name="Temperature 2d",
|
|
native_unit_of_measurement=TEMP_CELSIUS,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
),
|
|
SensorEntityDescription(
|
|
key="temperature_3d",
|
|
name="Temperature 3d",
|
|
native_unit_of_measurement=TEMP_CELSIUS,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
),
|
|
SensorEntityDescription(
|
|
key="temperature_4d",
|
|
name="Temperature 4d",
|
|
native_unit_of_measurement=TEMP_CELSIUS,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
),
|
|
SensorEntityDescription(
|
|
key="temperature_5d",
|
|
name="Temperature 5d",
|
|
native_unit_of_measurement=TEMP_CELSIUS,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
),
|
|
SensorEntityDescription(
|
|
key="mintemp_1d",
|
|
name="Minimum temperature 1d",
|
|
native_unit_of_measurement=TEMP_CELSIUS,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
),
|
|
SensorEntityDescription(
|
|
key="mintemp_2d",
|
|
name="Minimum temperature 2d",
|
|
native_unit_of_measurement=TEMP_CELSIUS,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
),
|
|
SensorEntityDescription(
|
|
key="mintemp_3d",
|
|
name="Minimum temperature 3d",
|
|
native_unit_of_measurement=TEMP_CELSIUS,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
),
|
|
SensorEntityDescription(
|
|
key="mintemp_4d",
|
|
name="Minimum temperature 4d",
|
|
native_unit_of_measurement=TEMP_CELSIUS,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
),
|
|
SensorEntityDescription(
|
|
key="mintemp_5d",
|
|
name="Minimum temperature 5d",
|
|
native_unit_of_measurement=TEMP_CELSIUS,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
),
|
|
SensorEntityDescription(
|
|
key="rain_1d",
|
|
name="Rain 1d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="rain_2d",
|
|
name="Rain 2d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="rain_3d",
|
|
name="Rain 3d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="rain_4d",
|
|
name="Rain 4d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="rain_5d",
|
|
name="Rain 5d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
# new in json api (>1.0.0):
|
|
SensorEntityDescription(
|
|
key="minrain_1d",
|
|
name="Minimum rain 1d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="minrain_2d",
|
|
name="Minimum rain 2d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="minrain_3d",
|
|
name="Minimum rain 3d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="minrain_4d",
|
|
name="Minimum rain 4d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="minrain_5d",
|
|
name="Minimum rain 5d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
# new in json api (>1.0.0):
|
|
SensorEntityDescription(
|
|
key="maxrain_1d",
|
|
name="Maximum rain 1d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="maxrain_2d",
|
|
name="Maximum rain 2d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="maxrain_3d",
|
|
name="Maximum rain 3d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="maxrain_4d",
|
|
name="Maximum rain 4d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="maxrain_5d",
|
|
name="Maximum rain 5d",
|
|
native_unit_of_measurement=LENGTH_MILLIMETERS,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="rainchance_1d",
|
|
name="Rainchance 1d",
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="rainchance_2d",
|
|
name="Rainchance 2d",
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="rainchance_3d",
|
|
name="Rainchance 3d",
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="rainchance_4d",
|
|
name="Rainchance 4d",
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="rainchance_5d",
|
|
name="Rainchance 5d",
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
icon="mdi:weather-pouring",
|
|
),
|
|
SensorEntityDescription(
|
|
key="sunchance_1d",
|
|
name="Sunchance 1d",
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
icon="mdi:weather-partly-cloudy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="sunchance_2d",
|
|
name="Sunchance 2d",
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
icon="mdi:weather-partly-cloudy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="sunchance_3d",
|
|
name="Sunchance 3d",
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
icon="mdi:weather-partly-cloudy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="sunchance_4d",
|
|
name="Sunchance 4d",
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
icon="mdi:weather-partly-cloudy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="sunchance_5d",
|
|
name="Sunchance 5d",
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
icon="mdi:weather-partly-cloudy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windforce_1d",
|
|
name="Wind force 1d",
|
|
native_unit_of_measurement="Bft",
|
|
icon="mdi:weather-windy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windforce_2d",
|
|
name="Wind force 2d",
|
|
native_unit_of_measurement="Bft",
|
|
icon="mdi:weather-windy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windforce_3d",
|
|
name="Wind force 3d",
|
|
native_unit_of_measurement="Bft",
|
|
icon="mdi:weather-windy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windforce_4d",
|
|
name="Wind force 4d",
|
|
native_unit_of_measurement="Bft",
|
|
icon="mdi:weather-windy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windforce_5d",
|
|
name="Wind force 5d",
|
|
native_unit_of_measurement="Bft",
|
|
icon="mdi:weather-windy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windspeed_1d",
|
|
name="Wind speed 1d",
|
|
native_unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
|
|
icon="mdi:weather-windy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windspeed_2d",
|
|
name="Wind speed 2d",
|
|
native_unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
|
|
icon="mdi:weather-windy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windspeed_3d",
|
|
name="Wind speed 3d",
|
|
native_unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
|
|
icon="mdi:weather-windy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windspeed_4d",
|
|
name="Wind speed 4d",
|
|
native_unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
|
|
icon="mdi:weather-windy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windspeed_5d",
|
|
name="Wind speed 5d",
|
|
native_unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
|
|
icon="mdi:weather-windy",
|
|
),
|
|
SensorEntityDescription(
|
|
key="winddirection_1d",
|
|
name="Wind direction 1d",
|
|
icon="mdi:compass-outline",
|
|
),
|
|
SensorEntityDescription(
|
|
key="winddirection_2d",
|
|
name="Wind direction 2d",
|
|
icon="mdi:compass-outline",
|
|
),
|
|
SensorEntityDescription(
|
|
key="winddirection_3d",
|
|
name="Wind direction 3d",
|
|
icon="mdi:compass-outline",
|
|
),
|
|
SensorEntityDescription(
|
|
key="winddirection_4d",
|
|
name="Wind direction 4d",
|
|
icon="mdi:compass-outline",
|
|
),
|
|
SensorEntityDescription(
|
|
key="winddirection_5d",
|
|
name="Wind direction 5d",
|
|
icon="mdi:compass-outline",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windazimuth_1d",
|
|
name="Wind direction azimuth 1d",
|
|
native_unit_of_measurement=DEGREE,
|
|
icon="mdi:compass-outline",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windazimuth_2d",
|
|
name="Wind direction azimuth 2d",
|
|
native_unit_of_measurement=DEGREE,
|
|
icon="mdi:compass-outline",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windazimuth_3d",
|
|
name="Wind direction azimuth 3d",
|
|
native_unit_of_measurement=DEGREE,
|
|
icon="mdi:compass-outline",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windazimuth_4d",
|
|
name="Wind direction azimuth 4d",
|
|
native_unit_of_measurement=DEGREE,
|
|
icon="mdi:compass-outline",
|
|
),
|
|
SensorEntityDescription(
|
|
key="windazimuth_5d",
|
|
name="Wind direction azimuth 5d",
|
|
native_unit_of_measurement=DEGREE,
|
|
icon="mdi:compass-outline",
|
|
),
|
|
SensorEntityDescription(
|
|
key="condition_1d",
|
|
name="Condition 1d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="condition_2d",
|
|
name="Condition 2d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="condition_3d",
|
|
name="Condition 3d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="condition_4d",
|
|
name="Condition 4d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="condition_5d",
|
|
name="Condition 5d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditioncode_1d",
|
|
name="Condition code 1d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditioncode_2d",
|
|
name="Condition code 2d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditioncode_3d",
|
|
name="Condition code 3d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditioncode_4d",
|
|
name="Condition code 4d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditioncode_5d",
|
|
name="Condition code 5d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditiondetailed_1d",
|
|
name="Detailed condition 1d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditiondetailed_2d",
|
|
name="Detailed condition 2d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditiondetailed_3d",
|
|
name="Detailed condition 3d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditiondetailed_4d",
|
|
name="Detailed condition 4d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditiondetailed_5d",
|
|
name="Detailed condition 5d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditionexact_1d",
|
|
name="Full condition 1d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditionexact_2d",
|
|
name="Full condition 2d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditionexact_3d",
|
|
name="Full condition 3d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditionexact_4d",
|
|
name="Full condition 4d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="conditionexact_5d",
|
|
name="Full condition 5d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="symbol_1d",
|
|
name="Symbol 1d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="symbol_2d",
|
|
name="Symbol 2d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="symbol_3d",
|
|
name="Symbol 3d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="symbol_4d",
|
|
name="Symbol 4d",
|
|
),
|
|
SensorEntityDescription(
|
|
key="symbol_5d",
|
|
name="Symbol 5d",
|
|
),
|
|
)
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
|
) -> None:
|
|
"""Create the buienradar sensor."""
|
|
config = entry.data
|
|
options = entry.options
|
|
|
|
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
|
|
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
|
|
|
|
timeframe = options.get(
|
|
CONF_TIMEFRAME, config.get(CONF_TIMEFRAME, DEFAULT_TIMEFRAME)
|
|
)
|
|
|
|
if None in (latitude, longitude):
|
|
_LOGGER.error("Latitude or longitude not set in Home Assistant config")
|
|
return
|
|
|
|
coordinates = {CONF_LATITUDE: float(latitude), CONF_LONGITUDE: float(longitude)}
|
|
|
|
_LOGGER.debug(
|
|
"Initializing buienradar sensor coordinate %s, timeframe %s",
|
|
coordinates,
|
|
timeframe,
|
|
)
|
|
|
|
entities = [
|
|
BrSensor(config.get(CONF_NAME, "Buienradar"), coordinates, description)
|
|
for description in SENSOR_TYPES
|
|
]
|
|
|
|
async_add_entities(entities)
|
|
|
|
data = BrData(hass, coordinates, timeframe, entities)
|
|
# schedule the first update in 1 minute from now:
|
|
await data.schedule_update(1)
|
|
|
|
|
|
class BrSensor(SensorEntity):
|
|
"""Representation of an Buienradar sensor."""
|
|
|
|
_attr_entity_registry_enabled_default = False
|
|
_attr_should_poll = False
|
|
|
|
def __init__(self, client_name, coordinates, description: SensorEntityDescription):
|
|
"""Initialize the sensor."""
|
|
self.entity_description = description
|
|
self._attr_name = f"{client_name} {description.name}"
|
|
self._measured = None
|
|
self._attr_unique_id = "{:2.6f}{:2.6f}{}".format(
|
|
coordinates[CONF_LATITUDE], coordinates[CONF_LONGITUDE], description.key
|
|
)
|
|
|
|
# All continuous sensors should be forced to be updated
|
|
self._attr_force_update = (
|
|
description.key != SYMBOL and not description.key.startswith(CONDITION)
|
|
)
|
|
|
|
if description.key.startswith(PRECIPITATION_FORECAST):
|
|
self._timeframe = None
|
|
|
|
@callback
|
|
def data_updated(self, data):
|
|
"""Update data."""
|
|
if self.hass and self._load_data(data):
|
|
self.async_write_ha_state()
|
|
|
|
@callback
|
|
def _load_data(self, data): # noqa: C901
|
|
"""Load the sensor with relevant data."""
|
|
# Find sensor
|
|
|
|
# Check if we have a new measurement,
|
|
# otherwise we do not have to update the sensor
|
|
if self._measured == data.get(MEASURED):
|
|
return False
|
|
|
|
self._measured = data.get(MEASURED)
|
|
sensor_type = self.entity_description.key
|
|
|
|
if (
|
|
sensor_type.endswith("_1d")
|
|
or sensor_type.endswith("_2d")
|
|
or sensor_type.endswith("_3d")
|
|
or sensor_type.endswith("_4d")
|
|
or sensor_type.endswith("_5d")
|
|
):
|
|
|
|
# update forcasting sensors:
|
|
fcday = 0
|
|
if sensor_type.endswith("_2d"):
|
|
fcday = 1
|
|
if sensor_type.endswith("_3d"):
|
|
fcday = 2
|
|
if sensor_type.endswith("_4d"):
|
|
fcday = 3
|
|
if sensor_type.endswith("_5d"):
|
|
fcday = 4
|
|
|
|
# update weather symbol & status text
|
|
if sensor_type.startswith(SYMBOL) or sensor_type.startswith(CONDITION):
|
|
try:
|
|
condition = data.get(FORECAST)[fcday].get(CONDITION)
|
|
except IndexError:
|
|
_LOGGER.warning("No forecast for fcday=%s", fcday)
|
|
return False
|
|
|
|
if condition:
|
|
new_state = condition.get(CONDITION)
|
|
if sensor_type.startswith(SYMBOL):
|
|
new_state = condition.get(EXACTNL)
|
|
if sensor_type.startswith("conditioncode"):
|
|
new_state = condition.get(CONDCODE)
|
|
if sensor_type.startswith("conditiondetailed"):
|
|
new_state = condition.get(DETAILED)
|
|
if sensor_type.startswith("conditionexact"):
|
|
new_state = condition.get(EXACT)
|
|
|
|
img = condition.get(IMAGE)
|
|
|
|
if new_state != self.state or img != self.entity_picture:
|
|
self._attr_native_value = new_state
|
|
self._attr_entity_picture = img
|
|
return True
|
|
return False
|
|
|
|
if sensor_type.startswith(WINDSPEED):
|
|
# hass wants windspeeds in km/h not m/s, so convert:
|
|
try:
|
|
self._attr_native_value = data.get(FORECAST)[fcday].get(
|
|
sensor_type[:-3]
|
|
)
|
|
if self.state is not None:
|
|
self._attr_native_value = round(self.state * 3.6, 1)
|
|
return True
|
|
except IndexError:
|
|
_LOGGER.warning("No forecast for fcday=%s", fcday)
|
|
return False
|
|
|
|
# update all other sensors
|
|
try:
|
|
self._attr_native_value = data.get(FORECAST)[fcday].get(
|
|
sensor_type[:-3]
|
|
)
|
|
return True
|
|
except IndexError:
|
|
_LOGGER.warning("No forecast for fcday=%s", fcday)
|
|
return False
|
|
|
|
if sensor_type == SYMBOL or sensor_type.startswith(CONDITION):
|
|
# update weather symbol & status text
|
|
if condition := data.get(CONDITION):
|
|
if sensor_type == SYMBOL:
|
|
new_state = condition.get(EXACTNL)
|
|
if sensor_type == CONDITION:
|
|
new_state = condition.get(CONDITION)
|
|
if sensor_type == "conditioncode":
|
|
new_state = condition.get(CONDCODE)
|
|
if sensor_type == "conditiondetailed":
|
|
new_state = condition.get(DETAILED)
|
|
if sensor_type == "conditionexact":
|
|
new_state = condition.get(EXACT)
|
|
|
|
img = condition.get(IMAGE)
|
|
|
|
if new_state != self.state or img != self.entity_picture:
|
|
self._attr_native_value = new_state
|
|
self._attr_entity_picture = img
|
|
return True
|
|
|
|
return False
|
|
|
|
if sensor_type.startswith(PRECIPITATION_FORECAST):
|
|
# update nested precipitation forecast sensors
|
|
nested = data.get(PRECIPITATION_FORECAST)
|
|
self._timeframe = nested.get(TIMEFRAME)
|
|
self._attr_native_value = nested.get(
|
|
sensor_type[len(PRECIPITATION_FORECAST) + 1 :]
|
|
)
|
|
return True
|
|
|
|
if sensor_type in [WINDSPEED, WINDGUST]:
|
|
# hass wants windspeeds in km/h not m/s, so convert:
|
|
self._attr_native_value = data.get(sensor_type)
|
|
if self.state is not None:
|
|
self._attr_native_value = round(data.get(sensor_type) * 3.6, 1)
|
|
return True
|
|
|
|
if sensor_type == VISIBILITY:
|
|
# hass wants visibility in km (not m), so convert:
|
|
self._attr_native_value = data.get(sensor_type)
|
|
if self.state is not None:
|
|
self._attr_native_value = round(self.state / 1000, 1)
|
|
return True
|
|
|
|
# update all other sensors
|
|
self._attr_native_value = data.get(sensor_type)
|
|
if sensor_type.startswith(PRECIPITATION_FORECAST):
|
|
result = {ATTR_ATTRIBUTION: data.get(ATTRIBUTION)}
|
|
if self._timeframe is not None:
|
|
result[TIMEFRAME_LABEL] = "%d min" % (self._timeframe)
|
|
|
|
self._attr_extra_state_attributes = result
|
|
|
|
result = {
|
|
ATTR_ATTRIBUTION: data.get(ATTRIBUTION),
|
|
STATIONNAME_LABEL: data.get(STATIONNAME),
|
|
}
|
|
if self._measured is not None:
|
|
# convert datetime (Europe/Amsterdam) into local datetime
|
|
local_dt = dt_util.as_local(self._measured)
|
|
result[MEASURED_LABEL] = local_dt.strftime("%c")
|
|
|
|
self._attr_extra_state_attributes = result
|
|
return True
|