Skip to content

Commit

Permalink
Add forecast data 🌤
Browse files Browse the repository at this point in the history
  • Loading branch information
elboletaire committed Jun 8, 2024
1 parent cde5cf1 commit 05c079f
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 7 deletions.
7 changes: 5 additions & 2 deletions custom_components/weatherxm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_update_data():
"""Fetch data from API endpoint."""
try:
return await hass.async_add_executor_job(api.get_devices)
devices = await hass.async_add_executor_job(api.get_devices)
for device in devices:
device['forecast'] = await hass.async_add_executor_job(api.get_forecast_data, device['id'])
return devices
except Exception as err:
raise UpdateFailed(f"Error communicating with API: {err}")

Expand Down Expand Up @@ -64,4 +67,4 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:

async def update_listener(hass: HomeAssistant, entry: ConfigEntry):
"""Handle options update."""
await hass.config_entries.async_reload(entry.entry_id)
await hass.config_entries.async_reload(entry.entry_id)
82 changes: 77 additions & 5 deletions custom_components/weatherxm/weather.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import logging
from homeassistant.components.weather import WeatherEntity
from homeassistant.components.weather import (
WeatherEntity,
WeatherEntityFeature,
Forecast,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.helpers.entity import generate_entity_id

from homeassistant.const import (
UnitOfPrecipitationDepth,
UnitOfPressure,
UnitOfSpeed,
UnitOfTemperature,
)
from .const import DOMAIN
from .utils import async_setup_entities_list

Expand All @@ -15,7 +23,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e
device_id=device['id'],
alias=alias,
address=device['address'],
current_weather=device['current_weather']
current_weather=device['current_weather'],
forecast=device.get('forecast', [])
))
async_add_entities(entities, True)

Expand Down Expand Up @@ -79,14 +88,25 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e
}

class WeatherXMWeather(CoordinatorEntity, WeatherEntity):
def __init__(self, coordinator, entity_id, device_id, alias, address, current_weather):
""" WeatherXM Weather Entity """

_attr_native_precipitation_unit = UnitOfPrecipitationDepth.MILLIMETERS
_attr_native_pressure_unit = UnitOfPressure.HPA
_attr_native_wind_speed_unit = UnitOfSpeed.KILOMETERS_PER_HOUR
_attr_supported_features = (
WeatherEntityFeature.FORECAST_DAILY | WeatherEntityFeature.FORECAST_HOURLY
)
_attr_native_temperature_unit = UnitOfTemperature.CELSIUS

def __init__(self, coordinator, entity_id, device_id, alias, address, current_weather, forecast):
"""Initialize."""
super().__init__(coordinator)
self.entity_id = entity_id
self._device_id = device_id
self._address = address
self._alias = alias
self._current_weather = current_weather
self._forecast = forecast
self._attr_name = alias
self._attr_unique_id = alias

Expand Down Expand Up @@ -185,3 +205,55 @@ def state_attributes(self):
"wind_gust_speed": self.wind_gust_speed,
})
return data

@property
def forecast(self):
return {
"hourly": self.forecast_hourly[:24], # Limit to 24 hourly forecasts
"daily": self.forecast_daily[:7], # Limit to 7 daily forecasts
}

@property
def forecast_hourly(self):
forecasts = []
for daily in self._forecast:
for hourly in daily.get("hourly", []):
hourly_forecast = {
"datetime": hourly.get("timestamp"),
"temperature": hourly.get("temperature"),
"precipitation": hourly.get("precipitation"),
"precipitation_probability": hourly.get("precipitation_probability"),
"wind_speed": hourly.get("wind_speed"),
"wind_bearing": hourly.get("wind_direction"),
"condition": ICON_TO_CONDITION_MAP.get(hourly.get("icon"), "unknown"),
}
forecasts.append(hourly_forecast)
return forecasts

@property
def forecast_daily(self):
forecasts = []
for daily in self._forecast:
day_data = daily.get("daily", {})
daily_forecast = {
"datetime": day_data.get("timestamp"),
"temperature": day_data.get("temperature_max"),
"templow": day_data.get("temperature_min"),
"precipitation": day_data.get("precipitation_intensity"),
"precipitation_probability": day_data.get("precipitation_probability"),
"wind_speed": day_data.get("wind_speed"),
"wind_bearing": day_data.get("wind_direction"),
"condition": ICON_TO_CONDITION_MAP.get(day_data.get("icon"), "unknown"),
}
forecasts.append(daily_forecast)
return forecasts

@property
def state(self):
return self.condition

async def async_forecast_daily(self):
return self.forecast_daily[:7]

async def async_forecast_hourly(self):
return self.forecast_hourly[:24]
21 changes: 21 additions & 0 deletions custom_components/weatherxm/weatherxm_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import json
import logging

from datetime import datetime, timedelta

_LOGGER = logging.getLogger(__name__)

class WeatherXMAPI:
Expand Down Expand Up @@ -44,3 +46,22 @@ def get_devices(self):
except requests.RequestException as e:
_LOGGER.error("Error fetching devices: %s", e)
return []

def get_forecast_data(self, device_id):
today = datetime.now().strftime('%Y-%m-%d')
future = (datetime.now() + timedelta(days=7)).strftime('%Y-%m-%d')
url = f"{self.host}/api/v1/me/devices/{device_id}/forecast?fromDate={today}&toDate={future}"
headers = {
'Authorization': f'Bearer {self.auth_token}',
'accept': 'application/json'
}
try:
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.json()
else:
_LOGGER.error("Failed to get forecast data: %s", response.text)
return []
except requests.RequestException as e:
_LOGGER.error("Error fetching forecast data: %s", e)
return []

0 comments on commit 05c079f

Please sign in to comment.