From f4b21f12ab67abe81ee32bf8c8db0b404d4dddb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20St=C3=A5hl?= Date: Tue, 13 Oct 2020 19:32:41 +0200 Subject: [PATCH] Add debug mode to config flow --- custom_components/localtuya/config_flow.py | 96 ++++++++++++++++--- .../localtuya/translations/en.json | 20 +++- 2 files changed, 99 insertions(+), 17 deletions(-) diff --git a/custom_components/localtuya/config_flow.py b/custom_components/localtuya/config_flow.py index c86bd6a25..9dc435d3d 100644 --- a/custom_components/localtuya/config_flow.py +++ b/custom_components/localtuya/config_flow.py @@ -30,12 +30,29 @@ DISCOVER_TIMEOUT = 6.0 +ACTION_SET_DPS = "set_dp" +ACTION_RELOAD_DPS = "reload_dps" +ACTION_EXIT_DEBUG = "exit_debug" + +CONF_ACTION = "action" +CONF_DATAPOINT = "datapoint" +CONF_DATA_TYPE = "data_type" +CONF_VALUE = "value" +CONF_DEBUG = "debug" + PLATFORM_TO_ADD = "platform_to_add" NO_ADDITIONAL_PLATFORMS = "no_additional_platforms" DISCOVERED_DEVICE = "discovered_device" CUSTOM_DEVICE = "..." +DEBUG_TYPES_CONVERSIONS = { + "int": int, + "str": str, + "bool": lambda x: x.lower() == "true", + "float": float, +} + BASIC_INFO_SCHEMA = vol.Schema( { vol.Required(CONF_FRIENDLY_NAME): str, @@ -43,6 +60,7 @@ vol.Required(CONF_HOST): str, vol.Required(CONF_DEVICE_ID): str, vol.Required(CONF_PROTOCOL_VERSION, default="3.3"): vol.In(["3.1", "3.3"]), + vol.Optional(CONF_DEBUG, default=False): bool, } ) @@ -70,6 +88,20 @@ ) +def debug_schema(dps): + """Create schema for debug mode.""" + return vol.Schema( + { + vol.Required(CONF_ACTION, default=ACTION_SET_DPS): vol.In( + [ACTION_SET_DPS, ACTION_RELOAD_DPS, ACTION_EXIT_DEBUG] + ), + vol.Optional(CONF_DATAPOINT): vol.In(dps), + vol.Optional(CONF_DATA_TYPE): vol.In(["int", "float", "str", "bool"]), + vol.Optional(CONF_VALUE): str, + } + ) + + def user_schema(devices): """Create schema for user step.""" devices = [f"{ip} ({dev['gwId']})" for ip, dev in devices.items()] @@ -157,20 +189,16 @@ def config_schema(): ) -async def validate_input(hass: core.HomeAssistant, data): - """Validate the user input allows us to connect.""" - detected_dps = {} - - interface = None +async def _tuya_command(hass: core.HomeAssistant, data, func, *args): + """Execute a Tuya command..""" + interface = pytuya.TuyaInterface( + data[CONF_DEVICE_ID], + data[CONF_HOST], + data[CONF_LOCAL_KEY], + float(data[CONF_PROTOCOL_VERSION]), + ) try: - interface = await pytuya.connect( - data[CONF_HOST], - data[CONF_DEVICE_ID], - data[CONF_LOCAL_KEY], - float(data[CONF_PROTOCOL_VERSION]), - ) - - detected_dps = await interface.detect_available_dps() + return await hass.async_add_executor_job(getattr(interface, func), *args) except (ConnectionRefusedError, ConnectionResetError): raise CannotConnect except ValueError: @@ -179,6 +207,10 @@ async def validate_input(hass: core.HomeAssistant, data): if interface: interface.close() + +async def validate_input(hass: core.HomeAssistant, data): + """Validate the user input allows us to connect.""" + detected_dps = await _tuya_command(hass, data, "detect_available_dps") return dps_string_list(detected_dps) @@ -233,9 +265,11 @@ async def async_step_basic_info(self, user_input=None): await self.async_set_unique_id(user_input[CONF_DEVICE_ID]) self._abort_if_unique_id_configured() + self.basic_info = user_input try: - self.basic_info = user_input self.dps_strings = await validate_input(self.hass, user_input) + if user_input.get(CONF_DEBUG): + return await self.async_step_debug() return await self.async_step_pick_entity_type() except CannotConnect: errors["base"] = "cannot_connect" @@ -314,6 +348,40 @@ async def async_step_import(self, user_input): title=f"{user_input[CONF_FRIENDLY_NAME]} (YAML)", data=user_input ) + async def async_step_debug(self, user_input=None): + """Handle debug mode.""" + errors = {} + if user_input is not None: + action = user_input[CONF_ACTION] + if action == ACTION_SET_DPS: + try: + type_convert = DEBUG_TYPES_CONVERSIONS[user_input[CONF_DATA_TYPE]] + value = type_convert(user_input[CONF_VALUE]) + dp = user_input[CONF_DATAPOINT].split(" ")[0] + await _tuya_command( + self.hass, self.basic_info, "set_dps", value, dp + ) + except Exception: # pylint: disable=broad-except + _LOGGER.exception(f"failed to set datapoint {dp}={value}") + errors["base"] = "set_dp_failed" + + elif action == ACTION_EXIT_DEBUG: + return self.async_abort(reason="exit_debug") + + # Always try to refresh datapoints after doing something + try: + self.dps_strings = await validate_input(self.hass, self.basic_info) + except Exception: # pylint: disable=broad-except + _LOGGER.exception("failed to fetch datapoints") + errors["base"] = "fetch_dps_failed" + + return self.async_show_form( + step_id="debug", + data_schema=debug_schema(self.dps_strings), + errors=errors, + description_placeholders={"dps": ", ".join(self.dps_strings)}, + ) + class LocalTuyaOptionsFlowHandler(config_entries.OptionsFlow): """Handle options flow for LocalTuya integration.""" diff --git a/custom_components/localtuya/translations/en.json b/custom_components/localtuya/translations/en.json index 3193735e8..cb6b5c20c 100644 --- a/custom_components/localtuya/translations/en.json +++ b/custom_components/localtuya/translations/en.json @@ -1,14 +1,17 @@ { "config": { "abort": { - "already_configured": "Device has already been configured." + "already_configured": "Device has already been configured.", + "exit_debug": "Leaving debug mode." }, "error": { "cannot_connect": "Cannot connect to device. Verify that address is correct and try again.", "invalid_auth": "Failed to authenticate with device. Verify that device id and local key are correct.", "unknown": "An unknown error occurred. See log for details.", "entity_already_configured": "Entity with this ID has already been configured.", - "discovery_failed": "Failed to discover devices. You can still add a device manually." + "discovery_failed": "Failed to discover devices. You can still add a device manually.", + "fetch_dps_failed": "Failed to fetch datapoints. See log for details.", + "set_dp_failed": "Failed to set datapoint. See log for details." }, "step": { "user": { @@ -26,7 +29,8 @@ "host": "Host", "device_id": "Device ID", "local_key": "Local key", - "protocol_version": "Protocol Version" + "protocol_version": "Protocol Version", + "debug": "Enable debug mode" } }, "pick_entity_type": { @@ -61,6 +65,16 @@ "brightness_upper": "Brightness Upper Value", "color_temp": "Color Temperature" } + }, + "debug": { + "title": "Debug", + "description": "You can manually alter the value of a datapoint here. Current values for all datapoints:\n\n{dps}", + "data": { + "action": "Action", + "datapoint": "Datapoint", + "data_type": "Data Type", + "value": "Value" + } } } },