__init__.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. """
  2. Platform for Tuya WiFi-connected devices.
  3. Based on nikrolls/homeassistant-goldair-climate for Goldair branded devices.
  4. Based on sean6541/tuya-homeassistant for service call logic, and TarxBoy's
  5. investigation into Goldair's tuyapi statuses
  6. https://github.com/codetheweb/tuyapi/issues/31.
  7. """
  8. import logging
  9. from homeassistant.config_entries import ConfigEntry
  10. from homeassistant.const import CONF_HOST
  11. from homeassistant.core import HomeAssistant
  12. from .const import (
  13. CONF_CLIMATE,
  14. CONF_DEVICE_ID,
  15. CONF_FAN,
  16. CONF_HUMIDIFIER,
  17. CONF_LIGHT,
  18. CONF_LOCAL_KEY,
  19. CONF_LOCK,
  20. CONF_SWITCH,
  21. CONF_TYPE,
  22. DOMAIN,
  23. )
  24. from .device import setup_device, delete_device
  25. from .helpers.device_config import get_config
  26. _LOGGER = logging.getLogger(__name__)
  27. async def async_migrate_entry(hass, entry: ConfigEntry):
  28. """Migrate to latest config format."""
  29. CONF_TYPE_AUTO = "auto"
  30. CONF_DISPLAY_LIGHT = "display_light"
  31. CONF_CHILD_LOCK = "child_lock"
  32. if entry.version == 1:
  33. # Removal of Auto detection.
  34. config = {**entry.data, **entry.options, "name": entry.title}
  35. opts = {**entry.options}
  36. if config[CONF_TYPE] == CONF_TYPE_AUTO:
  37. device = setup_device(hass, config)
  38. config[CONF_TYPE] = await device.async_inferred_type()
  39. if config[CONF_TYPE] is None:
  40. return False
  41. entry.data = {
  42. CONF_DEVICE_ID: config[CONF_DEVICE_ID],
  43. CONF_LOCAL_KEY: config[CONF_LOCAL_KEY],
  44. CONF_HOST: config[CONF_HOST],
  45. }
  46. if CONF_CHILD_LOCK in config:
  47. opts.pop(CONF_CHILD_LOCK, False)
  48. opts[CONF_LOCK] = config[CONF_CHILD_LOCK]
  49. if CONF_DISPLAY_LIGHT in config:
  50. opts.pop(CONF_DISPLAY_LIGHT, False)
  51. opts[CONF_LIGHT] = config[CONF_DISPLAY_LIGHT]
  52. entry.options = {**opts}
  53. entry.version = 2
  54. if entry.version == 2:
  55. # CONF_TYPE is not configurable, move it from options to the main config.
  56. config = {**entry.data, **entry.options, "name": entry.title}
  57. opts = {**entry.options}
  58. # Ensure type has been migrated. Some users are reporting errors which
  59. # suggest it was removed completely. But that is probably due to
  60. # overwriting options without CONF_TYPE.
  61. if config.get(CONF_TYPE, CONF_TYPE_AUTO) == CONF_TYPE_AUTO:
  62. device = setup_device(hass, config)
  63. config[CONF_TYPE] = await device.async_inferred_type()
  64. if config[CONF_TYPE] is None:
  65. return False
  66. entry.data = {
  67. CONF_DEVICE_ID: config[CONF_DEVICE_ID],
  68. CONF_LOCAL_KEY: config[CONF_LOCAL_KEY],
  69. CONF_HOST: config[CONF_HOST],
  70. CONF_TYPE: config[CONF_TYPE],
  71. }
  72. opts.pop(CONF_TYPE, None)
  73. entry.options = {**opts}
  74. entry.version = 3
  75. if entry.version == 3:
  76. # Migrate to filename based config_type, to avoid needing to
  77. # parse config files to find the right one.
  78. config = {**entry.data, **entry.options, "name": entry.title}
  79. config_type = get_config(config[CONF_TYPE]).config_type
  80. # Special case for kogan_switch. Consider also v2.
  81. if config_type == "smartplugv1":
  82. device = setup_device(hass, config)
  83. config_type = await device.async_inferred_type()
  84. if config_type != "smartplugv2":
  85. config_type = "smartplugv1"
  86. entry.data = {
  87. CONF_DEVICE_ID: config[CONF_DEVICE_ID],
  88. CONF_LOCAL_KEY: config[CONF_LOCAL_KEY],
  89. CONF_HOST: config[CONF_HOST],
  90. CONF_TYPE: config_type,
  91. }
  92. entry.version = 4
  93. return True
  94. async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
  95. _LOGGER.debug(f"Setting up entry for device: {entry.data[CONF_DEVICE_ID]}")
  96. config = {**entry.data, **entry.options, "name": entry.title}
  97. setup_device(hass, config)
  98. if config.get(CONF_CLIMATE, False) is True:
  99. hass.async_create_task(
  100. hass.config_entries.async_forward_entry_setup(entry, "climate")
  101. )
  102. if config.get(CONF_LIGHT, False) is True:
  103. hass.async_create_task(
  104. hass.config_entries.async_forward_entry_setup(entry, "light")
  105. )
  106. if config.get(CONF_LOCK, False) is True:
  107. hass.async_create_task(
  108. hass.config_entries.async_forward_entry_setup(entry, "lock")
  109. )
  110. if config.get(CONF_SWITCH, False) is True:
  111. hass.async_create_task(
  112. hass.config_entries.async_forward_entry_setup(entry, "switch")
  113. )
  114. if config.get(CONF_HUMIDIFIER, False) is True:
  115. hass.async_create_task(
  116. hass.config_entries.async_forward_entry_setup(entry, "humidifier")
  117. )
  118. if config.get(CONF_FAN, False) is True:
  119. hass.async_create_task(
  120. hass.config_entries.async_forward_entry_setup(entry, "fan")
  121. )
  122. entry.add_update_listener(async_update_entry)
  123. return True
  124. async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
  125. _LOGGER.debug(f"Unloading entry for device: {entry.data[CONF_DEVICE_ID]}")
  126. config = entry.data
  127. data = hass.data[DOMAIN][config[CONF_DEVICE_ID]]
  128. if CONF_CLIMATE in data:
  129. await hass.config_entries.async_forward_entry_unload(entry, "climate")
  130. if CONF_LIGHT in data:
  131. await hass.config_entries.async_forward_entry_unload(entry, "light")
  132. if CONF_LOCK in data:
  133. await hass.config_entries.async_forward_entry_unload(entry, "lock")
  134. if CONF_SWITCH in data:
  135. await hass.config_entries.async_forward_entry_unload(entry, "switch")
  136. if CONF_HUMIDIFIER in data:
  137. await hass.config_entries.async_forward_entry_unload(entry, "humidifier")
  138. if CONF_FAN in data:
  139. await hass.config_entries.async_forward_entry_unload(entry, "fan")
  140. delete_device(hass, config)
  141. del hass.data[DOMAIN][config[CONF_DEVICE_ID]]
  142. return True
  143. async def async_update_entry(hass: HomeAssistant, entry: ConfigEntry):
  144. _LOGGER.debug(f"Updating entry for device: {entry.data[CONF_DEVICE_ID]}")
  145. await async_unload_entry(hass, entry)
  146. await async_setup_entry(hass, entry)