diff --git a/custom_components/ohme/__init__.py b/custom_components/ohme/__init__.py index 226e4a5..732118d 100644 --- a/custom_components/ohme/__init__.py +++ b/custom_components/ohme/__init__.py @@ -17,6 +17,8 @@ async def async_setup_dependencies(hass, entry): client = OhmeApiClient(entry.data['email'], entry.data['password']) hass.data[DOMAIN][DATA_CLIENT] = client + hass.data[DOMAIN][DATA_OPTIONS] = entry.options + await client.async_create_session() await client.async_update_device_info() diff --git a/custom_components/ohme/config_flow.py b/custom_components/ohme/config_flow.py index ec566a7..b749d33 100644 --- a/custom_components/ohme/config_flow.py +++ b/custom_components/ohme/config_flow.py @@ -43,19 +43,36 @@ class OhmeOptionsFlow(OptionsFlow): def __init__(self, entry) -> None: self._config_entry = entry - async def async_step_init(self, info): + async def async_step_init(self, options): errors = {} - if info is not None: - instance = OhmeApiClient(info['email'], info['password']) - if await instance.async_refresh_session() is None: - errors["base"] = "auth_error" - else: + # If form filled + if options is not None: + data = self._config_entry.data + + # Update credentials + if 'email' in options and 'password' in options: + instance = OhmeApiClient(options['email'], options['password']) + if await instance.async_refresh_session() is None: + errors["base"] = "auth_error" + else: + data['email'] = options['email'] + data['password'] = options['password'] + + # If we have no errors, update the data array + if len(errors) == 0: + # Don't store email and password in options + options.pop('email', None) + options.pop('password', None) + + # Update data self.hass.config_entries.async_update_entry( - self._config_entry, data=info + self._config_entry, data=data ) + + # Update options return self.async_create_entry( title="", - data={} + data=options ) return self.async_show_form( @@ -64,8 +81,11 @@ async def async_step_init(self, info): vol.Required( "email", default=self._config_entry.data['email'] ): str, - vol.Required( + vol.Optional( "password" - ): str + ): str, + vol.Required( + "never_session_specific" + ) : bool }), errors=errors ) diff --git a/custom_components/ohme/const.py b/custom_components/ohme/const.py index ae0b25f..c80e09b 100644 --- a/custom_components/ohme/const.py +++ b/custom_components/ohme/const.py @@ -1,12 +1,14 @@ """Component constants""" DOMAIN = "ohme" USER_AGENT = "dan-r-homeassistant-ohme" -INTEGRATION_VERSION = "0.3.2" +INTEGRATION_VERSION = "0.3.3" CONFIG_VERSION = 1 ENTITY_TYPES = ["sensor", "binary_sensor", "switch", "button", "number", "time"] DATA_CLIENT = "client" DATA_COORDINATORS = "coordinators" +DATA_OPTIONS = "options" + COORDINATOR_CHARGESESSIONS = 0 COORDINATOR_ACCOUNTINFO = 1 COORDINATOR_STATISTICS = 2 diff --git a/custom_components/ohme/number.py b/custom_components/ohme/number.py index cc52524..9530e8c 100644 --- a/custom_components/ohme/number.py +++ b/custom_components/ohme/number.py @@ -65,7 +65,7 @@ def unique_id(self): async def async_set_native_value(self, value: float) -> None: """Update the current value.""" # If session in progress, update this session, if not update the first schedule - if session_in_progress(self.coordinator.data): + if session_in_progress(self.hass, self.coordinator.data): await self._client.async_apply_session_rule(target_percent=int(value)) await asyncio.sleep(1) await self.coordinator.async_refresh() @@ -83,7 +83,7 @@ def icon(self): def _handle_coordinator_update(self) -> None: """Get value from data returned from API by coordinator""" # Set with the same logic as reading - if session_in_progress(self.coordinator.data): + if session_in_progress(self.hass, self.coordinator.data): target = round(self.coordinator.data['appliedRule']['targetPercent']) elif self.coordinator_schedules.data: target = round(self.coordinator_schedules.data['targetPercent']) diff --git a/custom_components/ohme/time.py b/custom_components/ohme/time.py index 6afc7e2..dee2dbb 100644 --- a/custom_components/ohme/time.py +++ b/custom_components/ohme/time.py @@ -68,7 +68,7 @@ def unique_id(self): async def async_set_value(self, value: dt_time) -> None: """Update the current value.""" # If session in progress, update this session, if not update the first schedule - if session_in_progress(self.coordinator.data): + if session_in_progress(self.hass, self.coordinator.data): await self._client.async_apply_session_rule(target_time=(int(value.hour), int(value.minute))) await asyncio.sleep(1) await self.coordinator.async_refresh() @@ -87,7 +87,7 @@ def _handle_coordinator_update(self) -> None: """Get value from data returned from API by coordinator""" # Read with the same logic as setting target = None - if session_in_progress(self.coordinator.data): + if session_in_progress(self.hass, self.coordinator.data): target = self.coordinator.data['appliedRule']['targetTime'] elif self.coordinator_schedules.data: target = self.coordinator_schedules.data['targetTime'] diff --git a/custom_components/ohme/translations/en.json b/custom_components/ohme/translations/en.json index c1c83e5..3f400db 100644 --- a/custom_components/ohme/translations/en.json +++ b/custom_components/ohme/translations/en.json @@ -22,7 +22,12 @@ "description": "Update your Ohme account information.", "data": { "email": "Email address", - "password": "Password" + "password": "Password", + "never_session_specific": "Never update an ongoing session" + }, + "data_description": { + "password": "If you are not changing your credentials, leave these fields empty.", + "never_session_specific": "When adjusting charge percentage, charge target or preconditioning settings, the schedule will always be updated even if a charge session is in progress." } } }, diff --git a/custom_components/ohme/utils.py b/custom_components/ohme/utils.py index 9d0a744..269771d 100644 --- a/custom_components/ohme/utils.py +++ b/custom_components/ohme/utils.py @@ -1,5 +1,6 @@ from time import time from datetime import datetime, timedelta +from .const import DOMAIN, DATA_OPTIONS import pytz @@ -74,9 +75,13 @@ def time_next_occurs(hour, minute): return target -def session_in_progress(data): +def session_in_progress(hass, data): """Is there a session in progress? Used to check if we should update the current session rather than the first schedule.""" + # If config option set, never update session specific schedule + if get_option(hass, "never_session_specific"): + return False + # Default to False with no data if not data: return False @@ -86,3 +91,7 @@ def session_in_progress(data): return False return True + +def get_option(hass, option): + """Return option value, default to False.""" + return hass.data[DOMAIN][DATA_OPTIONS].get(option, None)