diff --git a/homeassistant/components/tasmota/config_flow.py b/homeassistant/components/tasmota/config_flow.py index 85959ef0674..435604b4bdd 100644 --- a/homeassistant/components/tasmota/config_flow.py +++ b/homeassistant/components/tasmota/config_flow.py @@ -29,16 +29,17 @@ class FlowHandler(config_entries.ConfigFlow, domain=DOMAIN): await self.async_set_unique_id(DOMAIN) - # Validate the topic, will throw if it fails - prefix = discovery_info["subscribed_topic"] - if prefix.endswith("/#"): - prefix = prefix[:-2] - try: - valid_subscribe_topic(f"{prefix}/#") - except vol.Invalid: + # Validate the message, abort if it fails + if not discovery_info["topic"].endswith("/config"): + # Not a Tasmota discovery message + return self.async_abort(reason="invalid_discovery_info") + if not discovery_info["payload"]: + # Empty payload, the Tasmota is not configured for native discovery return self.async_abort(reason="invalid_discovery_info") - self._prefix = prefix + # "tasmota/discovery/#" is hardcoded in Tasmota's manifest + assert discovery_info["subscribed_topic"] == "tasmota/discovery/#" + self._prefix = "tasmota/discovery" return await self.async_step_confirm() diff --git a/tests/components/tasmota/test_config_flow.py b/tests/components/tasmota/test_config_flow.py index c97ffb9edb8..7d6d0628de1 100644 --- a/tests/components/tasmota/test_config_flow.py +++ b/tests/components/tasmota/test_config_flow.py @@ -19,11 +19,20 @@ async def test_mqtt_abort_if_existing_entry(hass, mqtt_mock): async def test_mqtt_abort_invalid_topic(hass, mqtt_mock): """Check MQTT flow aborts if discovery topic is invalid.""" discovery_info = { - "topic": "", - "payload": "", + "topic": "tasmota/discovery/DC4F220848A2/bla", + "payload": ( + '{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,' + 'null,null,null],"hn":"tasmota_0848A2","mac":"DC4F220848A2","md":"Sonoff Basic",' + '"ty":0,"if":0,"ofln":"Offline","onln":"Online","state":["OFF","ON",' + '"TOGGLE","HOLD"],"sw":"9.4.0.4","t":"tasmota_0848A2","ft":"%topic%/%prefix%/",' + '"tp":["cmnd","stat","tele"],"rl":[1,0,0,0,0,0,0,0],"swc":[-1,-1,-1,-1,-1,-1,-1,-1],' + '"swn":[null,null,null,null,null,null,null,null],"btn":[0,0,0,0,0,0,0,0],' + '"so":{"4":0,"11":0,"13":0,"17":1,"20":0,"30":0,"68":0,"73":0,"82":0,"114":1,"117":0},' + '"lk":1,"lt_st":0,"sho":[0,0,0,0],"ver":1}' + ), "qos": 0, "retain": False, - "subscribed_topic": "custom_prefix/##", + "subscribed_topic": "tasmota/discovery/#", "timestamp": None, } result = await hass.config_entries.flow.async_init( @@ -32,15 +41,60 @@ async def test_mqtt_abort_invalid_topic(hass, mqtt_mock): assert result["type"] == "abort" assert result["reason"] == "invalid_discovery_info" + discovery_info = { + "topic": "tasmota/discovery/DC4F220848A2/config", + "payload": "", + "qos": 0, + "retain": False, + "subscribed_topic": "tasmota/discovery/#", + "timestamp": None, + } + result = await hass.config_entries.flow.async_init( + "tasmota", context={"source": config_entries.SOURCE_MQTT}, data=discovery_info + ) + assert result["type"] == "abort" + assert result["reason"] == "invalid_discovery_info" + + discovery_info = { + "topic": "tasmota/discovery/DC4F220848A2/config", + "payload": ( + '{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,' + 'null,null,null],"hn":"tasmota_0848A2","mac":"DC4F220848A2","md":"Sonoff Basic",' + '"ty":0,"if":0,"ofln":"Offline","onln":"Online","state":["OFF","ON",' + '"TOGGLE","HOLD"],"sw":"9.4.0.4","t":"tasmota_0848A2","ft":"%topic%/%prefix%/",' + '"tp":["cmnd","stat","tele"],"rl":[1,0,0,0,0,0,0,0],"swc":[-1,-1,-1,-1,-1,-1,-1,-1],' + '"swn":[null,null,null,null,null,null,null,null],"btn":[0,0,0,0,0,0,0,0],' + '"so":{"4":0,"11":0,"13":0,"17":1,"20":0,"30":0,"68":0,"73":0,"82":0,"114":1,"117":0},' + '"lk":1,"lt_st":0,"sho":[0,0,0,0],"ver":1}' + ), + "qos": 0, + "retain": False, + "subscribed_topic": "tasmota/discovery/#", + "timestamp": None, + } + result = await hass.config_entries.flow.async_init( + "tasmota", context={"source": config_entries.SOURCE_MQTT}, data=discovery_info + ) + assert result["type"] == "form" + async def test_mqtt_setup(hass, mqtt_mock) -> None: """Test we can finish a config flow through MQTT with custom prefix.""" discovery_info = { - "topic": "", - "payload": "", + "topic": "tasmota/discovery/DC4F220848A2/config", + "payload": ( + '{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,' + 'null,null,null],"hn":"tasmota_0848A2","mac":"DC4F220848A2","md":"Sonoff Basic",' + '"ty":0,"if":0,"ofln":"Offline","onln":"Online","state":["OFF","ON",' + '"TOGGLE","HOLD"],"sw":"9.4.0.4","t":"tasmota_0848A2","ft":"%topic%/%prefix%/",' + '"tp":["cmnd","stat","tele"],"rl":[1,0,0,0,0,0,0,0],"swc":[-1,-1,-1,-1,-1,-1,-1,-1],' + '"swn":[null,null,null,null,null,null,null,null],"btn":[0,0,0,0,0,0,0,0],' + '"so":{"4":0,"11":0,"13":0,"17":1,"20":0,"30":0,"68":0,"73":0,"82":0,"114":1,"117":0},' + '"lk":1,"lt_st":0,"sho":[0,0,0,0],"ver":1}' + ), "qos": 0, "retain": False, - "subscribed_topic": "custom_prefix/123/#", + "subscribed_topic": "tasmota/discovery/#", "timestamp": None, } result = await hass.config_entries.flow.async_init( @@ -51,9 +105,7 @@ async def test_mqtt_setup(hass, mqtt_mock) -> None: result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) assert result["type"] == "create_entry" - assert result["result"].data == { - "discovery_prefix": "custom_prefix/123", - } + assert result["result"].data == {"discovery_prefix": "tasmota/discovery"} async def test_user_setup(hass, mqtt_mock):