def forecast(self) -> list[Forecast] | None: """Return the forecast in native units.""" if self.coordinator.data.daily is None: return None forecasts: list[Forecast] = [] daily = self.coordinator.data.daily for index, time in enumerate(self.coordinator.data.daily.time): forecast = Forecast(datetime=time.isoformat(), ) if daily.weathercode is not None: forecast["condition"] = WMO_TO_HA_CONDITION_MAP.get( daily.weathercode[index]) if daily.precipitation_sum is not None: forecast["precipitation"] = daily.precipitation_sum[index] if daily.temperature_2m_max is not None: forecast["temperature"] = daily.temperature_2m_max[index] if daily.temperature_2m_min is not None: forecast["templow"] = daily.temperature_2m_min[index] if daily.wind_direction_10m_dominant is not None: forecast["wind_bearing"] = daily.wind_direction_10m_dominant[ index] if daily.wind_speed_10m_max is not None: forecast["wind_speed"] = daily.wind_speed_10m_max[index] forecasts.append(forecast) return forecasts
def _build_forecast_data(timestep: Timestep) -> Forecast: data = Forecast(datetime=timestep.date.isoformat()) if timestep.weather: data[ATTR_FORECAST_CONDITION] = _get_weather_condition( timestep.weather.value) if timestep.precipitation: data[ ATTR_FORECAST_PRECIPITATION_PROBABILITY] = timestep.precipitation.value if timestep.temperature: data[ATTR_FORECAST_NATIVE_TEMP] = timestep.temperature.value if timestep.wind_direction: data[ATTR_FORECAST_WIND_BEARING] = timestep.wind_direction.value if timestep.wind_speed: data[ATTR_FORECAST_NATIVE_WIND_SPEED] = timestep.wind_speed.value return data
def forecast(self) -> list[Forecast]: """Return the forecast.""" reftime = dt_util.now().replace(hour=16, minute=00) forecast_data = [] for entry in self._forecast: data_dict = Forecast( datetime=reftime.isoformat(), condition=entry[0], precipitation=entry[1], temperature=entry[2], templow=entry[3], precipitation_probability=entry[4], ) reftime = reftime + timedelta(hours=4) forecast_data.append(data_dict) return forecast_data
def __init__(self) -> None: """Initiate Entity.""" super().__init__() self._attr_condition = ATTR_CONDITION_SUNNY self._attr_precipitation_unit = LENGTH_MILLIMETERS self._attr_pressure = 10 self._attr_pressure_unit = PRESSURE_HPA self._attr_temperature = 20 self._attr_temperature_unit = TEMP_CELSIUS self._attr_visibility = 30 self._attr_visibility_unit = LENGTH_KILOMETERS self._attr_wind_speed = 3 self._attr_wind_speed_unit = SPEED_METERS_PER_SECOND self._attr_forecast = [ Forecast( datetime=datetime(2022, 6, 20, 20, 00, 00), precipitation=1, temperature=20, ) ]
def parse_hour_forecast(data: any, is_metric: bool) -> Forecast: """Parse hour forecast data.""" if data is None: return None # Sometimes the hourly forecast just has empty condition, skip if `time` element is missing. hour_forecast_time = data.get("time") if hour_forecast_time is None: return None condition = data.get("condition", {}) hour_forecast_time = datetime_to_iso(hour_forecast_time) is_day = to_int(data.get("is_day", "1")) == 1 return Forecast( datetime=hour_forecast_time, temperature=to_float(data.get("temp_c" if is_metric else "temp_f")), precipitation_probability=data.get("chance_of_rain"), wind_speed=to_float(data.get("wind_mph" if is_metric else "wind_kph")), condition=parse_condition_code(condition.get("code"), is_day), )
async def test_attr_compatibility(hass: HomeAssistant) -> None: """Test the _attr attributes in compatibility mode.""" weather = MockWeatherEntityCompat() weather.hass = hass assert weather.condition == ATTR_CONDITION_SUNNY assert weather._precipitation_unit == LENGTH_MILLIMETERS assert weather.pressure == 10 assert weather._pressure_unit == PRESSURE_HPA assert weather.temperature == 20 assert weather._temperature_unit == TEMP_CELSIUS assert weather.visibility == 30 assert weather.visibility_unit == LENGTH_KILOMETERS assert weather.wind_speed == 3 assert weather._wind_speed_unit == SPEED_KILOMETERS_PER_HOUR forecast_entry = [ Forecast( datetime=datetime(2022, 6, 20, 20, 00, 00), precipitation=1, temperature=20, ) ] assert weather.forecast == forecast_entry assert weather.state_attributes == { ATTR_FORECAST: forecast_entry, ATTR_WEATHER_PRESSURE: 10.0, ATTR_WEATHER_PRESSURE_UNIT: PRESSURE_HPA, ATTR_WEATHER_TEMPERATURE: 20.0, ATTR_WEATHER_TEMPERATURE_UNIT: TEMP_CELSIUS, ATTR_WEATHER_VISIBILITY: 30.0, ATTR_WEATHER_VISIBILITY_UNIT: LENGTH_KILOMETERS, ATTR_WEATHER_WIND_SPEED: 3.0 * 3.6, ATTR_WEATHER_WIND_SPEED_UNIT: SPEED_KILOMETERS_PER_HOUR, ATTR_WEATHER_PRECIPITATION_UNIT: LENGTH_MILLIMETERS, }
def parse_forecast(self, json): """Parse the forecast JSON data.""" entries = [] if not json: _LOGGER.warning("No forecast data received.") return entries _LOGGER.debug(json) forecastday_array = json.get("forecastday") if not forecastday_array: _LOGGER.warning("No day forecast found in data.") return entries is_metric = self._is_metric for forecastday in forecastday_array: # `date` is in YYYY-MM-DD format # `date_epoch` is unix time day = forecastday.get("day") if self._hourly_forecast: hour_array = forecastday.get("hour") hour_forecast_with_no_data = 0 for hour in hour_array: # Skip hourly forecast if it is empty .. `time` is missing hour_entry = self.parse_hour_forecast(hour, is_metric) if hour_entry is None: hour_forecast_with_no_data += 1 else: entries.append(hour_entry) if hour_forecast_with_no_data > 0: _LOGGER.warning( "%d hourly forecasts found for %s with no data.", hour_forecast_with_no_data, self._name, ) else: condition = day.get("condition", {}) is_day = to_int(day.get("is_day", "1")) == 1 day_entry = Forecast( datetime=datetime_to_iso(forecastday.get("date")), temperature=to_float( day.get("maxtemp_c" if is_metric else "maxtemp_f") ), templow=to_float( day.get("mintemp_c" if is_metric else "mintemp_f") ), precipitation=to_float( day.get("totalprecip_mm" if is_metric else "totalprecip_in") ), precipitation_probability=day.get("daily_chance_of_rain"), wind_speed=to_float( day.get("maxwind_kph" if is_metric else "maxwind_mph") ), condition=parse_condition_code(condition.get("code"), is_day), ) entries.append(day_entry) _LOGGER.info("Loaded %s forecast values for %s.", len(entries), self._name) return entries