test_config_flow.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. """Tests for the config flow."""
  2. from unittest.mock import ANY, AsyncMock, MagicMock, patch
  3. import pytest
  4. import voluptuous as vol
  5. from homeassistant.const import CONF_HOST, CONF_NAME
  6. from homeassistant.data_entry_flow import FlowResultType
  7. from pytest_homeassistant_custom_component.common import MockConfigEntry
  8. from custom_components.tuya_local import (
  9. async_migrate_entry,
  10. config_flow,
  11. )
  12. from custom_components.tuya_local.const import (
  13. CONF_DEVICE_CID,
  14. CONF_DEVICE_ID,
  15. CONF_LOCAL_KEY,
  16. CONF_POLL_ONLY,
  17. CONF_PROTOCOL_VERSION,
  18. CONF_TYPE,
  19. DOMAIN,
  20. )
  21. # Designed to contain "special" characters that users constantly suspect.
  22. TESTKEY = ")<jO<@)'P1|kR$Kd"
  23. @pytest.fixture(autouse=True)
  24. def auto_enable_custom_integrations(enable_custom_integrations):
  25. yield
  26. @pytest.fixture(autouse=True)
  27. def prevent_task_creation():
  28. with patch(
  29. "custom_components.tuya_local.device.TuyaLocalDevice.register_entity",
  30. ):
  31. yield
  32. @pytest.fixture
  33. def bypass_setup():
  34. """Prevent actual setup of the integration after config flow."""
  35. with patch(
  36. "custom_components.tuya_local.async_setup_entry",
  37. return_value=True,
  38. ):
  39. yield
  40. @pytest.mark.asyncio
  41. async def test_init_entry(hass):
  42. """Test initialisation of the config flow."""
  43. entry = MockConfigEntry(
  44. domain=DOMAIN,
  45. version=11,
  46. title="test",
  47. data={
  48. CONF_DEVICE_ID: "deviceid",
  49. CONF_HOST: "hostname",
  50. CONF_LOCAL_KEY: TESTKEY,
  51. CONF_POLL_ONLY: False,
  52. CONF_PROTOCOL_VERSION: "auto",
  53. CONF_TYPE: "kogan_kahtp_heater",
  54. CONF_DEVICE_CID: None,
  55. },
  56. options={},
  57. )
  58. entry.add_to_hass(hass)
  59. await hass.config_entries.async_setup(entry.entry_id)
  60. await hass.async_block_till_done()
  61. assert hass.states.get("climate.test")
  62. assert hass.states.get("lock.test_child_lock")
  63. @pytest.mark.asyncio
  64. @patch("custom_components.tuya_local.setup_device")
  65. async def test_migrate_entry(mock_setup, hass):
  66. """Test migration from old entry format."""
  67. mock_device = MagicMock()
  68. mock_device.async_inferred_type = AsyncMock(return_value="goldair_gpph_heater")
  69. mock_setup.return_value = mock_device
  70. entry = MockConfigEntry(
  71. domain=DOMAIN,
  72. version=1,
  73. title="test",
  74. data={
  75. CONF_DEVICE_ID: "deviceid",
  76. CONF_HOST: "hostname",
  77. CONF_LOCAL_KEY: TESTKEY,
  78. CONF_TYPE: "auto",
  79. "climate": True,
  80. "child_lock": True,
  81. "display_light": True,
  82. },
  83. )
  84. entry.add_to_hass(hass)
  85. assert await async_migrate_entry(hass, entry)
  86. mock_device.async_inferred_type = AsyncMock(return_value=None)
  87. mock_device.reset_mock()
  88. entry = MockConfigEntry(
  89. domain=DOMAIN,
  90. version=1,
  91. title="test2",
  92. data={
  93. CONF_DEVICE_ID: "deviceid",
  94. CONF_HOST: "hostname",
  95. CONF_LOCAL_KEY: TESTKEY,
  96. CONF_TYPE: "unknown",
  97. "climate": False,
  98. },
  99. )
  100. entry.add_to_hass(hass)
  101. assert not await async_migrate_entry(hass, entry)
  102. mock_device.reset_mock()
  103. entry = MockConfigEntry(
  104. domain=DOMAIN,
  105. version=2,
  106. title="test3",
  107. data={
  108. CONF_DEVICE_ID: "deviceid",
  109. CONF_HOST: "hostname",
  110. CONF_LOCAL_KEY: TESTKEY,
  111. CONF_TYPE: "auto",
  112. },
  113. options={
  114. "climate": False,
  115. },
  116. )
  117. entry.add_to_hass(hass)
  118. assert not await async_migrate_entry(hass, entry)
  119. mock_device.async_inferred_type = AsyncMock(return_value="smartplugv1")
  120. mock_device.reset_mock()
  121. entry = MockConfigEntry(
  122. domain=DOMAIN,
  123. version=3,
  124. title="test4",
  125. data={
  126. CONF_DEVICE_ID: "deviceid",
  127. CONF_HOST: "hostname",
  128. CONF_LOCAL_KEY: TESTKEY,
  129. CONF_TYPE: "smartplugv1",
  130. },
  131. options={
  132. "switch": True,
  133. },
  134. )
  135. entry.add_to_hass(hass)
  136. assert await async_migrate_entry(hass, entry)
  137. mock_device.async_inferred_type = AsyncMock(return_value="smartplugv2")
  138. mock_device.reset_mock()
  139. entry = MockConfigEntry(
  140. domain=DOMAIN,
  141. version=3,
  142. title="test5",
  143. data={
  144. CONF_DEVICE_ID: "deviceid",
  145. CONF_HOST: "hostname",
  146. CONF_LOCAL_KEY: TESTKEY,
  147. CONF_TYPE: "smartplugv1",
  148. },
  149. options={
  150. "switch": True,
  151. },
  152. )
  153. entry.add_to_hass(hass)
  154. assert await async_migrate_entry(hass, entry)
  155. mock_device.async_inferred_type = AsyncMock(return_value="goldair_dehumidifier")
  156. mock_device.reset_mock()
  157. entry = MockConfigEntry(
  158. domain=DOMAIN,
  159. version=4,
  160. title="test6",
  161. data={
  162. CONF_DEVICE_ID: "deviceid",
  163. CONF_HOST: "hostname",
  164. CONF_LOCAL_KEY: TESTKEY,
  165. CONF_TYPE: "goldair_dehumidifier",
  166. },
  167. options={
  168. "humidifier": True,
  169. "fan": True,
  170. "light": True,
  171. "lock": False,
  172. "switch": True,
  173. },
  174. )
  175. entry.add_to_hass(hass)
  176. assert await async_migrate_entry(hass, entry)
  177. mock_device.async_inferred_type = AsyncMock(
  178. return_value="grid_connect_usb_double_power_point"
  179. )
  180. mock_device.reset_mock()
  181. entry = MockConfigEntry(
  182. domain=DOMAIN,
  183. version=6,
  184. title="test7",
  185. data={
  186. CONF_DEVICE_ID: "deviceid",
  187. CONF_HOST: "hostname",
  188. CONF_LOCAL_KEY: TESTKEY,
  189. CONF_TYPE: "grid_connect_usb_double_power_point",
  190. },
  191. options={
  192. "switch_main_switch": True,
  193. "switch_left_outlet": True,
  194. "switch_right_outlet": True,
  195. },
  196. )
  197. entry.add_to_hass(hass)
  198. assert await async_migrate_entry(hass, entry)
  199. @pytest.mark.asyncio
  200. async def test_flow_user_init(hass):
  201. """Test the initialisation of the form in the first page of the manual config flow path."""
  202. result = await hass.config_entries.flow.async_init(
  203. DOMAIN, context={"source": "local"}
  204. )
  205. expected = {
  206. "data_schema": ANY,
  207. "description_placeholders": None,
  208. "errors": {},
  209. "flow_id": ANY,
  210. "handler": DOMAIN,
  211. "step_id": "local",
  212. "type": "form",
  213. "last_step": ANY,
  214. "preview": ANY,
  215. }
  216. assert expected == result
  217. # Check the schema. Simple comparison does not work since they are not
  218. # the same object
  219. try:
  220. result["data_schema"](
  221. {CONF_DEVICE_ID: "test", CONF_LOCAL_KEY: TESTKEY, CONF_HOST: "test"}
  222. )
  223. except vol.MultipleInvalid:
  224. assert False
  225. try:
  226. result["data_schema"]({CONF_DEVICE_ID: "missing_some"})
  227. assert False
  228. except vol.MultipleInvalid:
  229. pass
  230. @pytest.mark.asyncio
  231. @patch("custom_components.tuya_local.config_flow.TuyaLocalDevice")
  232. async def test_async_test_connection_valid(mock_device, hass):
  233. """Test that device is returned when connection is valid."""
  234. mock_instance = AsyncMock()
  235. mock_instance.has_returned_state = True
  236. mock_instance.pause = MagicMock()
  237. mock_instance.resume = MagicMock()
  238. mock_device.return_value = mock_instance
  239. hass.data[DOMAIN] = {"deviceid": {"device": mock_instance}}
  240. device = await config_flow.async_test_connection(
  241. {
  242. CONF_DEVICE_ID: "deviceid",
  243. CONF_LOCAL_KEY: TESTKEY,
  244. CONF_HOST: "hostname",
  245. CONF_PROTOCOL_VERSION: "auto",
  246. },
  247. hass,
  248. )
  249. assert device == mock_instance
  250. mock_instance.pause.assert_called_once()
  251. mock_instance.resume.assert_called_once()
  252. @pytest.mark.asyncio
  253. @patch("custom_components.tuya_local.config_flow.TuyaLocalDevice")
  254. async def test_async_test_connection_for_subdevice_valid(mock_device, hass):
  255. """Test that subdevice is returned when connection is valid."""
  256. mock_instance = AsyncMock()
  257. mock_instance.has_returned_state = True
  258. mock_instance.pause = MagicMock()
  259. mock_instance.resume = MagicMock()
  260. mock_device.return_value = mock_instance
  261. hass.data[DOMAIN] = {"subdeviceid": {"device": mock_instance}}
  262. device = await config_flow.async_test_connection(
  263. {
  264. CONF_DEVICE_ID: "deviceid",
  265. CONF_LOCAL_KEY: TESTKEY,
  266. CONF_HOST: "hostname",
  267. CONF_PROTOCOL_VERSION: "auto",
  268. CONF_DEVICE_CID: "subdeviceid",
  269. },
  270. hass,
  271. )
  272. assert device == mock_instance
  273. mock_instance.pause.assert_called_once()
  274. mock_instance.resume.assert_called_once()
  275. @pytest.mark.asyncio
  276. @patch("custom_components.tuya_local.config_flow.TuyaLocalDevice")
  277. async def test_async_test_connection_invalid(mock_device, hass):
  278. """Test that None is returned when connection is invalid."""
  279. mock_instance = AsyncMock()
  280. mock_instance.has_returned_state = False
  281. mock_device.return_value = mock_instance
  282. device = await config_flow.async_test_connection(
  283. {
  284. CONF_DEVICE_ID: "deviceid",
  285. CONF_LOCAL_KEY: TESTKEY,
  286. CONF_HOST: "hostname",
  287. CONF_PROTOCOL_VERSION: "auto",
  288. },
  289. hass,
  290. )
  291. assert device is None
  292. @pytest.mark.asyncio
  293. @patch("custom_components.tuya_local.config_flow.async_test_connection")
  294. async def test_flow_user_init_invalid_config(mock_test, hass):
  295. """Test errors populated when config is invalid."""
  296. mock_test.return_value = None
  297. flow = await hass.config_entries.flow.async_init(
  298. DOMAIN, context={"source": "local"}
  299. )
  300. result = await hass.config_entries.flow.async_configure(
  301. flow["flow_id"],
  302. user_input={
  303. CONF_DEVICE_ID: "deviceid",
  304. CONF_HOST: "hostname",
  305. CONF_LOCAL_KEY: "badkey",
  306. CONF_PROTOCOL_VERSION: "auto",
  307. CONF_POLL_ONLY: False,
  308. },
  309. )
  310. assert {"base": "connection"} == result["errors"]
  311. def setup_device_mock(mock, failure=False, type="test"):
  312. mock_type = MagicMock()
  313. mock_type.legacy_type = type
  314. mock_type.config_type = type
  315. mock_type.match_quality.return_value = 100
  316. mock.async_possible_types = AsyncMock(
  317. return_value=[mock_type] if not failure else []
  318. )
  319. @pytest.mark.asyncio
  320. @patch("custom_components.tuya_local.config_flow.async_test_connection")
  321. async def test_flow_user_init_data_valid(mock_test, hass):
  322. """Test we advance to the next step when connection config is valid."""
  323. mock_device = MagicMock()
  324. setup_device_mock(mock_device)
  325. mock_test.return_value = mock_device
  326. flow = await hass.config_entries.flow.async_init(
  327. DOMAIN, context={"source": "local"}
  328. )
  329. result = await hass.config_entries.flow.async_configure(
  330. flow["flow_id"],
  331. user_input={
  332. CONF_DEVICE_ID: "deviceid",
  333. CONF_HOST: "hostname",
  334. CONF_LOCAL_KEY: TESTKEY,
  335. },
  336. )
  337. assert "form" == result["type"]
  338. assert "select_type" == result["step_id"]
  339. @pytest.mark.asyncio
  340. @patch.object(config_flow.ConfigFlowHandler, "device")
  341. async def test_flow_select_type_init(mock_device, hass):
  342. """Test the initialisation of the form in the 2nd step of the config flow."""
  343. setup_device_mock(mock_device)
  344. result = await hass.config_entries.flow.async_init(
  345. DOMAIN, context={"source": "select_type"}
  346. )
  347. expected = {
  348. "data_schema": ANY,
  349. "description_placeholders": None,
  350. "errors": None,
  351. "flow_id": ANY,
  352. "handler": DOMAIN,
  353. "step_id": "select_type",
  354. "type": "form",
  355. "last_step": ANY,
  356. "preview": ANY,
  357. }
  358. assert expected == result
  359. # Check the schema. Simple comparison does not work since they are not
  360. # the same object
  361. try:
  362. result["data_schema"]({CONF_TYPE: "test"})
  363. except vol.MultipleInvalid:
  364. assert False
  365. try:
  366. result["data_schema"]({CONF_TYPE: "not_test"})
  367. assert False
  368. except vol.MultipleInvalid:
  369. pass
  370. @pytest.mark.asyncio
  371. @patch.object(config_flow.ConfigFlowHandler, "device")
  372. async def test_flow_select_type_aborts_when_no_match(mock_device, hass):
  373. """Test the flow aborts when an unsupported device is used."""
  374. setup_device_mock(mock_device, failure=True)
  375. result = await hass.config_entries.flow.async_init(
  376. DOMAIN, context={"source": "select_type"}
  377. )
  378. assert result["type"] == "abort"
  379. assert result["reason"] == "not_supported"
  380. @pytest.mark.asyncio
  381. @patch.object(config_flow.ConfigFlowHandler, "device")
  382. async def test_flow_select_type_data_valid(mock_device, hass):
  383. """Test the flow continues when valid data is supplied."""
  384. setup_device_mock(mock_device, type="smartplugv1")
  385. flow = await hass.config_entries.flow.async_init(
  386. DOMAIN, context={"source": "select_type"}
  387. )
  388. result = await hass.config_entries.flow.async_configure(
  389. flow["flow_id"],
  390. user_input={CONF_TYPE: "smartplugv1"},
  391. )
  392. assert "form" == result["type"]
  393. assert "choose_entities" == result["step_id"]
  394. @pytest.mark.asyncio
  395. async def test_flow_choose_entities_init(hass):
  396. """Test the initialisation of the form in the 3rd step of the config flow."""
  397. with patch.dict(config_flow.ConfigFlowHandler.data, {CONF_TYPE: "smartplugv1"}):
  398. result = await hass.config_entries.flow.async_init(
  399. DOMAIN, context={"source": "choose_entities"}
  400. )
  401. expected = {
  402. "data_schema": ANY,
  403. "description_placeholders": None,
  404. "errors": None,
  405. "flow_id": ANY,
  406. "handler": DOMAIN,
  407. "step_id": "choose_entities",
  408. "type": "form",
  409. "last_step": ANY,
  410. "preview": ANY,
  411. }
  412. assert expected == result
  413. # Check the schema. Simple comparison does not work since they are not
  414. # the same object
  415. try:
  416. result["data_schema"]({CONF_NAME: "test"})
  417. except vol.MultipleInvalid:
  418. assert False
  419. try:
  420. result["data_schema"]({"climate": True})
  421. assert False
  422. except vol.MultipleInvalid:
  423. pass
  424. @pytest.mark.asyncio
  425. async def test_flow_choose_entities_creates_config_entry(hass, bypass_setup):
  426. """Test the flow ends when data is valid."""
  427. with patch.dict(
  428. config_flow.ConfigFlowHandler.data,
  429. {
  430. CONF_DEVICE_ID: "deviceid",
  431. CONF_LOCAL_KEY: TESTKEY,
  432. CONF_HOST: "hostname",
  433. CONF_POLL_ONLY: False,
  434. CONF_PROTOCOL_VERSION: "auto",
  435. CONF_TYPE: "kogan_kahtp_heater",
  436. CONF_DEVICE_CID: None,
  437. },
  438. ):
  439. flow = await hass.config_entries.flow.async_init(
  440. DOMAIN, context={"source": "choose_entities"}
  441. )
  442. result = await hass.config_entries.flow.async_configure(
  443. flow["flow_id"],
  444. user_input={
  445. CONF_NAME: "test",
  446. },
  447. )
  448. expected = {
  449. "version": 13,
  450. "minor_version": ANY,
  451. "context": {"source": "choose_entities"},
  452. "type": FlowResultType.CREATE_ENTRY,
  453. "flow_id": ANY,
  454. "handler": DOMAIN,
  455. "title": "test",
  456. "description": None,
  457. "description_placeholders": None,
  458. "result": ANY,
  459. "subentries": (),
  460. "options": {},
  461. "data": {
  462. CONF_DEVICE_ID: "deviceid",
  463. CONF_HOST: "hostname",
  464. CONF_LOCAL_KEY: TESTKEY,
  465. CONF_POLL_ONLY: False,
  466. CONF_PROTOCOL_VERSION: "auto",
  467. CONF_TYPE: "kogan_kahtp_heater",
  468. CONF_DEVICE_CID: None,
  469. },
  470. }
  471. assert expected == result
  472. @pytest.mark.asyncio
  473. async def test_options_flow_init(hass):
  474. """Test config flow options."""
  475. config_entry = MockConfigEntry(
  476. domain=DOMAIN,
  477. version=13,
  478. unique_id="uniqueid",
  479. data={
  480. CONF_DEVICE_ID: "deviceid",
  481. CONF_HOST: "hostname",
  482. CONF_LOCAL_KEY: TESTKEY,
  483. CONF_NAME: "test",
  484. CONF_POLL_ONLY: False,
  485. CONF_PROTOCOL_VERSION: "auto",
  486. CONF_TYPE: "smartplugv1",
  487. CONF_DEVICE_CID: "",
  488. },
  489. )
  490. config_entry.add_to_hass(hass)
  491. assert await hass.config_entries.async_setup(config_entry.entry_id)
  492. await hass.async_block_till_done()
  493. # show initial form
  494. result = await hass.config_entries.options.async_init(config_entry.entry_id)
  495. assert "form" == result["type"]
  496. assert "user" == result["step_id"]
  497. assert {} == result["errors"]
  498. assert result["data_schema"](
  499. {
  500. CONF_HOST: "hostname",
  501. CONF_LOCAL_KEY: TESTKEY,
  502. }
  503. )
  504. @pytest.mark.asyncio
  505. @patch("custom_components.tuya_local.config_flow.async_test_connection")
  506. async def test_options_flow_modifies_config(mock_test, hass, bypass_setup):
  507. mock_device = MagicMock()
  508. mock_test.return_value = mock_device
  509. config_entry = MockConfigEntry(
  510. domain=DOMAIN,
  511. version=13,
  512. unique_id="uniqueid",
  513. data={
  514. CONF_DEVICE_ID: "deviceid",
  515. CONF_HOST: "hostname",
  516. CONF_LOCAL_KEY: TESTKEY,
  517. CONF_NAME: "test",
  518. CONF_POLL_ONLY: False,
  519. CONF_PROTOCOL_VERSION: "auto",
  520. CONF_TYPE: "ble_pt216_temp_humidity",
  521. CONF_DEVICE_CID: "subdeviceid",
  522. },
  523. )
  524. config_entry.add_to_hass(hass)
  525. assert await hass.config_entries.async_setup(config_entry.entry_id)
  526. await hass.async_block_till_done()
  527. # show initial form
  528. form = await hass.config_entries.options.async_init(config_entry.entry_id)
  529. # submit updated config
  530. result = await hass.config_entries.options.async_configure(
  531. form["flow_id"],
  532. user_input={
  533. CONF_HOST: "new_hostname",
  534. CONF_LOCAL_KEY: "new_key",
  535. CONF_POLL_ONLY: False,
  536. CONF_PROTOCOL_VERSION: 3.3,
  537. },
  538. )
  539. expected = {
  540. CONF_HOST: "new_hostname",
  541. CONF_LOCAL_KEY: "new_key",
  542. CONF_POLL_ONLY: False,
  543. CONF_PROTOCOL_VERSION: 3.3,
  544. }
  545. assert "create_entry" == result["type"]
  546. assert "" == result["title"]
  547. assert result["result"] is True
  548. assert expected == result["data"]
  549. @pytest.mark.asyncio
  550. @patch("custom_components.tuya_local.config_flow.async_test_connection")
  551. async def test_options_flow_fails_when_connection_fails(mock_test, hass):
  552. mock_test.return_value = None
  553. config_entry = MockConfigEntry(
  554. domain=DOMAIN,
  555. version=13,
  556. unique_id="uniqueid",
  557. data={
  558. CONF_DEVICE_ID: "deviceid",
  559. CONF_HOST: "hostname",
  560. CONF_LOCAL_KEY: TESTKEY,
  561. CONF_NAME: "test",
  562. CONF_POLL_ONLY: False,
  563. CONF_PROTOCOL_VERSION: "auto",
  564. CONF_TYPE: "smartplugv1",
  565. CONF_DEVICE_CID: "",
  566. },
  567. )
  568. config_entry.add_to_hass(hass)
  569. assert await hass.config_entries.async_setup(config_entry.entry_id)
  570. await hass.async_block_till_done()
  571. # show initial form
  572. form = await hass.config_entries.options.async_init(config_entry.entry_id)
  573. # submit updated config
  574. result = await hass.config_entries.options.async_configure(
  575. form["flow_id"],
  576. user_input={
  577. CONF_HOST: "new_hostname",
  578. CONF_LOCAL_KEY: "new_key",
  579. },
  580. )
  581. assert "form" == result["type"]
  582. assert "user" == result["step_id"]
  583. assert {"base": "connection"} == result["errors"]
  584. @pytest.mark.asyncio
  585. @patch("custom_components.tuya_local.config_flow.async_test_connection")
  586. async def test_options_flow_fails_when_config_is_missing(mock_test, hass):
  587. mock_device = MagicMock()
  588. mock_test.return_value = mock_device
  589. config_entry = MockConfigEntry(
  590. domain=DOMAIN,
  591. version=13,
  592. unique_id="uniqueid",
  593. data={
  594. CONF_DEVICE_ID: "deviceid",
  595. CONF_HOST: "hostname",
  596. CONF_LOCAL_KEY: TESTKEY,
  597. CONF_NAME: "test",
  598. CONF_POLL_ONLY: False,
  599. CONF_PROTOCOL_VERSION: "auto",
  600. CONF_TYPE: "non_existing",
  601. },
  602. )
  603. config_entry.add_to_hass(hass)
  604. await hass.config_entries.async_setup(config_entry.entry_id)
  605. await hass.async_block_till_done()
  606. # show initial form
  607. result = await hass.config_entries.options.async_init(config_entry.entry_id)
  608. assert result["type"] == "abort"
  609. assert result["reason"] == "not_supported"