fan.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. """Fan setup for our Integration."""
  2. import logging
  3. from typing import Any
  4. from homeassistant.components.fan import FanEntity, FanEntityFeature
  5. from homeassistant.core import HomeAssistant
  6. from homeassistant.helpers.entity_platform import AddEntitiesCallback
  7. from homeassistant.util.percentage import percentage_to_ranged_value
  8. from . import MyConfigEntry
  9. from .base import ExampleBaseEntity
  10. from .coordinator import ExampleCoordinator
  11. _LOGGER = logging.getLogger(__name__)
  12. async def async_setup_entry(
  13. hass: HomeAssistant,
  14. config_entry: MyConfigEntry,
  15. async_add_entities: AddEntitiesCallback,
  16. ):
  17. """Set up the Fans."""
  18. # This gets the data update coordinator from the config entry runtime data as specified in your __init__.py
  19. coordinator: ExampleCoordinator = config_entry.runtime_data.coordinator
  20. # ----------------------------------------------------------------------------
  21. # Here we are going to add our fan entity for the fan in our mock data.
  22. # ----------------------------------------------------------------------------
  23. # Fans
  24. fans = [
  25. ExampleFan(coordinator, device, "state")
  26. for device in coordinator.data
  27. if device.get("device_type") == "FAN"
  28. ]
  29. # Create the fans.
  30. async_add_entities(fans)
  31. class ExampleFan(ExampleBaseEntity, FanEntity):
  32. """Implementation of a fan.
  33. This inherits our ExampleBaseEntity to set common properties.
  34. See base.py for this class.
  35. https://developers.home-assistant.io/docs/core/entity/fan/
  36. """
  37. _attr_speed_count = 3
  38. _attr_supported_features = FanEntityFeature.OSCILLATE | FanEntityFeature.SET_SPEED
  39. _speed_parameter = "speed"
  40. _oscillating_parameter = "oscillating"
  41. @property
  42. def is_on(self) -> bool | None:
  43. """Return if the fan is on."""
  44. # This needs to enumerate to true or false
  45. return (
  46. self.coordinator.get_device_parameter(self.device_id, self.parameter)
  47. == "ON"
  48. )
  49. @property
  50. def oscillating(self) -> bool | None:
  51. """Return whether or not the fan is currently oscillating."""
  52. # This needs to enumerate to true or false
  53. return (
  54. self.coordinator.get_device_parameter(
  55. self.device_id, self._oscillating_parameter
  56. )
  57. == "ON"
  58. )
  59. @property
  60. def percentage(self) -> int | None:
  61. """Return the current speed as a percentage."""
  62. speed = self.coordinator.get_device_parameter(
  63. self.device_id, self._speed_parameter
  64. )
  65. # Need to return a percentage but our fan has speeds 0,1,2,3
  66. return int(self.percentage_step * speed)
  67. async def async_turn_on(
  68. self,
  69. percentage: int | None = None,
  70. preset_mode: str | None = None,
  71. **kwargs: Any,
  72. ) -> None:
  73. """Turn on the fan.
  74. A turn on command can be sent with or without a %, so we
  75. need to check that and turn on and set speed if requested.
  76. """
  77. await self.hass.async_add_executor_job(
  78. self.coordinator.api.set_data, self.device_id, self.parameter, "ON"
  79. )
  80. if percentage:
  81. self.async_set_fan_speed(percentage)
  82. # ----------------------------------------------------------------------------
  83. # Use async_refresh on the DataUpdateCoordinator to perform immediate update.
  84. # Using self.async_update or self.coordinator.async_request_refresh may delay update due
  85. # to trying to batch requests.
  86. # ----------------------------------------------------------------------------
  87. await self.coordinator.async_refresh()
  88. async def async_turn_off(self, **kwargs: Any) -> None:
  89. """Turn the fan off."""
  90. await self.hass.async_add_executor_job(
  91. self.coordinator.api.set_data, self.device_id, self.parameter, "OFF"
  92. )
  93. await self.coordinator.async_refresh()
  94. async def async_set_percentage(self, percentage: int) -> None:
  95. """Set the speed of the fan, as a percentage.
  96. Here we need to apply some logic if % is 0 to turn the fan
  97. off instead of setting its speed. If the fan is off, turn it on with
  98. the speed setting, otherwise just set the speed setting.
  99. """
  100. if percentage == 0:
  101. await self.async_turn_off()
  102. elif not self.is_on:
  103. await self.async_turn_on(percentage)
  104. else:
  105. await self.async_set_fan_speed(percentage)
  106. await self.coordinator.async_refresh()
  107. async def async_oscillate(self, oscillating: bool) -> None:
  108. """Oscillate the fan."""
  109. await self.hass.async_add_executor_job(
  110. self.coordinator.api.set_data,
  111. self.device_id,
  112. self._oscillating_parameter,
  113. "ON" if oscillating else "OFF",
  114. )
  115. await self.coordinator.async_refresh()
  116. # ----------------------------------------------------------------------------
  117. # Added a custom method to make our code simpler
  118. # ----------------------------------------------------------------------------
  119. async def async_set_fan_speed(self, percentage: int) -> None:
  120. """Set fan speed."""
  121. await self.hass.async_add_executor_job(
  122. self.coordinator.api.set_data,
  123. self.device_id,
  124. self._speed_parameter,
  125. percentage_to_ranged_value(1, self.speed_count, percentage),
  126. )