Skip to content
This repository was archived by the owner on Apr 30, 2022. It is now read-only.

Commit 9e544b1

Browse files
authored
Refresh access token during sensor startup (#8)
* Refresh access token during sensor startup * chore: address linting errors * Copy HomeAssistant config before rewriting it * Handle changed passwords and signal broken sensors
1 parent a76f9a6 commit 9e544b1

File tree

3 files changed

+60
-17
lines changed

3 files changed

+60
-17
lines changed

custom_components/hildebrandglow/config_flow.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,8 @@
1313
DATA_SCHEMA = vol.Schema({"app_id": str, "username": str, "password": str})
1414

1515

16-
async def validate_input(hass: core.HomeAssistant, data: dict) -> Dict[str, Any]:
17-
"""Validate the user input allows us to connect.
18-
19-
Data has the keys from DATA_SCHEMA with values provided by the user.
20-
"""
21-
glow = await Glow.authenticate(data["app_id"], data["username"], data["password"])
22-
23-
# Return some info we want to store in the config entry.
16+
def config_object(data: dict, glow: Dict[str, Any]) -> Dict[str, Any]:
17+
"""Prepare a ConfigEntity with authentication data and a temporary token."""
2418
return {
2519
"name": glow["name"],
2620
"app_id": data["app_id"],
@@ -31,6 +25,19 @@ async def validate_input(hass: core.HomeAssistant, data: dict) -> Dict[str, Any]
3125
}
3226

3327

28+
async def validate_input(hass: core.HomeAssistant, data: dict) -> Dict[str, Any]:
29+
"""Validate the user input allows us to connect.
30+
31+
Data has the keys from DATA_SCHEMA with values provided by the user.
32+
"""
33+
glow = await hass.async_add_executor_job(
34+
Glow.authenticate, data["app_id"], data["username"], data["password"]
35+
)
36+
37+
# Return some info we want to store in the config entry.
38+
return config_object(data, glow)
39+
40+
3441
class DomainConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
3542
"""Handle a config flow for Hildebrand Glow."""
3643

custom_components/hildebrandglow/glow.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ def __init__(self, app_id: str, token: str):
1717
self.token = token
1818

1919
@classmethod
20-
async def authenticate(
21-
cls, app_id: str, username: str, password: str
22-
) -> Dict[str, Any]:
20+
def authenticate(cls, app_id: str, username: str, password: str) -> Dict[str, Any]:
2321
"""
2422
Attempt to authenticate with Glowmarkt.
2523
@@ -42,7 +40,7 @@ async def authenticate(
4240
pprint(data)
4341
raise InvalidAuth
4442

45-
async def retrieve_resources(self) -> List[Dict[str, Any]]:
43+
def retrieve_resources(self) -> List[Dict[str, Any]]:
4644
"""Retrieve the resources known to Glowmarkt for the authenticated user."""
4745
url = f"{self.BASE_URL}/resource"
4846
headers = {"applicationId": self.app_id, "token": self.token}
@@ -58,7 +56,7 @@ async def retrieve_resources(self) -> List[Dict[str, Any]]:
5856
data = response.json()
5957
return data
6058

61-
async def current_usage(self, resource: Dict[str, Any]) -> Dict[str, Any]:
59+
def current_usage(self, resource: Dict[str, Any]) -> Dict[str, Any]:
6260
"""Retrieve the current usage for a specified resource."""
6361
url = f"{self.BASE_URL}/resource/{resource}/current"
6462
headers = {"applicationId": self.app_id, "token": self.token}

custom_components/hildebrandglow/sensor.py

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,52 @@
11
"""Platform for sensor integration."""
22
from typing import Any, Callable, Dict, Optional
33

4+
from homeassistant.config_entries import ConfigEntry
45
from homeassistant.const import DEVICE_CLASS_POWER, POWER_WATT
56
from homeassistant.core import HomeAssistant
67
from homeassistant.helpers.entity import Entity
78

9+
from .config_flow import config_object
810
from .const import DOMAIN
9-
from .glow import Glow
11+
from .glow import Glow, InvalidAuth
1012

1113

1214
async def async_setup_entry(
13-
hass: HomeAssistant, config: Dict[str, Any], async_add_entities: Callable
15+
hass: HomeAssistant, config: ConfigEntry, async_add_entities: Callable
1416
) -> bool:
1517
"""Set up the sensor platform."""
1618
new_entities = []
1719

20+
async def handle_failed_auth(config: ConfigEntry, hass: HomeAssistant) -> None:
21+
glow_auth = await hass.async_add_executor_job(
22+
Glow.authenticate,
23+
config.data["app_id"],
24+
config.data["username"],
25+
config.data["password"],
26+
)
27+
28+
current_config = dict(config.data.copy())
29+
new_config = config_object(current_config, glow_auth)
30+
hass.config_entries.async_update_entry(entry=config, data=new_config)
31+
32+
glow = Glow(config.data["app_id"], glow_auth["token"])
33+
hass.data[DOMAIN][config.entry_id] = glow
34+
1835
for entry in hass.data[DOMAIN]:
1936
glow = hass.data[DOMAIN][entry]
2037

21-
resources = await glow.retrieve_resources()
38+
resources: dict = dict()
2239

40+
try:
41+
resources = await hass.async_add_executor_job(glow.retrieve_resources)
42+
except InvalidAuth:
43+
try:
44+
await handle_failed_auth(config, hass)
45+
except InvalidAuth:
46+
return False
47+
48+
glow = hass.data[DOMAIN][entry]
49+
resources = await hass.async_add_executor_job(glow.retrieve_resources)
2350
for resource in resources:
2451
if resource["resourceTypeId"] in GlowConsumptionCurrent.resourceTypeId:
2552
sensor = GlowConsumptionCurrent(glow, resource)
@@ -33,11 +60,15 @@ async def async_setup_entry(
3360
class GlowConsumptionCurrent(Entity):
3461
"""Sensor object for the Glowmarkt resource's current consumption."""
3562

63+
hass: HomeAssistant
64+
3665
resourceTypeId = [
3766
"ea02304a-2820-4ea0-8399-f1d1b430c3a0", # Smart Meter, electricity consumption
3867
"672b8071-44ff-4f23-bca2-f50c6a3ddd02", # Smart Meter, gas consumption
3968
]
4069

70+
available = True
71+
4172
def __init__(self, glow: Glow, resource: Dict[str, Any]):
4273
"""Initialize the sensor."""
4374
self._state: Optional[Dict[str, Any]] = None
@@ -103,4 +134,11 @@ async def async_update(self) -> None:
103134
104135
This is the only method that should fetch new data for Home Assistant.
105136
"""
106-
self._state = await self.glow.current_usage(self.resource["resourceId"])
137+
try:
138+
self._state = await self.hass.async_add_executor_job(
139+
self.glow.current_usage, self.resource["resourceId"]
140+
)
141+
except InvalidAuth:
142+
# TODO: Trip the failed auth logic above somehow
143+
self.available = False
144+
pass

0 commit comments

Comments
 (0)