Home Assistant Unofficial Reference 2024.12.1
light.py
Go to the documentation of this file.
1 """Interfaces with the myLeviton API for Decora Smart WiFi products."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any
7 
8 from decora_wifi import DecoraWiFiSession
9 from decora_wifi.models.person import Person
10 from decora_wifi.models.residence import Residence
11 from decora_wifi.models.residential_account import ResidentialAccount
12 import voluptuous as vol
13 
14 from homeassistant.components import persistent_notification
16  ATTR_BRIGHTNESS,
17  ATTR_TRANSITION,
18  PLATFORM_SCHEMA as LIGHT_PLATFORM_SCHEMA,
19  ColorMode,
20  LightEntity,
21  LightEntityFeature,
22 )
23 from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, EVENT_HOMEASSISTANT_STOP
24 from homeassistant.core import HomeAssistant
26 from homeassistant.helpers.entity_platform import AddEntitiesCallback
27 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
28 
29 _LOGGER = logging.getLogger(__name__)
30 
31 # Validation of the user's configuration
32 PLATFORM_SCHEMA = LIGHT_PLATFORM_SCHEMA.extend(
33  {vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string}
34 )
35 
36 NOTIFICATION_ID = "leviton_notification"
37 NOTIFICATION_TITLE = "myLeviton Decora Setup"
38 
39 
41  hass: HomeAssistant,
42  config: ConfigType,
43  add_entities: AddEntitiesCallback,
44  discovery_info: DiscoveryInfoType | None = None,
45 ) -> None:
46  """Set up the Decora WiFi platform."""
47 
48  email = config[CONF_USERNAME]
49  password = config[CONF_PASSWORD]
50  session = DecoraWiFiSession()
51 
52  try:
53  success = session.login(email, password)
54 
55  # If login failed, notify user.
56  if success is None:
57  msg = "Failed to log into myLeviton Services. Check credentials."
58  _LOGGER.error(msg)
59  persistent_notification.create(
60  hass, msg, title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID
61  )
62  return
63 
64  # Gather all the available devices...
65  perms = session.user.get_residential_permissions()
66  all_switches: list = []
67  for permission in perms:
68  if permission.residentialAccountId is not None:
69  acct = ResidentialAccount(session, permission.residentialAccountId)
70  all_switches.extend(
71  switch
72  for residence in acct.get_residences()
73  for switch in residence.get_iot_switches()
74  )
75  elif permission.residenceId is not None:
76  residence = Residence(session, permission.residenceId)
77  all_switches.extend(residence.get_iot_switches())
78 
79  add_entities(DecoraWifiLight(sw) for sw in all_switches)
80  except ValueError:
81  _LOGGER.error("Failed to communicate with myLeviton Service")
82 
83  # Listen for the stop event and log out.
84  def logout(event):
85  """Log out..."""
86  try:
87  if session is not None:
88  Person.logout(session)
89  except ValueError:
90  _LOGGER.error("Failed to log out of myLeviton Service")
91 
92  hass.bus.listen(EVENT_HOMEASSISTANT_STOP, logout)
93 
94 
96  """Representation of a Decora WiFi switch."""
97 
98  def __init__(self, switch):
99  """Initialize the switch."""
100  self._switch_switch = switch
101  self._attr_unique_id_attr_unique_id = switch.serial
102 
103  @property
104  def color_mode(self) -> str:
105  """Return the color mode of the light."""
106  if self._switch_switch.canSetLevel:
107  return ColorMode.BRIGHTNESS
108  return ColorMode.ONOFF
109 
110  @property
111  def supported_color_modes(self) -> set[str] | None:
112  """Flag supported color modes."""
113  return {self.color_modecolor_modecolor_mode}
114 
115  @property
116  def supported_features(self) -> LightEntityFeature:
117  """Return supported features."""
118  if self._switch_switch.canSetLevel:
119  return LightEntityFeature.TRANSITION
120  return LightEntityFeature(0)
121 
122  @property
123  def name(self):
124  """Return the display name of this switch."""
125  return self._switch_switch.name
126 
127  @property
128  def unique_id(self):
129  """Return the ID of this light."""
130  return self._switch_switch.serial
131 
132  @property
133  def brightness(self):
134  """Return the brightness of the dimmer switch."""
135  return int(self._switch_switch.brightness * 255 / 100)
136 
137  @property
138  def is_on(self):
139  """Return true if switch is on."""
140  return self._switch_switch.power == "ON"
141 
142  def turn_on(self, **kwargs: Any) -> None:
143  """Instruct the switch to turn on & adjust brightness."""
144  attribs: dict[str, Any] = {"power": "ON"}
145 
146  if ATTR_BRIGHTNESS in kwargs:
147  min_level = self._switch_switch.data.get("minLevel", 0)
148  max_level = self._switch_switch.data.get("maxLevel", 100)
149  brightness = int(kwargs[ATTR_BRIGHTNESS] * max_level / 255)
150  brightness = max(brightness, min_level)
151  attribs["brightness"] = brightness
152 
153  if ATTR_TRANSITION in kwargs:
154  transition = int(kwargs[ATTR_TRANSITION])
155  attribs["fadeOnTime"] = attribs["fadeOffTime"] = transition
156 
157  try:
158  self._switch_switch.update_attributes(attribs)
159  except ValueError:
160  _LOGGER.error("Failed to turn on myLeviton switch")
161 
162  def turn_off(self, **kwargs: Any) -> None:
163  """Instruct the switch to turn off."""
164  attribs = {"power": "OFF"}
165  try:
166  self._switch_switch.update_attributes(attribs)
167  except ValueError:
168  _LOGGER.error("Failed to turn off myLeviton switch")
169 
170  def update(self) -> None:
171  """Fetch new state data for this switch."""
172  try:
173  self._switch_switch.refresh()
174  except ValueError:
175  _LOGGER.error("Failed to update myLeviton switch data")
ColorMode|str|None color_mode(self)
Definition: __init__.py:909
None add_entities(AsusWrtRouter router, AddEntitiesCallback async_add_entities, set[str] tracked)
None setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: light.py:45