Skip to content

Commit

Permalink
The custom component will try to get the tokens, when expired, from a…
Browse files Browse the repository at this point in the history
… local JSON file
  • Loading branch information
msanchezt committed Jan 17, 2025
1 parent fc63d3b commit 76aa06b
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 10 deletions.
27 changes: 27 additions & 0 deletions custom_components/aigues_barcelona/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import datetime
import json
import logging
import os

import requests
from homeassistant.core import HomeAssistant

from .const import API_COOKIE_TOKEN
from .const import API_HOST
Expand Down Expand Up @@ -268,3 +270,28 @@ def consumptions_month(self, date_from: datetime.date, contract=None, user=None)

def parse_consumptions(self, info, key="accumulatedConsumption"):
return [x[key] for x in info]

def load_token_from_file(self, hass: HomeAssistant) -> str | None:
"""Load token from JSON file based on username and company identification."""
try:
file_path = hass.config.path("automations", "aigues_tokens.json")
if not os.path.exists(file_path):
return None

with open(file_path, 'r') as f:
tokens = json.load(f)

lookup_key = self._username
if hasattr(self, '_company_identification') and self._company_identification:
lookup_key = f"{self._username}_{self._company_identification}"

if lookup_key in tokens:
token = tokens[lookup_key]
# Validate token before returning
self.set_token(token)
if not self.is_token_expired():
return token
return None

except Exception as e:
return None
43 changes: 36 additions & 7 deletions custom_components/aigues_barcelona/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import logging
from typing import Any
import asyncio

import homeassistant.helpers.config_validation as cv
import voluptuous as vol
Expand All @@ -20,13 +21,15 @@
from .const import CONF_CONTRACT
from .const import DOMAIN
from .const import CONF_COMPANY_IDENTIFICATOR
from .const import CONF_TOKEN_FILE, DEFAULT_TOKEN_FILE

_LOGGER = logging.getLogger(__name__)

ACCOUNT_CONFIG_SCHEMA = vol.Schema(
{
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_TOKEN_FILE, default=DEFAULT_TOKEN_FILE): cv.string,
vol.Optional(CONF_COMPANY_IDENTIFICATOR): cv.string,
}
)
Expand Down Expand Up @@ -109,8 +112,27 @@ class AiguesBarcelonaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_token(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Return to user step with stored input (previous user creds) and the
current provided token."""
"""Handle token step."""
if user_input is None:
retry_count = 0
while retry_count < 12: # Try for 1 hour (12 * 5 minutes)
api = AiguesApiClient(
self.stored_input[CONF_USERNAME],
self.stored_input[CONF_PASSWORD],
company_identification=self.stored_input.get(CONF_COMPANY_IDENTIFICATOR)
)
token = api.load_token_from_file(self.hass)

if token:
return await self.async_step_user({**self.stored_input, CONF_TOKEN: token})

retry_count += 1
if retry_count < 12:
await asyncio.sleep(300) # Wait 5 minutes before next try

# If we get here, show the manual token input form
return self.async_show_form(step_id="token", data_schema=TOKEN_SCHEMA)

return await self.async_step_user({**self.stored_input, **user_input})

async def async_step_reauth(self, entry) -> FlowResult:
Expand Down Expand Up @@ -138,14 +160,21 @@ async def async_step_reauth_confirm(
current provided token."""

if not user_input:
return self.async_show_form(
step_id="reauth_confirm", data_schema=TOKEN_SCHEMA
# Try to load token from file first
api = AiguesApiClient(
self.stored_input[CONF_USERNAME],
self.stored_input[CONF_PASSWORD],
company_identification=self.stored_input.get(CONF_COMPANY_IDENTIFICATOR)
)
token = api.load_token_from_file(self.hass)

if token:
return await self.async_step_user({**self.stored_input, CONF_TOKEN: token})

return self.async_show_form(step_id="reauth_confirm", data_schema=TOKEN_SCHEMA)

errors = {}
_LOGGER.debug(
f"Current values on reauth_confirm: {self.entry} --> {user_input}"
)
_LOGGER.debug(f"Current values on reauth_confirm: {self.entry} --> {user_input}")
user_input = {**self.stored_input, **user_input}
try:
info = await validate_credentials(self.hass, user_input)
Expand Down
4 changes: 2 additions & 2 deletions custom_components/aigues_barcelona/const.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""Constants definition."""

DOMAIN = "aigues_barcelona"

CONF_CONTRACT = "contract"
CONF_VALUE = "value"
CONF_COMPANY_IDENTIFICATOR = "company_identification"
CONF_TOKEN_FILE = "token_file"
DEFAULT_TOKEN_FILE = "/automations/aigues-barcelona.json"

ATTR_LAST_MEASURE = "Last measure"

Expand Down
2 changes: 1 addition & 1 deletion custom_components/aigues_barcelona/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"data": {
"username": "Username (DNI/NIE)",
"password": "Password",
"company_identification": "Company Identification (optional)"
"token_file": "Token file path (default: /automations/aigues-barcelona.json)"
},
"title": "Setup integration"
},
Expand Down

0 comments on commit 76aa06b

Please sign in to comment.