Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3f40b7369 | ||
|
|
b36d77b4da | ||
|
|
566f296835 |
@@ -4,8 +4,11 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.components.weather import WeatherEntityFeature
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant, SupportsResponse
|
||||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||||
|
|
||||||
from .const import DOMAIN, PLATFORMS
|
from .const import DOMAIN, PLATFORMS
|
||||||
@@ -15,6 +18,47 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
|
|
||||||
type BaiduWeatherConfigEntry = ConfigEntry[BaiduWeatherCoordinator]
|
type BaiduWeatherConfigEntry = ConfigEntry[BaiduWeatherCoordinator]
|
||||||
|
|
||||||
|
SERVICE_GET_FORECAST = "get_forecast"
|
||||||
|
|
||||||
|
|
||||||
|
async def _async_register_get_forecast_service(hass: HomeAssistant) -> None:
|
||||||
|
"""Register weather.get_forecast (singular) service if not already registered.
|
||||||
|
|
||||||
|
HA core only registers weather.get_forecasts (plural).
|
||||||
|
Some LLM integrations (e.g. Extended OpenAI Conversation) may call
|
||||||
|
the singular form, which causes a ServiceNotFound error.
|
||||||
|
This registers the singular form as an alias.
|
||||||
|
"""
|
||||||
|
if hass.services.has_service("weather", SERVICE_GET_FORECAST):
|
||||||
|
return
|
||||||
|
|
||||||
|
from homeassistant.components.weather import async_get_forecasts_service
|
||||||
|
from homeassistant.components.weather.const import DATA_COMPONENT
|
||||||
|
|
||||||
|
component = hass.data.get(DATA_COMPONENT)
|
||||||
|
if component is None:
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Weather component not initialized, cannot register get_forecast service"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
component.async_register_entity_service(
|
||||||
|
SERVICE_GET_FORECAST,
|
||||||
|
{
|
||||||
|
vol.Optional("type", default="daily"): vol.In(
|
||||||
|
("daily", "hourly", "twice_daily")
|
||||||
|
)
|
||||||
|
},
|
||||||
|
async_get_forecasts_service,
|
||||||
|
required_features=[
|
||||||
|
WeatherEntityFeature.FORECAST_DAILY,
|
||||||
|
WeatherEntityFeature.FORECAST_HOURLY,
|
||||||
|
WeatherEntityFeature.FORECAST_TWICE_DAILY,
|
||||||
|
],
|
||||||
|
supports_response=SupportsResponse.OPTIONAL,
|
||||||
|
)
|
||||||
|
_LOGGER.info("Registered weather.get_forecast service (singular form alias)")
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant, entry: BaiduWeatherConfigEntry
|
hass: HomeAssistant, entry: BaiduWeatherConfigEntry
|
||||||
@@ -35,6 +79,9 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
|
|
||||||
|
# Register weather.get_forecast (singular) service for LLM compatibility
|
||||||
|
await _async_register_get_forecast_service(hass)
|
||||||
|
|
||||||
entry.async_on_unload(entry.add_update_listener(_async_update_listener))
|
entry.async_on_unload(entry.add_update_listener(_async_update_listener))
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"domain": "hass_weather_baidu",
|
"domain": "hass_weather_baidu",
|
||||||
"name": "百度天气",
|
"name": "百度天气",
|
||||||
"codeowners": ["@your-github-username"],
|
"codeowners": ["@xyzmos"],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"dependencies": [],
|
"dependencies": ["weather"],
|
||||||
"documentation": "https://github.com/your-github-username/hass_weather_baidu",
|
"documentation": "https://github.com/xyzmos/hass_weather_baidu",
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"issue_tracker": "https://github.com/your-github-username/hass_weather_baidu/issues",
|
"issue_tracker": "https://github.com/xyzmos/hass_weather_baidu/issues",
|
||||||
"requirements": ["aiohttp>=3.8.0"],
|
"requirements": ["aiohttp>=3.8.0"],
|
||||||
"version": "1.0.0"
|
"version": "1.0.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""Sensor entities for Baidu Weather integration - Weather Alerts."""
|
"""Sensor entities for Baidu Weather integration - Weather Alerts & Forecasts."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@@ -6,11 +6,10 @@ import logging
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
SensorDeviceClass,
|
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
@@ -20,12 +19,18 @@ from .const import (
|
|||||||
CONF_LOCATION_NAME,
|
CONF_LOCATION_NAME,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
KEY_ALERTS,
|
KEY_ALERTS,
|
||||||
KEY_INDEXES,
|
KEY_FORECASTS,
|
||||||
|
KEY_NOW,
|
||||||
)
|
)
|
||||||
from .coordinator import BaiduWeatherCoordinator
|
from .coordinator import BaiduWeatherCoordinator
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Day labels for forecast sensors (index 0 = today)
|
||||||
|
_DAY_LABELS_CN = ["今天", "明天", "后天", "大后天", "第五天"]
|
||||||
|
_DAY_LABELS_EN = ["Today", "Tomorrow", "Day After Tomorrow", "In 3 Days", "In 4 Days"]
|
||||||
|
_DAY_KEYS = ["forecast_today", "forecast_tomorrow", "forecast_day2", "forecast_day3", "forecast_day4"]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@@ -41,6 +46,14 @@ async def async_setup_entry(
|
|||||||
BaiduWeatherAqiSensor(coordinator, entry, location_name),
|
BaiduWeatherAqiSensor(coordinator, entry, location_name),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Create daily forecast sensors (today + next 4 days = 5 sensors)
|
||||||
|
for day_index in range(5):
|
||||||
|
entities.append(
|
||||||
|
BaiduWeatherDailyForecastSensor(
|
||||||
|
coordinator, entry, location_name, day_index
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
@@ -187,3 +200,137 @@ class BaiduWeatherAqiSensor(
|
|||||||
attrs["aqi_level"] = "严重污染"
|
attrs["aqi_level"] = "严重污染"
|
||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
|
class BaiduWeatherDailyForecastSensor(
|
||||||
|
CoordinatorEntity[BaiduWeatherCoordinator], SensorEntity
|
||||||
|
):
|
||||||
|
"""Sensor entity for a single day's weather forecast.
|
||||||
|
|
||||||
|
Each instance represents one day (today, tomorrow, day after tomorrow, etc.).
|
||||||
|
The sensor state is a human-readable summary like "多云 12~20°C".
|
||||||
|
Extra attributes contain detailed forecast fields so that voice assistants
|
||||||
|
and LLM integrations can read the forecast directly from entity state.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
_attr_icon = "mdi:weather-partly-cloudy"
|
||||||
|
_attr_attribution = ATTRIBUTION
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: BaiduWeatherCoordinator,
|
||||||
|
entry: ConfigEntry,
|
||||||
|
location_name: str,
|
||||||
|
day_index: int,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the daily forecast sensor.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
day_index: 0 = today, 1 = tomorrow, 2 = day after tomorrow, etc.
|
||||||
|
"""
|
||||||
|
super().__init__(coordinator)
|
||||||
|
self._entry = entry
|
||||||
|
self._day_index = day_index
|
||||||
|
self._attr_translation_key = _DAY_KEYS[day_index]
|
||||||
|
self._attr_unique_id = f"{DOMAIN}_{entry.entry_id}_{_DAY_KEYS[day_index]}"
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
entry_type=DeviceEntryType.SERVICE,
|
||||||
|
identifiers={(DOMAIN, entry.entry_id)},
|
||||||
|
manufacturer="百度地图",
|
||||||
|
name=f"百度天气 - {location_name}",
|
||||||
|
configuration_url="https://lbsyun.baidu.com/",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_forecast_data(self) -> dict[str, Any] | None:
|
||||||
|
"""Get the forecast data for this day by index."""
|
||||||
|
if self.coordinator.data is None:
|
||||||
|
return None
|
||||||
|
forecasts = self.coordinator.data.get(KEY_FORECASTS, [])
|
||||||
|
if self._day_index < len(forecasts):
|
||||||
|
return forecasts[self._day_index]
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def native_value(self) -> str | None:
|
||||||
|
"""Return a human-readable weather summary for this day.
|
||||||
|
|
||||||
|
Format: "多云 12~20°C" or "晴转多云 8~18°C"
|
||||||
|
This makes it easy for voice assistants to read aloud.
|
||||||
|
"""
|
||||||
|
fc = self._get_forecast_data()
|
||||||
|
if fc is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
text_day = fc.get("text_day", "")
|
||||||
|
text_night = fc.get("text_night", "")
|
||||||
|
high = fc.get("high")
|
||||||
|
low = fc.get("low")
|
||||||
|
|
||||||
|
# Build condition text
|
||||||
|
if text_day and text_night and text_day != text_night:
|
||||||
|
condition_text = f"{text_day}转{text_night}"
|
||||||
|
elif text_day:
|
||||||
|
condition_text = text_day
|
||||||
|
elif text_night:
|
||||||
|
condition_text = text_night
|
||||||
|
else:
|
||||||
|
condition_text = "未知"
|
||||||
|
|
||||||
|
# Build temperature range
|
||||||
|
if low is not None and high is not None:
|
||||||
|
temp_text = f"{low}~{high}°C"
|
||||||
|
elif high is not None:
|
||||||
|
temp_text = f"最高{high}°C"
|
||||||
|
elif low is not None:
|
||||||
|
temp_text = f"最低{low}°C"
|
||||||
|
else:
|
||||||
|
temp_text = ""
|
||||||
|
|
||||||
|
if temp_text:
|
||||||
|
return f"{condition_text} {temp_text}"
|
||||||
|
return condition_text
|
||||||
|
|
||||||
|
@property
|
||||||
|
def extra_state_attributes(self) -> dict[str, Any]:
|
||||||
|
"""Return detailed forecast attributes for this day.
|
||||||
|
|
||||||
|
These attributes are designed to be easily readable by LLM integrations.
|
||||||
|
"""
|
||||||
|
attrs: dict[str, Any] = {}
|
||||||
|
fc = self._get_forecast_data()
|
||||||
|
if fc is None:
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
# Date
|
||||||
|
if fc.get("date"):
|
||||||
|
attrs["date"] = fc["date"]
|
||||||
|
|
||||||
|
# Day label (今天/明天/后天...)
|
||||||
|
attrs["day_label"] = _DAY_LABELS_CN[self._day_index]
|
||||||
|
|
||||||
|
# Conditions
|
||||||
|
if fc.get("text_day"):
|
||||||
|
attrs["condition_day"] = fc["text_day"]
|
||||||
|
if fc.get("text_night"):
|
||||||
|
attrs["condition_night"] = fc["text_night"]
|
||||||
|
|
||||||
|
# Temperatures
|
||||||
|
if fc.get("high") is not None:
|
||||||
|
attrs["temperature_high"] = fc["high"]
|
||||||
|
if fc.get("low") is not None:
|
||||||
|
attrs["temperature_low"] = fc["low"]
|
||||||
|
|
||||||
|
# Wind - Day
|
||||||
|
if fc.get("wc_day"):
|
||||||
|
attrs["wind_class_day"] = fc["wc_day"]
|
||||||
|
if fc.get("wd_day"):
|
||||||
|
attrs["wind_direction_day"] = fc["wd_day"]
|
||||||
|
|
||||||
|
# Wind - Night
|
||||||
|
if fc.get("wc_night"):
|
||||||
|
attrs["wind_class_night"] = fc["wc_night"]
|
||||||
|
if fc.get("wd_night"):
|
||||||
|
attrs["wind_direction_night"] = fc["wd_night"]
|
||||||
|
|
||||||
|
return attrs
|
||||||
|
|||||||
@@ -69,6 +69,21 @@
|
|||||||
},
|
},
|
||||||
"aqi": {
|
"aqi": {
|
||||||
"name": "空气质量指数"
|
"name": "空气质量指数"
|
||||||
|
},
|
||||||
|
"forecast_today": {
|
||||||
|
"name": "今天天气预报"
|
||||||
|
},
|
||||||
|
"forecast_tomorrow": {
|
||||||
|
"name": "明天天气预报"
|
||||||
|
},
|
||||||
|
"forecast_day2": {
|
||||||
|
"name": "后天天气预报"
|
||||||
|
},
|
||||||
|
"forecast_day3": {
|
||||||
|
"name": "大后天天气预报"
|
||||||
|
},
|
||||||
|
"forecast_day4": {
|
||||||
|
"name": "第五天天气预报"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,21 @@
|
|||||||
},
|
},
|
||||||
"aqi": {
|
"aqi": {
|
||||||
"name": "Air Quality Index"
|
"name": "Air Quality Index"
|
||||||
|
},
|
||||||
|
"forecast_today": {
|
||||||
|
"name": "Today's Weather Forecast"
|
||||||
|
},
|
||||||
|
"forecast_tomorrow": {
|
||||||
|
"name": "Tomorrow's Weather Forecast"
|
||||||
|
},
|
||||||
|
"forecast_day2": {
|
||||||
|
"name": "Day After Tomorrow Forecast"
|
||||||
|
},
|
||||||
|
"forecast_day3": {
|
||||||
|
"name": "3-Day Forecast"
|
||||||
|
},
|
||||||
|
"forecast_day4": {
|
||||||
|
"name": "4-Day Forecast"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,21 @@
|
|||||||
},
|
},
|
||||||
"aqi": {
|
"aqi": {
|
||||||
"name": "空气质量指数"
|
"name": "空气质量指数"
|
||||||
|
},
|
||||||
|
"forecast_today": {
|
||||||
|
"name": "今天天气预报"
|
||||||
|
},
|
||||||
|
"forecast_tomorrow": {
|
||||||
|
"name": "明天天气预报"
|
||||||
|
},
|
||||||
|
"forecast_day2": {
|
||||||
|
"name": "后天天气预报"
|
||||||
|
},
|
||||||
|
"forecast_day3": {
|
||||||
|
"name": "大后天天气预报"
|
||||||
|
},
|
||||||
|
"forecast_day4": {
|
||||||
|
"name": "第五天天气预报"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from homeassistant.components.weather import (
|
|||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
UnitOfLength,
|
||||||
UnitOfPressure,
|
UnitOfPressure,
|
||||||
UnitOfSpeed,
|
UnitOfSpeed,
|
||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
@@ -27,8 +28,10 @@ from .const import (
|
|||||||
CONDITION_MAP,
|
CONDITION_MAP,
|
||||||
CONF_LOCATION_NAME,
|
CONF_LOCATION_NAME,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
KEY_ALERTS,
|
||||||
KEY_FORECAST_HOURS,
|
KEY_FORECAST_HOURS,
|
||||||
KEY_FORECASTS,
|
KEY_FORECASTS,
|
||||||
|
KEY_INDEXES,
|
||||||
KEY_NOW,
|
KEY_NOW,
|
||||||
WIND_BEARING_MAP,
|
WIND_BEARING_MAP,
|
||||||
WIND_SPEED_MAP,
|
WIND_SPEED_MAP,
|
||||||
@@ -144,26 +147,17 @@ class BaiduWeatherEntity(CoordinatorEntity[BaiduWeatherCoordinator], WeatherEnti
|
|||||||
return self._now_data.get("clouds")
|
return self._now_data.get("clouds")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def visibility(self) -> float | None:
|
def native_visibility(self) -> float | None:
|
||||||
"""Return the visibility in km."""
|
"""Return visibility in km."""
|
||||||
vis = self._now_data.get("vis")
|
vis = self._now_data.get("vis")
|
||||||
if vis is None:
|
if vis is None:
|
||||||
return None
|
return None
|
||||||
# API returns meters, convert to km
|
# API returns meters, convert to km
|
||||||
return vis / 1000.0
|
return vis / 1000.0
|
||||||
|
|
||||||
@property
|
|
||||||
def native_visibility(self) -> float | None:
|
|
||||||
"""Return visibility in km."""
|
|
||||||
vis = self._now_data.get("vis")
|
|
||||||
if vis is None:
|
|
||||||
return None
|
|
||||||
return vis / 1000.0
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_visibility_unit(self) -> str:
|
def native_visibility_unit(self) -> str:
|
||||||
"""Return the visibility unit."""
|
"""Return the visibility unit."""
|
||||||
from homeassistant.const import UnitOfLength
|
|
||||||
return UnitOfLength.KILOMETERS
|
return UnitOfLength.KILOMETERS
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -183,7 +177,13 @@ class BaiduWeatherEntity(CoordinatorEntity[BaiduWeatherCoordinator], WeatherEnti
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self) -> dict[str, Any]:
|
def extra_state_attributes(self) -> dict[str, Any]:
|
||||||
"""Return extra state attributes for voice assistants."""
|
"""Return extra state attributes for voice assistants.
|
||||||
|
|
||||||
|
Includes forecast data so that LLM integrations (e.g. Extended OpenAI
|
||||||
|
Conversation) can read forecasts directly from entity state without
|
||||||
|
needing to call the weather.get_forecasts service (which requires
|
||||||
|
return_response=True that many LLM integrations don't support).
|
||||||
|
"""
|
||||||
attrs: dict[str, Any] = {}
|
attrs: dict[str, Any] = {}
|
||||||
now = self._now_data
|
now = self._now_data
|
||||||
|
|
||||||
@@ -210,6 +210,88 @@ class BaiduWeatherEntity(CoordinatorEntity[BaiduWeatherCoordinator], WeatherEnti
|
|||||||
if now.get("uptime") is not None:
|
if now.get("uptime") is not None:
|
||||||
attrs["update_time"] = now["uptime"]
|
attrs["update_time"] = now["uptime"]
|
||||||
|
|
||||||
|
# --- Daily forecast (for voice assistants / LLM) ---
|
||||||
|
if self.coordinator.data is not None:
|
||||||
|
forecasts_raw = self.coordinator.data.get(KEY_FORECASTS, [])
|
||||||
|
if forecasts_raw:
|
||||||
|
forecast_list = []
|
||||||
|
for fc in forecasts_raw:
|
||||||
|
date_str = fc.get("date", "")
|
||||||
|
entry: dict[str, Any] = {"date": date_str}
|
||||||
|
if fc.get("text_day"):
|
||||||
|
entry["condition_day"] = fc["text_day"]
|
||||||
|
if fc.get("text_night"):
|
||||||
|
entry["condition_night"] = fc["text_night"]
|
||||||
|
if fc.get("high") is not None:
|
||||||
|
entry["temperature_high"] = fc["high"]
|
||||||
|
if fc.get("low") is not None:
|
||||||
|
entry["temperature_low"] = fc["low"]
|
||||||
|
if fc.get("wc_day"):
|
||||||
|
entry["wind_class_day"] = fc["wc_day"]
|
||||||
|
if fc.get("wd_day"):
|
||||||
|
entry["wind_direction_day"] = fc["wd_day"]
|
||||||
|
if fc.get("wc_night"):
|
||||||
|
entry["wind_class_night"] = fc["wc_night"]
|
||||||
|
if fc.get("wd_night"):
|
||||||
|
entry["wind_direction_night"] = fc["wd_night"]
|
||||||
|
forecast_list.append(entry)
|
||||||
|
attrs["forecast_daily"] = forecast_list
|
||||||
|
|
||||||
|
# --- Hourly forecast ---
|
||||||
|
hours_raw = self.coordinator.data.get(KEY_FORECAST_HOURS, [])
|
||||||
|
if hours_raw:
|
||||||
|
hourly_list = []
|
||||||
|
for hour in hours_raw:
|
||||||
|
entry = {}
|
||||||
|
if hour.get("data_time"):
|
||||||
|
entry["datetime"] = hour["data_time"]
|
||||||
|
if hour.get("text"):
|
||||||
|
entry["condition"] = hour["text"]
|
||||||
|
if hour.get("temp_fc") is not None:
|
||||||
|
entry["temperature"] = hour["temp_fc"]
|
||||||
|
if hour.get("rh") is not None:
|
||||||
|
entry["humidity"] = hour["rh"]
|
||||||
|
if hour.get("wind_class"):
|
||||||
|
entry["wind_class"] = hour["wind_class"]
|
||||||
|
if hour.get("wind_dir"):
|
||||||
|
entry["wind_direction"] = hour["wind_dir"]
|
||||||
|
if hour.get("prec_1h") is not None:
|
||||||
|
entry["precipitation"] = hour["prec_1h"]
|
||||||
|
hourly_list.append(entry)
|
||||||
|
attrs["forecast_hourly"] = hourly_list
|
||||||
|
|
||||||
|
# --- Weather alerts ---
|
||||||
|
alerts = self.coordinator.data.get(KEY_ALERTS, [])
|
||||||
|
if alerts:
|
||||||
|
alert_list = []
|
||||||
|
for alert in alerts:
|
||||||
|
entry = {}
|
||||||
|
if alert.get("title"):
|
||||||
|
entry["title"] = alert["title"]
|
||||||
|
if alert.get("type"):
|
||||||
|
entry["type"] = alert["type"]
|
||||||
|
if alert.get("level"):
|
||||||
|
entry["level"] = alert["level"]
|
||||||
|
if alert.get("desc"):
|
||||||
|
entry["description"] = alert["desc"]
|
||||||
|
alert_list.append(entry)
|
||||||
|
attrs["alerts"] = alert_list
|
||||||
|
|
||||||
|
# --- Life indexes ---
|
||||||
|
indexes = self.coordinator.data.get(KEY_INDEXES, [])
|
||||||
|
if indexes:
|
||||||
|
index_list = []
|
||||||
|
for idx in indexes:
|
||||||
|
entry = {}
|
||||||
|
if idx.get("name"):
|
||||||
|
entry["name"] = idx["name"]
|
||||||
|
if idx.get("brief"):
|
||||||
|
entry["brief"] = idx["brief"]
|
||||||
|
if idx.get("detail"):
|
||||||
|
entry["detail"] = idx["detail"]
|
||||||
|
index_list.append(entry)
|
||||||
|
attrs["life_indexes"] = index_list
|
||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
async def async_forecast_daily(self) -> list[Forecast] | None:
|
async def async_forecast_daily(self) -> list[Forecast] | None:
|
||||||
|
|||||||
Reference in New Issue
Block a user