From 64dab6e64df6503695e4d16f3b317bcc4a5b350e Mon Sep 17 00:00:00 2001 From: lbbrhzn <8673442+lbbrhzn@users.noreply.github.com> Date: Fri, 10 Nov 2023 08:56:25 +0100 Subject: [PATCH] autodetect supported measurands (#968) * autodetect supported measurands * fix ConfigurationStatus check * remove measurands from config flow --- custom_components/ocpp/api.py | 23 +++++++++++++++++- custom_components/ocpp/config_flow.py | 34 +++++---------------------- custom_components/ocpp/const.py | 30 +++++++++++------------ tests/const.py | 30 ++++------------------- tests/test_config_flow.py | 11 +-------- 5 files changed, 48 insertions(+), 80 deletions(-) diff --git a/custom_components/ocpp/api.py b/custom_components/ocpp/api.py index 15f8573d..1bb4c2ab 100644 --- a/custom_components/ocpp/api.py +++ b/custom_components/ocpp/api.py @@ -430,10 +430,31 @@ async def handle_data_transfer(call): resp = await self.get_configuration(ckey.number_of_connectors.value) self._metrics[cdet.connectors.value].value = resp await self.get_configuration(ckey.heartbeat_interval.value) + + all_measurands = self.entry.data.get( + CONF_MONITORED_VARIABLES, DEFAULT_MEASURAND + ) + + accepted_measurands = [] + key = ckey.meter_values_sampled_data.value + + for measurand in all_measurands.split(","): + _LOGGER.debug(f"'{self.id}' trying measurand '{measurand}'") + req = call.ChangeConfigurationPayload(key=key, value=measurand) + resp = await self.call(req) + if resp.status == ConfigurationStatus.accepted: + _LOGGER.debug(f"'{self.id}' adding measurand '{measurand}'") + accepted_measurands.append(measurand) + + accepted_measurands = ",".join(accepted_measurands) + + _LOGGER.debug(f"'{self.id}' allowed measurands '{accepted_measurands}'") + await self.configure( ckey.meter_values_sampled_data.value, - self.entry.data.get(CONF_MONITORED_VARIABLES, DEFAULT_MEASURAND), + accepted_measurands, ) + await self.configure( ckey.meter_value_sample_interval.value, str(self.entry.data.get(CONF_METER_INTERVAL, DEFAULT_METER_INTERVAL)), diff --git a/custom_components/ocpp/config_flow.py b/custom_components/ocpp/config_flow.py index 7539d6e2..07c421b7 100644 --- a/custom_components/ocpp/config_flow.py +++ b/custom_components/ocpp/config_flow.py @@ -26,8 +26,8 @@ DEFAULT_HOST, DEFAULT_IDLE_INTERVAL, DEFAULT_MAX_CURRENT, - DEFAULT_MEASURAND, DEFAULT_METER_INTERVAL, + DEFAULT_MONITORED_VARIABLES, DEFAULT_PORT, DEFAULT_SKIP_SCHEMA_VALIDATION, DEFAULT_SSL, @@ -38,7 +38,6 @@ DEFAULT_WEBSOCKET_PING_TIMEOUT, DEFAULT_WEBSOCKET_PING_TRIES, DOMAIN, - MEASURANDS, ) STEP_USER_DATA_SCHEMA = vol.Schema( @@ -51,6 +50,9 @@ vol.Required(CONF_CSID, default=DEFAULT_CSID): str, vol.Required(CONF_CPID, default=DEFAULT_CPID): str, vol.Required(CONF_MAX_CURRENT, default=DEFAULT_MAX_CURRENT): int, + vol.Required( + CONF_MONITORED_VARIABLES, default=DEFAULT_MONITORED_VARIABLES + ): str, vol.Required(CONF_METER_INTERVAL, default=DEFAULT_METER_INTERVAL): int, vol.Required(CONF_IDLE_INTERVAL, default=DEFAULT_IDLE_INTERVAL): int, vol.Required( @@ -73,12 +75,6 @@ ): bool, } ) -STEP_USER_MEASURANDS_SCHEMA = vol.Schema( - { - vol.Required(m, default=(True if m == DEFAULT_MEASURAND else False)): bool - for m in MEASURANDS - } -) class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): @@ -98,27 +94,9 @@ async def async_step_user(self, user_input=None): if user_input is not None: # Todo: validate the user input self._data = user_input - return await self.async_step_measurands() + self._data[CONF_MONITORED_VARIABLES] = DEFAULT_MONITORED_VARIABLES + return self.async_create_entry(title=self._data[CONF_CSID], data=self._data) return self.async_show_form( step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors ) - - async def async_step_measurands(self, user_input=None): - """Select the measurands to be shown.""" - - errors: dict[str, str] = {} - if user_input is not None: - selected_measurands = [m for m, value in user_input.items() if value] - if set(selected_measurands).issubset(set(MEASURANDS)): - self._data[CONF_MONITORED_VARIABLES] = ",".join(selected_measurands) - return self.async_create_entry( - title=self._data[CONF_CSID], data=self._data - ) - else: - errors["base"] = "measurand" - return self.async_show_form( - step_id="measurands", - data_schema=STEP_USER_MEASURANDS_SCHEMA, - errors=errors, - ) diff --git a/custom_components/ocpp/const.py b/custom_components/ocpp/const.py index 3bf16bbc..cf9fa653 100644 --- a/custom_components/ocpp/const.py +++ b/custom_components/ocpp/const.py @@ -70,28 +70,28 @@ # Ocpp supported measurands MEASURANDS = [ - Measurand.energy_active_import_register.value, - Measurand.energy_reactive_import_register.value, + Measurand.current_export.value, + Measurand.current_import.value, + Measurand.current_offered.value, + Measurand.energy_active_export_interval.value, + Measurand.energy_active_export_register.value, Measurand.energy_active_import_interval.value, + Measurand.energy_active_import_register.value, + Measurand.energy_reactive_export_interval.value, + Measurand.energy_reactive_export_register.value, Measurand.energy_reactive_import_interval.value, + Measurand.energy_reactive_import_register.value, + Measurand.frequency.value, + Measurand.power_active_export.value, Measurand.power_active_import.value, - Measurand.power_reactive_import.value, - Measurand.power_offered.value, Measurand.power_factor.value, - Measurand.current_import.value, - Measurand.current_offered.value, - Measurand.voltage.value, - Measurand.frequency.value, + Measurand.power_offered.value, + Measurand.power_reactive_export.value, + Measurand.power_reactive_import.value, Measurand.rpm.value, Measurand.soc.value, Measurand.temperature.value, - Measurand.current_export.value, - Measurand.energy_active_export_register.value, - Measurand.energy_reactive_export_register.value, - Measurand.energy_active_export_interval.value, - Measurand.energy_reactive_export_interval.value, - Measurand.power_active_export.value, - Measurand.power_reactive_export.value, + Measurand.voltage.value, ] DEFAULT_MEASURAND = Measurand.energy_active_import_register.value DEFAULT_MONITORED_VARIABLES = ",".join(MEASURANDS) diff --git a/tests/const.py b/tests/const.py index 59327bdc..a5c52024 100644 --- a/tests/const.py +++ b/tests/const.py @@ -17,8 +17,8 @@ CONF_WEBSOCKET_PING_INTERVAL, CONF_WEBSOCKET_PING_TIMEOUT, CONF_WEBSOCKET_PING_TRIES, + DEFAULT_MONITORED_VARIABLES, ) -from ocpp.v16.enums import Measurand MOCK_CONFIG = { CONF_HOST: "127.0.0.1", @@ -31,6 +31,7 @@ CONF_IDLE_INTERVAL: 900, CONF_MAX_CURRENT: 32, CONF_METER_INTERVAL: 60, + CONF_MONITORED_VARIABLES: DEFAULT_MONITORED_VARIABLES, CONF_SKIP_SCHEMA_VALIDATION: False, CONF_FORCE_SMART_CHARGING: True, CONF_WEBSOCKET_CLOSE_TIMEOUT: 1, @@ -38,30 +39,7 @@ CONF_WEBSOCKET_PING_INTERVAL: 1, CONF_WEBSOCKET_PING_TIMEOUT: 1, } -MOCK_CONFIG_2 = { - Measurand.current_export.value: True, - Measurand.current_import.value: True, - Measurand.current_offered.value: True, - Measurand.energy_active_export_register.value: True, - Measurand.energy_active_import_register.value: True, - Measurand.energy_reactive_export_register.value: True, - Measurand.energy_reactive_import_register.value: True, - Measurand.energy_active_export_interval.value: True, - Measurand.energy_active_import_interval.value: True, - Measurand.energy_reactive_export_interval.value: True, - Measurand.energy_reactive_import_interval.value: True, - Measurand.frequency.value: True, - Measurand.power_active_export.value: True, - Measurand.power_active_import.value: True, - Measurand.power_factor.value: True, - Measurand.power_offered.value: True, - Measurand.power_reactive_export.value: True, - Measurand.power_reactive_import.value: True, - Measurand.rpm.value: True, - Measurand.soc.value: True, - Measurand.temperature.value: True, - Measurand.voltage.value: True, -} + MOCK_CONFIG_DATA = { CONF_HOST: "127.0.0.1", CONF_PORT: 9000, @@ -70,7 +48,7 @@ CONF_IDLE_INTERVAL: 900, CONF_MAX_CURRENT: 32, CONF_METER_INTERVAL: 60, - CONF_MONITORED_VARIABLES: "Current.Export,Current.Import,Current.Offered,Energy.Active.Export.Register,Energy.Active.Import.Register,Energy.Reactive.Export.Register,Energy.Reactive.Import.Register,Energy.Active.Export.Interval,Energy.Active.Import.Interval,Energy.Reactive.Export.Interval,Energy.Reactive.Import.Interval,Frequency,Power.Active.Export,Power.Active.Import,Power.Factor,Power.Offered,Power.Reactive.Export,Power.Reactive.Import,RPM,SoC,Temperature,Voltage", + CONF_MONITORED_VARIABLES: DEFAULT_MONITORED_VARIABLES, CONF_SKIP_SCHEMA_VALIDATION: False, CONF_FORCE_SMART_CHARGING: True, CONF_SSL: False, diff --git a/tests/test_config_flow.py b/tests/test_config_flow.py index ff64c94b..1e0af0fa 100644 --- a/tests/test_config_flow.py +++ b/tests/test_config_flow.py @@ -8,7 +8,7 @@ DOMAIN, ) -from .const import MOCK_CONFIG, MOCK_CONFIG_2, MOCK_CONFIG_DATA +from .const import MOCK_CONFIG, MOCK_CONFIG_DATA # from pytest_homeassistant_custom_component.common import MockConfigEntry @@ -49,15 +49,6 @@ async def test_successful_config_flow(hass, bypass_get_data): result["flow_id"], user_input=MOCK_CONFIG ) - # Check that the config flow shows the user form as the first step - assert result["type"] == data_entry_flow.RESULT_TYPE_FORM - assert result["step_id"] == "measurands" - - # Call again for step_id == "measurands" with default measurand - result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input=MOCK_CONFIG_2 - ) - # Check that the config flow is complete and a new entry is created with # the input data assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY