Skip to content

Commit

Permalink
Add support for reauthentication without fully removing and readding (#…
Browse files Browse the repository at this point in the history
…344)

Also linter changes. Need to standardize those at some point, I try to
stick to the ones in the Home Assistant core repo.
  • Loading branch information
magico13 authored Jan 19, 2025
1 parent 4467393 commit 33ac4e9
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 29 deletions.
36 changes: 22 additions & 14 deletions custom_components/emporia_vue/__init__.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
"""The Emporia Vue integration."""

import asyncio
from datetime import UTC, datetime, timedelta, tzinfo
import logging
import re
from datetime import UTC, datetime, timedelta, tzinfo
from typing import Any

import dateutil.relativedelta
import dateutil.tz
import requests
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from homeassistant.core import HomeAssistant, State
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from pyemvue import PyEmVue
from pyemvue.device import (
ChargerDevice,
Expand All @@ -25,6 +17,19 @@
VueUsageDevice,
)
from pyemvue.enums import Scale
import requests

from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from homeassistant.core import HomeAssistant, State
from homeassistant.exceptions import (
ConfigEntryAuthFailed,
ConfigEntryNotReady,
HomeAssistantError,
)
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import DOMAIN, ENABLE_1D, ENABLE_1M, ENABLE_1MON, VUE_DATA

Expand Down Expand Up @@ -79,10 +84,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
result: bool = await loop.run_in_executor(None, vue.login, email, password)
if not result:
_LOGGER.error("Failed to login to Emporia Vue")
return False
raise ConfigEntryAuthFailed("Failed to login to Emporia Vue")
except ConfigEntryAuthFailed:
raise
except Exception as err: # pylint: disable=broad-exception-caught
_LOGGER.error("Failed to login to Emporia Vue: %s", err)
return False
raise ConfigEntryAuthFailed("Failed to login to Emporia Vue") from err

try:
devices: list[VueDevice] = await loop.run_in_executor(None, vue.get_devices)
Expand Down Expand Up @@ -459,10 +466,11 @@ async def parse_flattened_usage_data(
fixed_usage,
)

bidirectional = "bidirectional" in info_channel.type.lower() or "merged" in info_channel.type.lower()
fixed_usage = fix_usage_sign(
channel_num, fixed_usage, bidirectional
bidirectional = (
"bidirectional" in info_channel.type.lower()
or "merged" in info_channel.type.lower()
)
fixed_usage = fix_usage_sign(channel_num, fixed_usage, bidirectional)

data[identifier] = {
"device_gid": gid,
Expand Down
57 changes: 49 additions & 8 deletions custom_components/emporia_vue/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import asyncio
import logging
from typing import Any

from pyemvue import PyEmVue
import voluptuous as vol

from homeassistant import config_entries, core, exceptions
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from pyemvue import PyEmVue

from .const import DOMAIN, DOMAIN_SCHEMA, ENABLE_1D, ENABLE_1M, ENABLE_1MON

Expand All @@ -33,15 +35,15 @@ async def validate_input(data: dict):
"""
hub = VueHub()
if not await hub.authenticate(data[CONF_EMAIL], data[CONF_PASSWORD]):
raise InvalidAuth()
raise InvalidAuth

# If you cannot connect:
# throw CannotConnect
# If the authentication is wrong:
# InvalidAuth

if not hub.vue.customer:
raise InvalidAuth()
raise InvalidAuth

# Return info that you want to store in the config entry.
return {
Expand Down Expand Up @@ -84,6 +86,49 @@ async def async_step_user(self, user_input=None) -> config_entries.FlowResult:
step_id="user", data_schema=DOMAIN_SCHEMA, errors=errors
)

async def async_step_reauth(
self, entry_data: dict[str, Any]
) -> config_entries.FlowResult:
"""Perform reauthentication upon an API authentication error."""
return await self.async_step_reauth_confirm()

async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> config_entries.FlowResult:
"""Confirm reauthentication dialog."""
errors: dict[str, str] = {}
if user_input:
gid = 0
try:
hub = VueHub()
if not await hub.authenticate(
user_input[CONF_EMAIL], user_input[CONF_PASSWORD]
):
raise InvalidAuth
gid = hub.vue.customer.customer_gid
except InvalidAuth:
errors["base"] = "invalid_auth"
else:
await self.async_set_unique_id(str(gid))
self._abort_if_unique_id_mismatch(reason="wrong_account")
return self.async_update_reload_and_abort(
self._get_reauth_entry(),
data_updates={
CONF_EMAIL: user_input[CONF_EMAIL],
CONF_PASSWORD: user_input[CONF_PASSWORD],
},
)
return self.async_show_form(
step_id="reauth_confirm",
data_schema=vol.Schema(
{
vol.Required(CONF_EMAIL): str,
vol.Required(CONF_PASSWORD): str,
}
),
errors=errors,
)

@staticmethod
@core.callback
def async_get_options_flow(
Expand All @@ -98,11 +143,7 @@ class CannotConnect(exceptions.HomeAssistantError):


class OptionsFlowHandler(config_entries.OptionsFlow):
"""Handle a options flow for Emporia Vue."""

def __init__(self, config_entry: config_entries.ConfigEntry) -> None:
"""Initialize options flow."""
self.config_entry: config_entries.ConfigEntry = config_entry
"""Handle an options flow for Emporia Vue."""

async def async_step_init(self, user_input=None) -> config_entries.FlowResult:
"""Manage the options."""
Expand Down
2 changes: 1 addition & 1 deletion custom_components/emporia_vue/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def unique_id(self) -> str:
f"{self._channel.device_gid}-{self._channel.channel_num}"
)
return (
"sensor.emporia_vue.{self._scale}."
f"sensor.emporia_vue.{self._scale}."
f"{self._channel.device_gid}-{self._channel.channel_num}"
)

Expand Down
12 changes: 6 additions & 6 deletions custom_components/emporia_vue/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"data": {
"email": "[%key:common::config_flow::data::email%]",
"password": "[%key:common::config_flow::data::password%]",
"enable_1m": "One Minute Sensor",
"enable_1d": "One Day Sensor",
"enable_1mon": "One Month Sensor"
"enable_1m": "Power Minute Average Sensor",
"enable_1d": "Energy Today Sensor",
"enable_1mon": "Energy This Month Sensor"
}
}
},
Expand All @@ -26,9 +26,9 @@
"data": {
"email": "[%key:common::config_flow::data::email%]",
"password": "[%key:common::config_flow::data::password%]",
"enable_1m": "One Minute Sensor",
"enable_1d": "One Day Sensor",
"enable_1mon": "One Month Sensor"
"enable_1m": "Power Minute Average Sensor",
"enable_1d": "Energy Today Sensor",
"enable_1mon": "Energy This Month Sensor"
}
}
}
Expand Down

0 comments on commit 33ac4e9

Please sign in to comment.