From dafa6dcd4bb69dc13a76fa5f82c2df25c9e66eb6 Mon Sep 17 00:00:00 2001 From: trizmark Date: Wed, 1 May 2024 17:07:23 +0100 Subject: [PATCH 1/2] Added extra logging to grid charge control --- custom_components/myenergi/select.py | 4 ---- custom_components/myenergi/switch.py | 6 ++++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/custom_components/myenergi/select.py b/custom_components/myenergi/select.py index e937514..f0220d3 100644 --- a/custom_components/myenergi/select.py +++ b/custom_components/myenergi/select.py @@ -1,6 +1,4 @@ """Sensor platform for myenergi.""" -import logging - import voluptuous as vol from homeassistant.components.select import SelectEntity from homeassistant.helpers import entity_platform @@ -11,8 +9,6 @@ from .const import DOMAIN from .entity import MyenergiEntity -_LOGGER: logging.Logger = logging.getLogger(__package__) - LIBBI_MODE_NAMES = {"STOP": "Stopped", "BALANCE": "Normal", "DRAIN": "Export"} ATTR_BOOST_AMOUNT = "amount" diff --git a/custom_components/myenergi/switch.py b/custom_components/myenergi/switch.py index 7b82f77..9bd56b0 100644 --- a/custom_components/myenergi/switch.py +++ b/custom_components/myenergi/switch.py @@ -1,4 +1,5 @@ """Switch platform for myenergi.""" +import logging import operator from homeassistant.components.switch import SwitchEntity @@ -7,6 +8,8 @@ from .const import DOMAIN from .entity import MyenergiEntity +_LOGGER: logging.Logger = logging.getLogger(__package__) + async def async_setup_entry(hass, entry, async_add_devices): """Setup switch platform.""" @@ -63,10 +66,13 @@ def icon(self): async def async_turn_on(self, **kwargs): """Turn the entity on.""" + _LOGGER.debug("libbi charging from grid is now ON") + _LOGGER.debug(type(self)) await operator.methodcaller(self.meta["update_func"], True)(self.device) self.async_schedule_update_ha_state() async def async_turn_off(self, **kwargs): """Turn the entity off.""" + _LOGGER.debug("libbi charging from grid is now OFF") await operator.methodcaller(self.meta["update_func"], False)(self.device) self.async_schedule_update_ha_state() From e5f9d007c8165d6c8b56a7751c4503f00bac5cf0 Mon Sep 17 00:00:00 2001 From: trizmark Date: Tue, 4 Jun 2024 14:30:53 +0100 Subject: [PATCH 2/2] Further refinement of libbi component --- custom_components/myenergi/__init__.py | 11 +++++++- custom_components/myenergi/config_flow.py | 27 ++++++++++++++++--- custom_components/myenergi/const.py | 2 +- custom_components/myenergi/manifest.json | 2 +- custom_components/myenergi/sensor.py | 5 +++- custom_components/myenergi/switch.py | 1 - .../myenergi/translations/en.json | 8 +++--- 7 files changed, 45 insertions(+), 11 deletions(-) diff --git a/custom_components/myenergi/__init__.py b/custom_components/myenergi/__init__.py index 1e6ed7e..1a6b934 100644 --- a/custom_components/myenergi/__init__.py +++ b/custom_components/myenergi/__init__.py @@ -50,7 +50,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): conn = await hass.async_add_executor_job( Connection, username, password, app_password, app_email ) - await conn.discoverLocations() + if app_email and app_password: + await conn.discoverLocations() client = MyenergiClient(conn) @@ -68,6 +69,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): entry.add_update_listener(async_reload_entry) + # once we reconfigure the integration, we (possibly) need to use the new credentials + entry.async_on_unload(entry.add_update_listener(config_update_listener)) + return True @@ -85,6 +89,7 @@ def __init__(self, hass: HomeAssistant, client: MyenergiClient, entry) -> None: entry.data.get(CONF_SCAN_INTERVAL, SCAN_INTERVAL.total_seconds()), ) ) + super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=scan_interval) async def _async_update_data(self): @@ -127,3 +132,7 @@ async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: """Reload config entry.""" await async_unload_entry(hass, entry) await async_setup_entry(hass, entry) + + +async def config_update_listener(hass, entry): + """Handle options update.""" diff --git a/custom_components/myenergi/config_flow.py b/custom_components/myenergi/config_flow.py index f6eec84..4e0434d 100644 --- a/custom_components/myenergi/config_flow.py +++ b/custom_components/myenergi/config_flow.py @@ -71,8 +71,8 @@ async def _show_config_form(self, user_input): # pylint: disable=unused-argumen { vol.Required(CONF_USERNAME, default=defaults[CONF_USERNAME]): str, vol.Required(CONF_PASSWORD, default=defaults[CONF_PASSWORD]): str, - vol.Required(CONF_APP_EMAIL, default=defaults[CONF_APP_EMAIL]): str, - vol.Required( + vol.Optional(CONF_APP_EMAIL, default=defaults[CONF_APP_EMAIL]): str, + vol.Optional( CONF_APP_PASSWORD, default=defaults[CONF_APP_PASSWORD] ): str, } @@ -87,7 +87,8 @@ async def _test_credentials(self, username, password, app_email, app_password): conn = await self.hass.async_add_executor_job( Connection, username, password, app_password, app_email ) - await conn.discoverLocations() + if app_password and app_email: + await conn.discoverLocations() client = MyenergiClient(conn) await client.refresh() return None, client @@ -119,12 +120,30 @@ async def async_step_init(self, user_input=None): # pylint: disable=unused-argu async def async_step_user(self, user_input=None): """Handle a flow initialized by the user.""" if user_input is not None: + # create a new dict to update config data (don't duplicate it in options) + cdata = {} + cdata[CONF_USERNAME] = self.config_entry.data[CONF_USERNAME] + cdata[CONF_PASSWORD] = self.config_entry.data[CONF_PASSWORD] + if CONF_APP_EMAIL in user_input: + cdata[CONF_APP_EMAIL] = user_input[CONF_APP_EMAIL] + del user_input[CONF_APP_EMAIL] + if CONF_APP_PASSWORD in user_input: + cdata[CONF_APP_PASSWORD] = user_input[CONF_APP_PASSWORD] + del user_input[CONF_APP_PASSWORD] + + # now update config data + self.hass.config_entries.async_update_entry(self.config_entry, data=cdata) + + # finally update options data (which is now only the SCAN_INTERVAL) self.options.update(user_input) return await self._update_options() scan_interval = self.config_entry.options.get( CONF_SCAN_INTERVAL, SCAN_INTERVAL.total_seconds() ) + app_email = self.config_entry.options.get(CONF_APP_EMAIL) + app_password = self.config_entry.options.get(CONF_APP_PASSWORD) + return self.async_show_form( step_id="user", data_schema=vol.Schema( @@ -134,6 +153,8 @@ async def async_step_user(self, user_input=None): ): NumberSelector( NumberSelectorConfig(min=1, max=300, step=1), ), + vol.Optional(CONF_APP_EMAIL, default=app_email): str, + vol.Optional(CONF_APP_PASSWORD, default=app_password): str, } ), ) diff --git a/custom_components/myenergi/const.py b/custom_components/myenergi/const.py index 1f21bf4..85e8cdf 100644 --- a/custom_components/myenergi/const.py +++ b/custom_components/myenergi/const.py @@ -3,7 +3,7 @@ NAME = "myenergi" DOMAIN = "myenergi" DOMAIN_DATA = f"{DOMAIN}_data" -VERSION = "0.0.27" +VERSION = "0.0.28-pre" ATTRIBUTION = "Data provided by myenergi" ISSUE_URL = "https://github.com/CJNE/ha-myenergi/issues" diff --git a/custom_components/myenergi/manifest.json b/custom_components/myenergi/manifest.json index 23407ce..c5a9d49 100644 --- a/custom_components/myenergi/manifest.json +++ b/custom_components/myenergi/manifest.json @@ -7,6 +7,6 @@ "documentation": "https://github.com/cjne/ha-myenergi", "iot_class": "cloud_polling", "issue_tracker": "https://github.com/cjne/ha-myenergi/issues", - "requirements": ["pymyenergi==0.1.1"], + "requirements": ["pymyenergi==0.2.0"], "version": "0.0.28-pre" } diff --git a/custom_components/myenergi/sensor.py b/custom_components/myenergi/sensor.py index ec154a4..8c26eba 100644 --- a/custom_components/myenergi/sensor.py +++ b/custom_components/myenergi/sensor.py @@ -756,7 +756,10 @@ def name(self): def state(self): """Return the state of the sensor.""" value = operator.attrgetter(self.meta["prop_name"])(self.device) - return value + if value is not None: + return value + else: + self._attr_available = False @property def unit_of_measurement(self): diff --git a/custom_components/myenergi/switch.py b/custom_components/myenergi/switch.py index 9bd56b0..2c2dced 100644 --- a/custom_components/myenergi/switch.py +++ b/custom_components/myenergi/switch.py @@ -67,7 +67,6 @@ def icon(self): async def async_turn_on(self, **kwargs): """Turn the entity on.""" _LOGGER.debug("libbi charging from grid is now ON") - _LOGGER.debug(type(self)) await operator.methodcaller(self.meta["update_func"], True)(self.device) self.async_schedule_update_ha_state() diff --git a/custom_components/myenergi/translations/en.json b/custom_components/myenergi/translations/en.json index 897d9da..4b85f5b 100644 --- a/custom_components/myenergi/translations/en.json +++ b/custom_components/myenergi/translations/en.json @@ -6,8 +6,8 @@ "data": { "username": "Hub serial number", "password": "API key", - "app_email": "App email", - "app_password": "App password" + "app_email": "App email (only required for libbi)", + "app_password": "App password (only required for libbi)" } } }, @@ -24,7 +24,9 @@ "step": { "user": { "data": { - "scan_interval": "Update interval (seconds)" + "scan_interval": "Update interval (seconds)", + "app_email": "App email (only required for libbi)", + "app_password": "App password (only required for libbi)" } } }