async def async_step_config(self, user_input: dict[str, Any] | None = None ) -> FlowResult: """Confirm the setup.""" errors = {} data = {CONF_DISCOVERY_PREFIX: self._prefix} if user_input is not None: bad_prefix = False prefix = user_input[CONF_DISCOVERY_PREFIX] if prefix.endswith("/#"): prefix = prefix[:-2] try: valid_subscribe_topic(f"{prefix}/#") except vol.Invalid: errors["base"] = "invalid_discovery_topic" bad_prefix = True else: data[CONF_DISCOVERY_PREFIX] = prefix if not bad_prefix: return self.async_create_entry(title="Tasmota", data=data) fields = {} fields[vol.Optional(CONF_DISCOVERY_PREFIX, default=self._prefix)] = str return self.async_show_form(step_id="config", data_schema=vol.Schema(fields), errors=errors)
async def async_step_config(self, user_input=None): """Confirm the setup.""" errors = {} data = {CONF_OPENWB_BASE_TOPIC: self._basetopic} if user_input is not None: bad_basetopic = False basetopic = user_input[CONF_OPENWB_BASE_TOPIC] if basetopic.endswith("/#"): basetopic = basetopic[:-2] try: valid_subscribe_topic(f"{basetopic}/#") except vol.Invalid: errors["base"] = "invalid_discovery_topic" bad_basetopic = True else: data[CONF_OPENWB_BASE_TOPIC] = basetopic if not bad_basetopic: return self.async_create_entry(title="OpenWB", data=data) fields = {} fields[vol.Optional(CONF_OPENWB_BASE_TOPIC, default=self._basetopic)] = str return self.async_show_form(step_id="config", data_schema=vol.Schema(fields), errors=errors)
async def async_step_gw_mqtt(self, user_input: dict[str, Any] | None = None ) -> FlowResult: """Create a config entry for a mqtt gateway.""" # Naive check that doesn't consider config entry state. if MQTT_DOMAIN not in self.hass.config.components: return self.async_abort(reason="mqtt_required") gw_type = self._gw_type = CONF_GATEWAY_TYPE_MQTT errors: dict[str, str] = {} if user_input is not None: user_input[CONF_DEVICE] = MQTT_COMPONENT try: valid_subscribe_topic(user_input[CONF_TOPIC_IN_PREFIX]) except vol.Invalid: errors[CONF_TOPIC_IN_PREFIX] = "invalid_subscribe_topic" else: if self._check_topic_exists(user_input[CONF_TOPIC_IN_PREFIX]): errors[CONF_TOPIC_IN_PREFIX] = "duplicate_topic" try: valid_publish_topic(user_input[CONF_TOPIC_OUT_PREFIX]) except vol.Invalid: errors[CONF_TOPIC_OUT_PREFIX] = "invalid_publish_topic" if not errors: if (user_input[CONF_TOPIC_IN_PREFIX] == user_input[CONF_TOPIC_OUT_PREFIX]): errors[CONF_TOPIC_OUT_PREFIX] = "same_topic" elif self._check_topic_exists( user_input[CONF_TOPIC_OUT_PREFIX]): errors[CONF_TOPIC_OUT_PREFIX] = "duplicate_topic" errors.update(await self.validate_common(gw_type, errors, user_input)) if not errors: return self._async_create_entry(user_input) user_input = user_input or {} schema = { vol.Required(CONF_TOPIC_IN_PREFIX, default=user_input.get(CONF_TOPIC_IN_PREFIX, "")): str, vol.Required(CONF_TOPIC_OUT_PREFIX, default=user_input.get(CONF_TOPIC_OUT_PREFIX, "")): str, vol.Required(CONF_RETAIN, default=user_input.get(CONF_RETAIN, True)): bool, } schema.update(_get_schema_common(user_input)) schema = vol.Schema(schema) return self.async_show_form(step_id="gw_mqtt", data_schema=schema, errors=errors)
async def async_step_gw_mqtt( self, user_input: dict[str, Any] | None = None ) -> FlowResult: """Create a config entry for a mqtt gateway.""" errors = {} if user_input is not None: user_input[CONF_DEVICE] = MQTT_COMPONENT try: valid_subscribe_topic(user_input[CONF_TOPIC_IN_PREFIX]) except vol.Invalid: errors[CONF_TOPIC_IN_PREFIX] = "invalid_subscribe_topic" else: if self._check_topic_exists(user_input[CONF_TOPIC_IN_PREFIX]): errors[CONF_TOPIC_IN_PREFIX] = "duplicate_topic" try: valid_publish_topic(user_input[CONF_TOPIC_OUT_PREFIX]) except vol.Invalid: errors[CONF_TOPIC_OUT_PREFIX] = "invalid_publish_topic" if not errors: if ( user_input[CONF_TOPIC_IN_PREFIX] == user_input[CONF_TOPIC_OUT_PREFIX] ): errors[CONF_TOPIC_OUT_PREFIX] = "same_topic" elif self._check_topic_exists(user_input[CONF_TOPIC_OUT_PREFIX]): errors[CONF_TOPIC_OUT_PREFIX] = "duplicate_topic" errors.update( await self.validate_common(CONF_GATEWAY_TYPE_MQTT, errors, user_input) ) if not errors: return self._async_create_entry(user_input) user_input = user_input or {} schema = _get_schema_common(user_input) schema[ vol.Required(CONF_RETAIN, default=user_input.get(CONF_RETAIN, True)) ] = bool schema[ vol.Required( CONF_TOPIC_IN_PREFIX, default=user_input.get(CONF_TOPIC_IN_PREFIX, "") ) ] = str schema[ vol.Required( CONF_TOPIC_OUT_PREFIX, default=user_input.get(CONF_TOPIC_OUT_PREFIX, "") ) ] = str schema = vol.Schema(schema) return self.async_show_form( step_id="gw_mqtt", data_schema=schema, errors=errors )
def _validate_topics(self, user_input: dict[str, Any]) -> None: topics = {x.strip() for x in user_input[CONF_MQTT_TOPICS].split(",")} if not topics: self.errors[ CONF_MQTT_TOPICS] = VALIDATION_ERROR_MQTT_INVALID_SUBSCRIBE_TOPIC for topic in topics: try: mqtt.valid_subscribe_topic(topic) except vol.Invalid: self.errors[ CONF_MQTT_TOPICS] = VALIDATION_ERROR_MQTT_INVALID_SUBSCRIBE_TOPIC
async def async_step_mqtt(self, discovery_info=None): """Handle a flow initialized by MQTT discovery.""" if self._async_in_progress() or self._async_current_entries(): return self.async_abort(reason="single_instance_allowed") 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: return self.async_abort(reason="invalid_discovery_info") self._prefix = prefix return await self.async_step_confirm()
def test_validate_subscribe_topic(self): """Test invalid subscribe topics.""" mqtt.valid_subscribe_topic('#') mqtt.valid_subscribe_topic('sport/#') with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic('sport/#/') with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic('foo/bar#') with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic('foo/#/bar') mqtt.valid_subscribe_topic('+') mqtt.valid_subscribe_topic('+/tennis/#') with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic('sport+') with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic('sport+/') with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic('sport/+1') with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic('sport/+#') with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic('bad+topic') mqtt.valid_subscribe_topic('sport/+/player1') mqtt.valid_subscribe_topic('/finance') mqtt.valid_subscribe_topic('+/+') mqtt.valid_subscribe_topic('$SYS/#')
def test_validate_subscribe_topic(): """Test invalid subscribe topics.""" mqtt.valid_subscribe_topic("#") mqtt.valid_subscribe_topic("sport/#") with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic("sport/#/") with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic("foo/bar#") with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic("foo/#/bar") mqtt.valid_subscribe_topic("+") mqtt.valid_subscribe_topic("+/tennis/#") with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic("sport+") with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic("sport+/") with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic("sport/+1") with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic("sport/+#") with pytest.raises(vol.Invalid): mqtt.valid_subscribe_topic("bad+topic") mqtt.valid_subscribe_topic("sport/+/player1") mqtt.valid_subscribe_topic("/finance") mqtt.valid_subscribe_topic("+/+") mqtt.valid_subscribe_topic("$SYS/#")