Home Assistant Unofficial Reference 2024.12.1
websocket_api.py
Go to the documentation of this file.
1 """The weather websocket API."""
2 
3 from __future__ import annotations
4 
5 from typing import Any, Literal
6 
7 import voluptuous as vol
8 
9 from homeassistant.components import websocket_api
10 from homeassistant.core import HomeAssistant, callback
11 from homeassistant.helpers import config_validation as cv
12 from homeassistant.util.json import JsonValueType
13 
14 from .const import DATA_COMPONENT, DOMAIN, VALID_UNITS, WeatherEntityFeature
15 
16 FORECAST_TYPE_TO_FLAG = {
17  "daily": WeatherEntityFeature.FORECAST_DAILY,
18  "hourly": WeatherEntityFeature.FORECAST_HOURLY,
19  "twice_daily": WeatherEntityFeature.FORECAST_TWICE_DAILY,
20 }
21 
22 
23 @callback
24 def async_setup(hass: HomeAssistant) -> None:
25  """Set up the weather websocket API."""
26  websocket_api.async_register_command(hass, ws_convertible_units)
27  websocket_api.async_register_command(hass, ws_subscribe_forecast)
28 
29 
30 @callback
31 @websocket_api.websocket_command( { vol.Required("type"): "weather/convertible_units",
32  }
33 )
35  hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any]
36 ) -> None:
37  """Return supported units for a device class."""
38  sorted_units = {
39  key: sorted(units, key=str.casefold) for key, units in VALID_UNITS.items()
40  }
41  connection.send_result(msg["id"], {"units": sorted_units})
42 
43 
44 @websocket_api.websocket_command( { vol.Required("type"): "weather/subscribe_forecast",
45  vol.Required("entity_id"): cv.entity_domain(DOMAIN),
46  vol.Required("forecast_type"): vol.In(["daily", "hourly", "twice_daily"]),
47  }
48 )
49 @websocket_api.async_response
50 async def ws_subscribe_forecast(
51  hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any]
52 ) -> None:
53  """Subscribe to weather forecasts."""
54  entity_id: str = msg["entity_id"]
55  forecast_type: Literal["daily", "hourly", "twice_daily"] = msg["forecast_type"]
56 
57  if not (entity := hass.data[DATA_COMPONENT].get_entity(msg["entity_id"])):
58  connection.send_error(
59  msg["id"],
60  "invalid_entity_id",
61  f"Weather entity not found: {entity_id}",
62  )
63  return
64 
65  if (
66  entity.supported_features is None
67  or not entity.supported_features & FORECAST_TYPE_TO_FLAG[forecast_type]
68  ):
69  connection.send_error(
70  msg["id"],
71  "forecast_not_supported",
72  f"The weather entity does not support forecast type: {forecast_type}",
73  )
74  return
75 
76  @callback
77  def forecast_listener(forecast: list[JsonValueType] | None) -> None:
78  """Push a new forecast to websocket."""
79  connection.send_message(
80  websocket_api.event_message(
81  msg["id"],
82  {
83  "type": forecast_type,
84  "forecast": forecast,
85  },
86  )
87  )
88 
89  connection.subscriptions[msg["id"]] = entity.async_subscribe_forecast(
90  forecast_type, forecast_listener
91  )
92  connection.send_message(websocket_api.result_message(msg["id"]))
93 
94  # Push an initial forecast update
95  await entity.async_update_listeners({forecast_type})
96 
CalendarEntity get_entity(HomeAssistant hass, str entity_id)
Definition: trigger.py:96
None ws_convertible_units(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)
None ws_subscribe_forecast(HomeAssistant hass, websocket_api.ActiveConnection connection, dict[str, Any] msg)