Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 67 additions & 38 deletions homeassistant/components/yeelight/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
from homeassistant.helpers import discovery
from homeassistant.helpers.discovery import load_platform
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import dispatcher_send
from homeassistant.helpers.dispatcher import dispatcher_send, \
dispatcher_connect
from homeassistant.helpers.event import track_time_interval

REQUIREMENTS = ['yeelight==0.4.4']
Expand All @@ -23,6 +24,7 @@
DOMAIN = "yeelight"
DATA_YEELIGHT = DOMAIN
DATA_UPDATED = 'yeelight_{}_data_updated'
DEVICE_INITIALIZED = '{}_device_initialized'.format(DOMAIN)

DEFAULT_NAME = 'Yeelight'
DEFAULT_TRANSITION = 350
Expand Down Expand Up @@ -116,7 +118,7 @@ def setup(hass, config):
conf = config.get(DOMAIN, {})
yeelight_data = hass.data[DATA_YEELIGHT] = {}

def device_discovered(service, info):
def device_discovered(_, info):
_LOGGER.debug("Adding autodetected %s", info['hostname'])

device_type = info['device_type']
Expand All @@ -133,14 +135,25 @@ def device_discovered(service, info):

discovery.listen(hass, SERVICE_YEELIGHT, device_discovered)

def update(event):
def update(_):
for device in list(yeelight_data.values()):
device.update()

track_time_interval(
hass, update, conf.get(CONF_SCAN_INTERVAL, SCAN_INTERVAL)
)

def load_platforms(ipaddr):
platform_config = hass.data[DATA_YEELIGHT][ipaddr].config.copy()
platform_config[CONF_HOST] = ipaddr
platform_config[CONF_CUSTOM_EFFECTS] = \
config.get(DOMAIN, {}).get(CONF_CUSTOM_EFFECTS, {})
load_platform(hass, LIGHT_DOMAIN, DOMAIN, platform_config, config)
load_platform(hass, BINARY_SENSOR_DOMAIN, DOMAIN, platform_config,
config)

dispatcher_connect(hass, DEVICE_INITIALIZED, load_platforms)

if DOMAIN in config:
for ipaddr, device_config in conf[CONF_DEVICES].items():
_LOGGER.debug("Adding configured %s", device_config[CONF_NAME])
Expand All @@ -149,7 +162,7 @@ def update(event):
return True


def _setup_device(hass, hass_config, ipaddr, device_config):
def _setup_device(hass, _, ipaddr, device_config):
devices = hass.data[DATA_YEELIGHT]

if ipaddr in devices:
Expand All @@ -158,47 +171,29 @@ def _setup_device(hass, hass_config, ipaddr, device_config):
device = YeelightDevice(hass, ipaddr, device_config)

devices[ipaddr] = device

platform_config = device_config.copy()
platform_config[CONF_HOST] = ipaddr
platform_config[CONF_CUSTOM_EFFECTS] = \
hass_config.get(DOMAIN, {}).get(CONF_CUSTOM_EFFECTS, {})

load_platform(hass, LIGHT_DOMAIN, DOMAIN, platform_config, hass_config)
load_platform(hass, BINARY_SENSOR_DOMAIN, DOMAIN, platform_config,
hass_config)
hass.add_job(device.setup)


class YeelightDevice:
"""Represents single Yeelight device."""

def __init__(self, hass, ipaddr, config):
"""Initialize device."""
import yeelight

self._hass = hass
self._config = config
self._ipaddr = ipaddr
self._name = config.get(CONF_NAME)
self._model = config.get(CONF_MODEL)
self._bulb_device = None
self._bulb_device = yeelight.Bulb(self.ipaddr, model=self._model)
self._device_type = None
self._available = False
self._initialized = False

@property
def bulb(self):
"""Return bulb device."""
if self._bulb_device is None:
import yeelight
try:
self._bulb_device = yeelight.Bulb(self._ipaddr,
model=self._model)
# force init for type
self.update()

self._available = True
except yeelight.BulbException as ex:
self._available = False
_LOGGER.error("Failed to connect to bulb %s, %s: %s",
self._ipaddr, self._name, ex)

return self._bulb_device

@property
Expand All @@ -221,23 +216,38 @@ def available(self):
"""Return true is device is available."""
return self._available

@property
def model(self):
"""Return configured device model."""
return self._model

@property
def is_nightlight_enabled(self) -> bool:
"""Return true / false if nightlight is currently enabled."""
if self.bulb is None:
return False

return self.bulb.last_properties.get('active_mode') == '1'
return self._active_mode == '1'

@property
def is_nightlight_supported(self) -> bool:
"""Return true / false if nightlight is supported."""
return self.bulb.get_model_specs().get('night_light', False)
if self.model:
return self.bulb.get_model_specs().get('night_light', False)

return self._active_mode is not None

@property
def is_ambilight_supported(self) -> bool:
"""Return true / false if ambilight is supported."""
return self.bulb.get_model_specs().get('background_light', False)
def _active_mode(self):
return self.bulb.last_properties.get('active_mode')

@property
def type(self):
"""Return bulb type."""
if not self._device_type:
self._device_type = self.bulb.bulb_type

return self._device_type

def turn_on(self, duration=DEFAULT_TRANSITION, light_type=None):
"""Turn on device."""
Expand All @@ -247,7 +257,6 @@ def turn_on(self, duration=DEFAULT_TRANSITION, light_type=None):
self.bulb.turn_on(duration=duration, light_type=light_type)
except BulbException as ex:
_LOGGER.error("Unable to turn the bulb on: %s", ex)
return

def turn_off(self, duration=DEFAULT_TRANSITION, light_type=None):
"""Turn off device."""
Expand All @@ -256,10 +265,10 @@ def turn_off(self, duration=DEFAULT_TRANSITION, light_type=None):
try:
self.bulb.turn_off(duration=duration, light_type=light_type)
except BulbException as ex:
_LOGGER.error("Unable to turn the bulb off: %s", ex)
return
_LOGGER.error("Unable to turn the bulb off: %s, %s: %s",
self.ipaddr, self.name, ex)

def update(self):
def _update_properties(self):
"""Read new properties from the device."""
from yeelight import BulbException

Expand All @@ -271,7 +280,27 @@ def update(self):
self._available = True
except BulbException as ex:
if self._available: # just inform once
_LOGGER.error("Unable to update bulb status: %s", ex)
_LOGGER.error("Unable to update device %s, %s: %s",
self.ipaddr, self.name, ex)
self._available = False

return self._available

def _initialize_if_not_already(self):
if self._initialized:
return

self._initialized = True
dispatcher_send(self._hass, DEVICE_INITIALIZED, self.ipaddr)

def update(self):
"""Update device properties and send data updated signal."""
if self._update_properties():
self._initialize_if_not_already()

dispatcher_send(self._hass, DATA_UPDATED.format(self._ipaddr))

def setup(self):
"""Initialize device and send initialized signal."""
if self._update_properties() or self.model:
self._initialize_if_not_already()
Loading