Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The Flick Electric integration."""
2 
3 from datetime import datetime as dt
4 import logging
5 
6 import jwt
7 from pyflick import FlickAPI
8 from pyflick.authentication import AbstractFlickAuth
9 from pyflick.const import DEFAULT_CLIENT_ID, DEFAULT_CLIENT_SECRET
10 
11 from homeassistant.config_entries import ConfigEntry
12 from homeassistant.const import (
13  CONF_ACCESS_TOKEN,
14  CONF_CLIENT_ID,
15  CONF_CLIENT_SECRET,
16  CONF_PASSWORD,
17  CONF_USERNAME,
18  Platform,
19 )
20 from homeassistant.core import HomeAssistant
21 from homeassistant.helpers import aiohttp_client
22 
23 from .const import CONF_TOKEN_EXPIRY, DOMAIN
24 
25 _LOGGER = logging.getLogger(__name__)
26 
27 CONF_ID_TOKEN = "id_token"
28 
29 PLATFORMS = [Platform.SENSOR]
30 
31 
32 async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
33  """Set up Flick Electric from a config entry."""
34  auth = HassFlickAuth(hass, entry)
35 
36  hass.data.setdefault(DOMAIN, {})
37  hass.data[DOMAIN][entry.entry_id] = FlickAPI(auth)
38 
39  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
40 
41  return True
42 
43 
44 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
45  """Unload a config entry."""
46  unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
47  if unload_ok:
48  hass.data[DOMAIN].pop(entry.entry_id)
49  return unload_ok
50 
51 
52 class HassFlickAuth(AbstractFlickAuth):
53  """Implementation of AbstractFlickAuth based on a Home Assistant entity config."""
54 
55  def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
56  """Flick authentication based on a Home Assistant entity config."""
57  super().__init__(aiohttp_client.async_get_clientsession(hass))
58  self._entry_entry = entry
59  self._hass_hass = hass
60 
61  async def _get_entry_token(self):
62  # No token saved, generate one
63  if (
64  CONF_TOKEN_EXPIRY not in self._entry_entry.data
65  or CONF_ACCESS_TOKEN not in self._entry_entry.data
66  ):
67  await self._update_token_update_token()
68 
69  # Token is expired, generate a new one
70  if self._entry_entry.data[CONF_TOKEN_EXPIRY] <= dt.now().timestamp():
71  await self._update_token_update_token()
72 
73  return self._entry_entry.data[CONF_ACCESS_TOKEN]
74 
75  async def _update_token(self):
76  _LOGGER.debug("Fetching new access token")
77 
78  token = await self.get_new_token(
79  username=self._entry_entry.data[CONF_USERNAME],
80  password=self._entry_entry.data[CONF_PASSWORD],
81  client_id=self._entry_entry.data.get(CONF_CLIENT_ID, DEFAULT_CLIENT_ID),
82  client_secret=self._entry_entry.data.get(
83  CONF_CLIENT_SECRET, DEFAULT_CLIENT_SECRET
84  ),
85  )
86 
87  _LOGGER.debug("New token: %s", token)
88 
89  # Flick will send the same token, but expiry is relative - so grab it from the token
90  token_decoded = jwt.decode(
91  token[CONF_ID_TOKEN], options={"verify_signature": False}
92  )
93 
94  self._hass_hass.config_entries.async_update_entry(
95  self._entry_entry,
96  data={
97  **self._entry_entry.data,
98  CONF_ACCESS_TOKEN: token,
99  CONF_TOKEN_EXPIRY: token_decoded["exp"],
100  },
101  )
102 
103  async def async_get_access_token(self):
104  """Get Access Token from HASS Storage."""
105  token = await self._get_entry_token_get_entry_token()
106 
107  return token[CONF_ID_TOKEN]
None __init__(self, HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:55
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:44
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:32