Files
HomeAssistantVS/custom_components/pirateweather/sensor.py
T
2026-07-17 10:12:15 -04:00

1471 lines
51 KiB
Python

"""Support for Pirate Weather (Dark Sky Compatable) weather service."""
import datetime
import logging
from dataclasses import dataclass, field
from typing import Literal, NamedTuple
import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from homeassistant.components.sensor import (
PLATFORM_SCHEMA,
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import (
ATTR_ATTRIBUTION,
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONF_API_KEY,
CONF_LATITUDE,
CONF_LONGITUDE,
CONF_MONITORED_CONDITIONS,
CONF_NAME,
CONF_SCAN_INTERVAL,
DEGREE,
PERCENTAGE,
UV_INDEX,
UnitOfIrradiance,
UnitOfLength,
UnitOfPressure,
UnitOfSpeed,
UnitOfTemperature,
UnitOfVolumetricFlux,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import DiscoveryInfoType, StateType
from homeassistant.util import dt as dt_util
from .const import (
ALL_CONDITIONS,
DEFAULT_SCAN_INTERVAL,
DOMAIN,
ENTRY_WEATHER_COORDINATOR,
MANUFACTURER,
PW_PLATFORM,
PW_PLATFORMS,
PW_PREVPLATFORM,
PW_ROUND,
)
from .weather_update_coordinator import WeatherUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
ATTRIBUTION = "Powered by Pirate Weather"
CONF_FORECAST = "forecast"
CONF_HOURLY_FORECAST = "hourly_forecast"
CONF_LANGUAGE = "language"
CONF_UNITS = "units"
DEFAULT_LANGUAGE = "en"
DEFAULT_NAME = "Pirate Weather"
DEPRECATED_SENSOR_TYPES = {
"apparent_temperature_max",
"apparent_temperature_min",
"temperature_max",
"temperature_min",
}
MAP_UNIT_SYSTEM: dict[
Literal["si", "us", "ca", "uk", "uk2"],
Literal["si_unit", "us_unit", "ca_unit", "uk_unit", "uk2_unit"],
] = {
"si": "si_unit",
"us": "us_unit",
"ca": "ca_unit",
"uk": "uk_unit",
"uk2": "uk2_unit",
}
@dataclass
class PirateWeatherSensorEntityDescription(SensorEntityDescription):
"""Describes Pirate Weather sensor entity."""
si_unit: str | None = None
us_unit: str | None = None
ca_unit: str | None = None
uk_unit: str | None = None
uk2_unit: str | None = None
forecast_mode: list[str] = field(default_factory=list)
# Sensor Types
SENSOR_TYPES: dict[str, PirateWeatherSensorEntityDescription] = {
"summary": PirateWeatherSensorEntityDescription(
key="summary",
name="Summary",
forecast_mode=["currently", "hourly", "daily"],
),
"minutely_summary": PirateWeatherSensorEntityDescription(
key="minutely_summary",
name="Minutely Summary",
forecast_mode=[],
),
"hourly_summary": PirateWeatherSensorEntityDescription(
key="hourly_summary",
name="Hourly Summary",
forecast_mode=[],
),
"daily_summary": PirateWeatherSensorEntityDescription(
key="daily_summary",
name="Daily Summary",
forecast_mode=[],
),
"icon": PirateWeatherSensorEntityDescription(
key="icon",
name="Icon",
forecast_mode=["currently", "hourly", "daily"],
),
"nearest_storm_distance": PirateWeatherSensorEntityDescription(
key="nearest_storm_distance",
name="Nearest Storm Distance",
si_unit=UnitOfLength.KILOMETERS,
us_unit=UnitOfLength.MILES,
ca_unit=UnitOfLength.KILOMETERS,
uk_unit=UnitOfLength.KILOMETERS,
uk2_unit=UnitOfLength.MILES,
suggested_display_precision=2,
icon="mdi:weather-lightning",
forecast_mode=["currently"],
),
"nearest_storm_bearing": PirateWeatherSensorEntityDescription(
key="nearest_storm_bearing",
name="Nearest Storm Bearing",
si_unit=DEGREE,
us_unit=DEGREE,
ca_unit=DEGREE,
uk_unit=DEGREE,
uk2_unit=DEGREE,
suggested_display_precision=0,
icon="mdi:weather-lightning",
forecast_mode=["currently"],
),
"precip_type": PirateWeatherSensorEntityDescription(
key="precip_type",
name="Precip",
icon="mdi:weather-pouring",
forecast_mode=["currently", "minutely", "hourly", "daily"],
),
"precip_intensity": PirateWeatherSensorEntityDescription(
key="precip_intensity",
name="Precip Intensity",
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
suggested_display_precision=4,
icon="mdi:weather-rainy",
forecast_mode=["currently", "minutely", "hourly", "daily"],
),
"precip_probability": PirateWeatherSensorEntityDescription(
key="precip_probability",
name="Precip Probability",
state_class=SensorStateClass.MEASUREMENT,
si_unit=PERCENTAGE,
us_unit=PERCENTAGE,
ca_unit=PERCENTAGE,
uk_unit=PERCENTAGE,
uk2_unit=PERCENTAGE,
suggested_display_precision=0,
icon="mdi:water-percent",
forecast_mode=["currently", "minutely", "hourly", "daily"],
),
"precip_accumulation": PirateWeatherSensorEntityDescription(
key="precip_accumulation",
name="Precip Accumulation",
device_class=SensorDeviceClass.PRECIPITATION,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfLength.CENTIMETERS,
us_unit=UnitOfLength.INCHES,
ca_unit=UnitOfLength.CENTIMETERS,
uk_unit=UnitOfLength.CENTIMETERS,
uk2_unit=UnitOfLength.CENTIMETERS,
suggested_display_precision=4,
icon="mdi:weather-snowy",
forecast_mode=["hourly", "daily"],
),
"liquid_accumulation": PirateWeatherSensorEntityDescription(
key="liquid_accumulation",
name="Liquid Accumulation",
device_class=SensorDeviceClass.PRECIPITATION,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfLength.CENTIMETERS,
us_unit=UnitOfLength.INCHES,
ca_unit=UnitOfLength.CENTIMETERS,
uk_unit=UnitOfLength.CENTIMETERS,
uk2_unit=UnitOfLength.CENTIMETERS,
suggested_display_precision=4,
icon="mdi:weather-rainy",
forecast_mode=["hourly", "daily"],
),
"snow_accumulation": PirateWeatherSensorEntityDescription(
key="snow_accumulation",
name="Snow Accumulation",
device_class=SensorDeviceClass.PRECIPITATION,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfLength.CENTIMETERS,
us_unit=UnitOfLength.INCHES,
ca_unit=UnitOfLength.CENTIMETERS,
uk_unit=UnitOfLength.CENTIMETERS,
uk2_unit=UnitOfLength.CENTIMETERS,
suggested_display_precision=4,
icon="mdi:weather-snowy",
forecast_mode=["hourly", "daily"],
),
"ice_accumulation": PirateWeatherSensorEntityDescription(
key="ice_accumulation",
name="Ice Accumulation",
device_class=SensorDeviceClass.PRECIPITATION,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfLength.CENTIMETERS,
us_unit=UnitOfLength.INCHES,
ca_unit=UnitOfLength.CENTIMETERS,
uk_unit=UnitOfLength.CENTIMETERS,
uk2_unit=UnitOfLength.CENTIMETERS,
suggested_display_precision=4,
icon="mdi:weather-snowy-rainy",
forecast_mode=["hourly", "daily"],
),
"current_day_liquid": PirateWeatherSensorEntityDescription(
key="current_day_liquid",
name="Current Day Liquid Accumulation",
device_class=SensorDeviceClass.PRECIPITATION,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfLength.CENTIMETERS,
us_unit=UnitOfLength.INCHES,
ca_unit=UnitOfLength.CENTIMETERS,
uk_unit=UnitOfLength.CENTIMETERS,
uk2_unit=UnitOfLength.CENTIMETERS,
suggested_display_precision=4,
icon="mdi:weather-rainy",
forecast_mode=["currently"],
),
"current_day_snow": PirateWeatherSensorEntityDescription(
key="current_day_snow",
name="Current Day Snow Accumulation",
device_class=SensorDeviceClass.PRECIPITATION,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfLength.CENTIMETERS,
us_unit=UnitOfLength.INCHES,
ca_unit=UnitOfLength.CENTIMETERS,
uk_unit=UnitOfLength.CENTIMETERS,
uk2_unit=UnitOfLength.CENTIMETERS,
suggested_display_precision=4,
icon="mdi:weather-snowy",
forecast_mode=["currently"],
),
"current_day_ice": PirateWeatherSensorEntityDescription(
key="current_day_ice",
name="Current Day Ice Accumulation",
device_class=SensorDeviceClass.PRECIPITATION,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfLength.CENTIMETERS,
us_unit=UnitOfLength.INCHES,
ca_unit=UnitOfLength.CENTIMETERS,
uk_unit=UnitOfLength.CENTIMETERS,
uk2_unit=UnitOfLength.CENTIMETERS,
suggested_display_precision=4,
icon="mdi:weather-snowy-rainy",
forecast_mode=["currently"],
),
"temperature": PirateWeatherSensorEntityDescription(
key="temperature",
name="Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
suggested_display_precision=2,
forecast_mode=["currently", "hourly"],
),
"apparent_temperature": PirateWeatherSensorEntityDescription(
key="apparent_temperature",
name="Apparent Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
suggested_display_precision=2,
forecast_mode=["currently", "hourly"],
),
"dew_point": PirateWeatherSensorEntityDescription(
key="dew_point",
name="Dew Point",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
suggested_display_precision=2,
forecast_mode=["currently", "hourly", "daily"],
),
"wind_speed": PirateWeatherSensorEntityDescription(
key="wind_speed",
name="Wind Speed",
device_class=SensorDeviceClass.WIND_SPEED,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfSpeed.METERS_PER_SECOND,
us_unit=UnitOfSpeed.MILES_PER_HOUR,
ca_unit=UnitOfSpeed.KILOMETERS_PER_HOUR,
uk_unit=UnitOfSpeed.MILES_PER_HOUR,
uk2_unit=UnitOfSpeed.MILES_PER_HOUR,
suggested_display_precision=2,
icon="mdi:weather-windy",
forecast_mode=["currently", "hourly", "daily"],
),
"wind_bearing": PirateWeatherSensorEntityDescription(
key="wind_bearing",
name="Wind Bearing",
state_class=SensorStateClass.MEASUREMENT,
si_unit=DEGREE,
us_unit=DEGREE,
ca_unit=DEGREE,
uk_unit=DEGREE,
uk2_unit=DEGREE,
suggested_display_precision=0,
icon="mdi:compass",
forecast_mode=["currently", "hourly", "daily"],
),
"wind_gust": PirateWeatherSensorEntityDescription(
key="wind_gust",
name="Wind Gust",
device_class=SensorDeviceClass.WIND_SPEED,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfSpeed.METERS_PER_SECOND,
us_unit=UnitOfSpeed.MILES_PER_HOUR,
ca_unit=UnitOfSpeed.KILOMETERS_PER_HOUR,
uk_unit=UnitOfSpeed.MILES_PER_HOUR,
uk2_unit=UnitOfSpeed.MILES_PER_HOUR,
suggested_display_precision=2,
icon="mdi:weather-windy-variant",
forecast_mode=["currently", "hourly", "daily"],
),
"cloud_cover": PirateWeatherSensorEntityDescription(
key="cloud_cover",
name="Cloud Coverage",
state_class=SensorStateClass.MEASUREMENT,
si_unit=PERCENTAGE,
us_unit=PERCENTAGE,
ca_unit=PERCENTAGE,
uk_unit=PERCENTAGE,
uk2_unit=PERCENTAGE,
suggested_display_precision=0,
icon="mdi:weather-partly-cloudy",
forecast_mode=["currently", "hourly", "daily"],
),
"humidity": PirateWeatherSensorEntityDescription(
key="humidity",
name="Humidity",
device_class=SensorDeviceClass.HUMIDITY,
state_class=SensorStateClass.MEASUREMENT,
si_unit=PERCENTAGE,
us_unit=PERCENTAGE,
ca_unit=PERCENTAGE,
uk_unit=PERCENTAGE,
uk2_unit=PERCENTAGE,
suggested_display_precision=0,
forecast_mode=["currently", "hourly", "daily"],
),
"pressure": PirateWeatherSensorEntityDescription(
key="pressure",
name="Pressure",
device_class=SensorDeviceClass.PRESSURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfPressure.MBAR,
us_unit=UnitOfPressure.MBAR,
ca_unit=UnitOfPressure.MBAR,
uk_unit=UnitOfPressure.MBAR,
uk2_unit=UnitOfPressure.MBAR,
suggested_display_precision=2,
forecast_mode=["currently", "hourly", "daily"],
),
"visibility": PirateWeatherSensorEntityDescription(
key="visibility",
name="Visibility",
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfLength.KILOMETERS,
us_unit=UnitOfLength.MILES,
ca_unit=UnitOfLength.KILOMETERS,
uk_unit=UnitOfLength.KILOMETERS,
uk2_unit=UnitOfLength.MILES,
suggested_display_precision=2,
icon="mdi:eye",
forecast_mode=["currently", "hourly", "daily"],
),
"ozone": PirateWeatherSensorEntityDescription(
key="ozone",
name="Ozone",
state_class=SensorStateClass.MEASUREMENT,
si_unit="DU",
us_unit="DU",
ca_unit="DU",
uk_unit="DU",
uk2_unit="DU",
suggested_display_precision=2,
forecast_mode=["currently", "hourly", "daily"],
),
"fire_index": PirateWeatherSensorEntityDescription(
key="fire_index",
name="Fire Index",
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=2,
icon="mdi:fire",
forecast_mode=["currently", "hourly"],
),
"fire_risk_level": PirateWeatherSensorEntityDescription(
key="fire_risk_level",
name="Fire Risk Level",
device_class=SensorDeviceClass.ENUM,
icon="mdi:fire",
forecast_mode=["currently", "hourly", "daily"],
options=["Extreme", "Very High", "High", "Moderate", "Low", "N/A"],
),
"fire_index_max": PirateWeatherSensorEntityDescription(
key="fire_index_max",
name="Fire Index Max",
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=2,
icon="mdi:fire",
forecast_mode=["daily"],
),
"smoke": PirateWeatherSensorEntityDescription(
key="smoke",
name="Smoke",
device_class=SensorDeviceClass.PM25,
state_class=SensorStateClass.MEASUREMENT,
si_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
us_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
ca_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
uk_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
uk2_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
suggested_display_precision=2,
icon="mdi:smoke",
forecast_mode=["currently", "hourly"],
),
"smoke_max": PirateWeatherSensorEntityDescription(
key="smoke_max",
name="Smoke Max",
device_class=SensorDeviceClass.PM25,
state_class=SensorStateClass.MEASUREMENT,
si_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
us_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
ca_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
uk_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
uk2_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
suggested_display_precision=2,
icon="mdi:smoke",
forecast_mode=["daily"],
),
"apparent_temperature_max": PirateWeatherSensorEntityDescription(
key="apparent_temperature_max",
name="Daily High Apparent Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
suggested_display_precision=2,
forecast_mode=["daily"],
),
"apparent_temperature_high": PirateWeatherSensorEntityDescription(
key="apparent_temperature_high",
name="Daytime High Apparent Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
suggested_display_precision=2,
forecast_mode=["daily"],
),
"apparent_temperature_high_time": PirateWeatherSensorEntityDescription(
key="apparent_temperature_high_time",
name="Daytime High Apparent Temperature Time",
icon="mdi:clock-time-three-outline",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=["daily"],
),
"apparent_temperature_min": PirateWeatherSensorEntityDescription(
key="apparent_temperature_min",
name="Daily Low Apparent Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
suggested_display_precision=2,
forecast_mode=["daily"],
),
"apparent_temperature_low": PirateWeatherSensorEntityDescription(
key="apparent_temperature_low",
name="Overnight Low Apparent Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
suggested_display_precision=2,
forecast_mode=["daily"],
),
"apparent_temperature_low_time": PirateWeatherSensorEntityDescription(
key="apparent_temperature_low_time",
name="Overnight Low Apparent Temperature Time",
icon="mdi:clock-time-three-outline",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=["daily"],
),
"temperature_max": PirateWeatherSensorEntityDescription(
key="temperature_max",
name="Daily High Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
suggested_display_precision=2,
forecast_mode=["daily"],
),
"temperature_high": PirateWeatherSensorEntityDescription(
key="temperature_high",
name="Daytime High Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
suggested_display_precision=2,
forecast_mode=["daily"],
),
"temperature_high_time": PirateWeatherSensorEntityDescription(
key="temperature_high_time",
name="Daytime High Temperature Time",
icon="mdi:clock-time-three-outline",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=["daily"],
),
"temperature_min": PirateWeatherSensorEntityDescription(
key="temperature_min",
name="Daily Low Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
suggested_display_precision=2,
forecast_mode=["daily"],
),
"temperature_min_time": PirateWeatherSensorEntityDescription(
key="temperature_min_time",
name="Daily Low Temperature Time",
icon="mdi:clock-time-three-outline",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=["daily"],
),
"temperature_low": PirateWeatherSensorEntityDescription(
key="temperature_low",
name="Overnight Low Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
suggested_display_precision=2,
forecast_mode=["daily"],
),
"precip_intensity_max": PirateWeatherSensorEntityDescription(
key="precip_intensity_max",
name="Daily Max Precip Intensity",
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
suggested_display_precision=2,
icon="mdi:thermometer",
forecast_mode=["daily"],
),
"uv_index": PirateWeatherSensorEntityDescription(
key="uv_index",
name="UV Index",
state_class=SensorStateClass.MEASUREMENT,
si_unit=UV_INDEX,
us_unit=UV_INDEX,
ca_unit=UV_INDEX,
uk_unit=UV_INDEX,
uk2_unit=UV_INDEX,
suggested_display_precision=2,
icon="mdi:weather-sunny",
forecast_mode=["currently", "hourly", "daily"],
),
"air_quality_index": PirateWeatherSensorEntityDescription(
key="air_quality_index",
name="Air Quality Index",
device_class=SensorDeviceClass.AQI,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
icon="mdi:air-filter",
forecast_mode=["currently", "hourly", "daily"],
),
"cape": PirateWeatherSensorEntityDescription(
key="cape",
name="Convective Available Potential Energy",
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
icon="mdi:weather-lightning",
forecast_mode=["currently", "hourly"],
),
"cape_max": PirateWeatherSensorEntityDescription(
key="cape_max",
name="Convective Available Potential Energy Max",
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
icon="mdi:weather-lightning",
forecast_mode=["daily"],
),
"solar": PirateWeatherSensorEntityDescription(
key="solar",
name="Downward Short-Wave Radiation Flux",
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
us_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
ca_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
uk_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
uk2_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
suggested_display_precision=2,
icon="mdi:weather-sunny",
forecast_mode=["currently", "hourly"],
),
"solar_max": PirateWeatherSensorEntityDescription(
key="solar_max",
name="Downward Short-Wave Radiation Flux Max",
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
us_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
ca_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
uk_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
uk2_unit=UnitOfIrradiance.WATTS_PER_SQUARE_METER,
suggested_display_precision=2,
icon="mdi:weather-sunny",
forecast_mode=["daily"],
),
"rain_intensity": PirateWeatherSensorEntityDescription(
key="rain_intensity",
name="Rain Intensity",
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
suggested_display_precision=4,
icon="mdi:weather-rainy",
forecast_mode=["currently", "hourly", "daily"],
),
"rain_intensity_max": PirateWeatherSensorEntityDescription(
key="rain_intensity_max",
name="Rain Intensity Max",
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
suggested_display_precision=4,
icon="mdi:weather-rainy",
forecast_mode=["daily"],
),
"snow_intensity": PirateWeatherSensorEntityDescription(
key="snow_intensity",
name="Snow Intensity",
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
suggested_display_precision=4,
icon="mdi:weather-snowy",
forecast_mode=["currently", "hourly", "daily"],
),
"snow_intensity_max": PirateWeatherSensorEntityDescription(
key="snow_intensity_max",
name="Snow Intensity Max",
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
suggested_display_precision=4,
icon="mdi:weather-snowy",
forecast_mode=["daily"],
),
"ice_intensity": PirateWeatherSensorEntityDescription(
key="ice_intensity",
name="Ice Intensity",
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
suggested_display_precision=4,
icon="mdi:weather-snowy-rainy",
forecast_mode=["currently", "hourly", "daily"],
),
"ice_intensity_max": PirateWeatherSensorEntityDescription(
key="ice_intensity_max",
name="Ice Intensity Max",
device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
suggested_display_precision=4,
icon="mdi:weather-snowy-rainy",
forecast_mode=["daily"],
),
"moon_phase": PirateWeatherSensorEntityDescription(
key="moon_phase",
name="Moon Phase",
suggested_display_precision=2,
icon="mdi:weather-night",
forecast_mode=["daily"],
),
"sunrise_time": PirateWeatherSensorEntityDescription(
key="sunrise_time",
name="Sunrise",
icon="mdi:white-balance-sunny",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=["daily"],
),
"sunset_time": PirateWeatherSensorEntityDescription(
key="sunset_time",
name="Sunset",
icon="mdi:weather-night",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=["daily"],
),
"alerts": PirateWeatherSensorEntityDescription(
key="alerts",
name="Alerts",
icon="mdi:alert-circle-outline",
forecast_mode=[],
),
"time": PirateWeatherSensorEntityDescription(
key="time",
name="Time",
icon="mdi:clock-time-three-outline",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=["currently", "hourly", "daily"],
),
"hrrr_subh_update_time": PirateWeatherSensorEntityDescription(
key="hrrr_subh",
name="HRRR SubHourly Update Time",
icon="mdi:clock-time-three-outline",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=[],
),
"hrrr_0_18_update_time": PirateWeatherSensorEntityDescription(
key="hrrr_0-18",
name="HRRR 0-18 Update Time",
icon="mdi:clock-time-three-outline",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=[],
),
"nbm_update_time": PirateWeatherSensorEntityDescription(
key="nbm",
name="NBM Update Time",
icon="mdi:clock-time-three-outline",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=[],
),
"nbm_fire_update_time": PirateWeatherSensorEntityDescription(
key="nbm_fire",
name="NBM Fire Update Time",
icon="mdi:clock-time-three-outline",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=[],
),
"hrrr_18_48_update_time": PirateWeatherSensorEntityDescription(
key="hrrr_18-48",
name="HRRR 18-48 Update Time",
icon="mdi:clock-time-three-outline",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=[],
),
"gfs_update_time": PirateWeatherSensorEntityDescription(
key="gfs",
name="GFS Update Time",
icon="mdi:clock-time-three-outline",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=[],
),
"gefs_update_time": PirateWeatherSensorEntityDescription(
key="gefs",
name="GEFS Update Time",
icon="mdi:clock-time-three-outline",
device_class=SensorDeviceClass.TIMESTAMP,
forecast_mode=[],
),
}
class ConditionPicture(NamedTuple):
"""Entity picture and icon for condition."""
entity_picture: str
icon: str
CONDITION_PICTURES: dict[str, ConditionPicture] = {
"clear-day": ConditionPicture(
entity_picture="/static/images/darksky/weather-sunny.svg",
icon="mdi:weather-sunny",
),
"clear-night": ConditionPicture(
entity_picture="/static/images/darksky/weather-night.svg",
icon="mdi:weather-night",
),
"rain": ConditionPicture(
entity_picture="/static/images/darksky/weather-pouring.svg",
icon="mdi:weather-pouring",
),
"snow": ConditionPicture(
entity_picture="/static/images/darksky/weather-snowy.svg",
icon="mdi:weather-snowy",
),
"sleet": ConditionPicture(
entity_picture="/static/images/darksky/weather-hail.svg",
icon="mdi:weather-snowy-rainy",
),
"wind": ConditionPicture(
entity_picture="/static/images/darksky/weather-windy.svg",
icon="mdi:weather-windy",
),
"fog": ConditionPicture(
entity_picture="/static/images/darksky/weather-fog.svg",
icon="mdi:weather-fog",
),
"cloudy": ConditionPicture(
entity_picture="/static/images/darksky/weather-cloudy.svg",
icon="mdi:weather-cloudy",
),
"partly-cloudy-day": ConditionPicture(
entity_picture="/static/images/darksky/weather-partlycloudy.svg",
icon="mdi:weather-partly-cloudy",
),
"partly-cloudy-night": ConditionPicture(
entity_picture="/static/images/darksky/weather-cloudy.svg",
icon="mdi:weather-night-partly-cloudy",
),
}
# Language Supported Codes
LANGUAGE_CODES = [
"ar",
"az",
"be",
"bg",
"bn",
"bs",
"ca",
"cs",
"da",
"de",
"el",
"en",
"ja",
"ka",
"kn",
"ko",
"eo",
"es",
"et",
"fi",
"fr",
"he",
"hi",
"hr",
"hu",
"id",
"is",
"it",
"kw",
"lv",
"ml",
"mr",
"nb",
"nl",
"pa",
"pl",
"pt",
"ro",
"ru",
"sk",
"sl",
"sr",
"sv",
"ta",
"te",
"tet",
"tr",
"uk",
"ur",
"x-pig-latin",
"zh",
"zh-tw",
]
ALLOWED_UNITS = ["si", "us", "ca", "uk", "uk2"]
ALERTS_ATTRS = ["time", "description", "expires", "severity", "uri", "regions", "title"]
HOURS = list(range(168))
DAYS = list(range(7))
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_API_KEY): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_UNITS): vol.In(ALLOWED_UNITS),
vol.Optional(CONF_LANGUAGE, default=DEFAULT_LANGUAGE): vol.In(LANGUAGE_CODES),
vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL): cv.time_period,
vol.Inclusive(
CONF_LATITUDE, "coordinates", "Latitude and longitude must exist together"
): cv.latitude,
vol.Inclusive(
CONF_LONGITUDE, "coordinates", "Latitude and longitude must exist together"
): cv.longitude,
vol.Optional(PW_PLATFORM): cv.multi_select(PW_PLATFORMS),
vol.Optional(PW_PREVPLATFORM): cv.string,
vol.Optional(CONF_FORECAST): cv.multi_select(DAYS),
vol.Optional(CONF_HOURLY_FORECAST): cv.multi_select(HOURS),
vol.Optional(CONF_MONITORED_CONDITIONS, default=None): cv.multi_select(
ALL_CONDITIONS
),
}
)
async def async_setup_platform(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Import the platform into a config entry."""
_LOGGER.warning(
"Configuration of Pirate Weather sensor in YAML is deprecated "
"Your existing configuration has been imported into the UI automatically "
"and can be safely removed from your configuration.yaml file"
)
# Define as a sensor platform
config_entry[PW_PLATFORM] = [PW_PLATFORMS[0]]
# Set as no rounding for compatability
config_entry[PW_ROUND] = "No"
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=config_entry
)
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Pirate Weather sensor entities based on a config entry."""
domain_data = hass.data[DOMAIN][config_entry.entry_id]
name = domain_data[CONF_NAME]
weather_coordinator = domain_data[ENTRY_WEATHER_COORDINATOR]
conditions = domain_data[CONF_MONITORED_CONDITIONS]
forecast_days = domain_data[CONF_FORECAST]
forecast_hours = domain_data[CONF_HOURLY_FORECAST]
service_id = config_entry.unique_id or config_entry.entry_id
# Round Output
outputRound = domain_data[PW_ROUND]
sensors: list[PirateWeatherSensor] = []
for condition in conditions:
# Save units for conversion later
requestUnits = domain_data[CONF_UNITS]
sensorDescription = SENSOR_TYPES[condition]
if condition in DEPRECATED_SENSOR_TYPES:
_LOGGER.warning("Monitored condition %s is deprecated", condition)
if (
not sensorDescription.forecast_mode
or "currently" in sensorDescription.forecast_mode
):
unique_id = f"{config_entry.unique_id}-sensor-{condition}"
sensors.append(
PirateWeatherSensor(
weather_coordinator,
condition,
name,
unique_id,
forecast_day=None,
forecast_hour=None,
description=sensorDescription,
requestUnits=requestUnits,
outputRound=outputRound,
service_id=service_id,
)
)
if forecast_days is not None and "daily" in sensorDescription.forecast_mode:
for forecast_day in forecast_days:
unique_id = (
f"{config_entry.unique_id}-sensor-{condition}-daily-{forecast_day}"
)
sensors.append(
PirateWeatherSensor(
weather_coordinator,
condition,
name,
unique_id,
forecast_day=int(forecast_day),
forecast_hour=None,
description=sensorDescription,
requestUnits=requestUnits,
outputRound=outputRound,
service_id=service_id,
)
)
if forecast_hours is not None and "hourly" in sensorDescription.forecast_mode:
for forecast_h in forecast_hours:
unique_id = (
f"{config_entry.unique_id}-sensor-{condition}-hourly-{forecast_h}"
)
sensors.append(
PirateWeatherSensor(
weather_coordinator,
condition,
name,
unique_id,
forecast_day=None,
forecast_hour=int(forecast_h),
description=sensorDescription,
requestUnits=requestUnits,
outputRound=outputRound,
service_id=service_id,
)
)
async_add_entities(sensors)
class PirateWeatherSensor(SensorEntity):
"""Class for an Pirate Weather sensor."""
# _attr_should_poll = False
_attr_attribution = ATTRIBUTION
entity_description: PirateWeatherSensorEntityDescription
def __init__(
self,
weather_coordinator: WeatherUpdateCoordinator,
condition: str,
name: str,
unique_id,
forecast_day: int,
forecast_hour: int,
description: PirateWeatherSensorEntityDescription,
requestUnits: str,
outputRound: str,
service_id: str,
) -> None:
"""Initialize the sensor."""
self.client_name = name
self.entity_description = description
self.description = description
self._weather_coordinator = weather_coordinator
self._attr_unique_id = unique_id
self._attr_name = name
self._attr_device_info = DeviceInfo(
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, service_id)},
manufacturer=MANUFACTURER,
name=name,
)
self.forecast_day = forecast_day
self.forecast_hour = forecast_hour
self.requestUnits = requestUnits
self.outputRound = outputRound
self.type = condition
self._icon = None
self._alerts = None
self._name = description.name
@property
def name(self):
"""Return the name of the sensor."""
if self.forecast_day is not None:
return f"{self.client_name} {self._name} {self.forecast_day}d"
if self.forecast_hour is not None:
return f"{self.client_name} {self._name} {self.forecast_hour}h"
return f"{self.client_name} {self._name}"
@property
def available(self) -> bool:
"""Return if weather data is available from Pirate Weather."""
return self._weather_coordinator.data is not None
@property
def attribution(self):
"""Return the attribution."""
return ATTRIBUTION
@property
def native_unit_of_measurement(self):
"""Return the unit of measurement of this entity, if any."""
unit_key = MAP_UNIT_SYSTEM.get(self.unit_system, "si_unit")
self._attr_native_unit_of_measurement = getattr(
self.entity_description, unit_key
)
return self._attr_native_unit_of_measurement
@property
def unit_system(self):
"""Return the unit system of this entity."""
return self.requestUnits
@property
def entity_picture(self) -> str | None:
"""Return the entity picture to use in the frontend, if any."""
if self._icon is None or "summary" not in self.entity_description.key:
return None
if self._icon in CONDITION_PICTURES:
return CONDITION_PICTURES[self._icon].entity_picture
return None
def update_unit_of_measurement(self) -> None:
"""Update units based on unit system."""
unit_key = MAP_UNIT_SYSTEM.get(self.unit_system, "si_unit")
self._attr_native_unit_of_measurement = getattr(
self.entity_description, unit_key
)
@property
def icon(self) -> str | None:
"""Icon to use in the frontend, if any."""
if (
"summary" in self.entity_description.key
and self._icon in CONDITION_PICTURES
):
return CONDITION_PICTURES[self._icon].icon
return self.entity_description.icon
@property
def extra_state_attributes(self):
"""Return the state attributes."""
if self.type == "alerts":
extraATTR = self._alerts
extraATTR[ATTR_ATTRIBUTION] = ATTRIBUTION
else:
extraATTR = {ATTR_ATTRIBUTION: ATTRIBUTION}
return extraATTR
@property
def native_value(self) -> StateType:
"""Return the state of the device."""
self.update_unit_of_measurement()
if self.type == "alerts":
data = self._weather_coordinator.data.alerts()
alerts = {}
if data is None:
self._alerts = alerts
return data
multiple_alerts = len(data) > 1
for i, alert in enumerate(data):
for attr in ALERTS_ATTRS:
if multiple_alerts:
dkey = f"{attr}_{i!s}"
else:
dkey = attr
alertsAttr = getattr(alert, attr)
# Convert time to string using dt_util
if isinstance(alertsAttr, int):
alertsAttr = dt_util.as_local(
dt_util.utc_from_timestamp(alertsAttr)
).isoformat()
alerts[dkey] = alertsAttr
self._alerts = alerts
native_val = len(data)
elif self.type in [
"hrrr_subh_update_time",
"hrrr_0_18_update_time",
"nbm_update_time",
"nbm_fire_update_time",
"hrrr_18_48_update_time",
"gfs_update_time",
"gefs_update_time",
]:
try:
flags = self._weather_coordinator.data.flags()
model_time_string = flags.sourceTimes[self.entity_description.key]
native_val = datetime.datetime.strptime(
model_time_string[0:-1], "%Y-%m-%d %H"
).replace(tzinfo=datetime.UTC)
except KeyError:
native_val = None
elif self.type == "minutely_summary":
native_val = getattr(
self._weather_coordinator.data.minutely(), "summary", ""
)
self._icon = getattr(self._weather_coordinator.data.minutely(), "icon", "")
elif self.type == "hourly_summary":
native_val = getattr(self._weather_coordinator.data.hourly(), "summary", "")
self._icon = getattr(self._weather_coordinator.data.hourly(), "icon", "")
elif self.forecast_hour is not None:
hourly = self._weather_coordinator.data.hourly()
if hasattr(hourly, "data"):
native_val = self.get_state(hourly.data[self.forecast_hour].d)
else:
native_val = 0
elif self.type == "daily_summary":
native_val = getattr(self._weather_coordinator.data.daily(), "summary", "")
self._icon = getattr(self._weather_coordinator.data.daily(), "icon", "")
elif self.forecast_day is not None:
daily = self._weather_coordinator.data.daily()
if hasattr(daily, "data"):
native_val = self.get_state(daily.data[self.forecast_day].d)
else:
native_val = 0
else:
currently = self._weather_coordinator.data.currently()
native_val = self.get_state(currently.d)
# self._state = native_val
return native_val
def get_state(self, data):
"""Return a new state based on the type.
If the sensor type is unknown, the current state is returned.
"""
if self.type == "fire_risk_level":
if self.forecast_hour is not None:
state = data.get("fireIndex")
elif self.forecast_day is not None:
state = data.get("fireIndexMax")
else:
state = data.get("fireIndex")
else:
lookup_type = convert_to_camel(self.type)
state = data.get(lookup_type)
# If the sensor is numeric and the data is -999 set return None instead of -999
if isinstance(state, (int, float)) and state == -999:
return None
if state is None:
return state
if "summary" in self.type:
self._icon = getattr(data, "icon", "")
# If output rounding is requested, round to nearest integer
if self.outputRound == "Yes":
roundingVal = 0
roundingPrecip = 2
else:
roundingVal = 2
roundingPrecip = 4
# Some state data needs to be rounded to whole values or converted to
# percentages
if self.type in ["precip_probability", "cloud_cover", "humidity"]:
state = int(state * 100)
# Convert unix times to datetimes times
if self.type in [
"temperature_high_time",
"temperature_min_time",
"apparent_temperature_high_time",
"apparent_temperature_low_time",
"sunrise_time",
"sunset_time",
"time",
]:
outState = datetime.datetime.fromtimestamp(state, datetime.UTC)
elif self.type == "fire_risk_level":
outState = fire_index(state)
elif self.type in [
"dew_point",
"temperature",
"apparent_temperature",
"temperature_low",
"apparent_temperature_low",
"temperature_min",
"apparent_temperature_min",
"temperature_high",
"apparent_temperature_high",
"temperature_max",
"apparent_temperature_max",
"pressure",
"ozone",
"fire_index",
"fire_index_max",
"uv_index",
"air_quality_index",
"wind_speed",
"wind_gust",
"visibility",
"nearest_storm_distance",
"smoke",
"smoke_max",
"solar",
"solar_max",
]:
if roundingVal == 0:
outState = int(round(state, roundingVal))
else:
outState = round(state, roundingVal)
elif self.type in [
"precip_accumulation",
"liquid_accumulation",
"snow_accumulation",
"ice_accumulation",
"precip_intensity",
"precip_intensity_max",
"current_day_liquid",
"current_day_snow",
"current_day_ice",
"rain_intensity",
"rain_intensity_max",
"snow_intensity",
"snow_intensity_max",
"ice_intensity",
"ice_intensity_max",
]:
# Convert snow intensity from cm/h to mm/h for non-US units
if (
self.type in ["snow_intensity", "snow_intensity_max"]
and self.unit_system != "us"
):
state = state * 10
outState = round(state, roundingPrecip)
else:
outState = state
return outState
async def async_added_to_hass(self) -> None:
"""Connect to dispatcher listening for entity data notifications."""
self.async_on_remove(
self._weather_coordinator.async_add_listener(self.async_write_ha_state)
)
# async def async_update(self) -> None:
# """Get the latest data from PW and updates the states."""
# await self._weather_coordinator.async_request_refresh()
def convert_to_camel(data):
"""Convert snake case (foo_bar_bat) to camel case (fooBarBat).
This is not pythonic, but needed for certain situations.
"""
components = data.split("_")
capital_components = "".join(x.title() for x in components[1:])
return f"{components[0]}{capital_components}"
def fire_index(fire_index):
"""Convert numeric fire index to a textual value."""
if fire_index == -999:
outState = "N/A"
elif fire_index >= 30:
outState = "Extreme"
elif fire_index >= 20:
outState = "Very High"
elif fire_index >= 10:
outState = "High"
elif fire_index >= 5:
outState = "Moderate"
else:
outState = "Low"
return outState