Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for GU10 lights #141

Merged
merged 18 commits into from
Jan 21, 2018
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[![Coverage Status](https://coveralls.io/repos/github/ggravlingen/pytradfri/badge.svg?branch=master)](https://coveralls.io/github/ggravlingen/pytradfri?branch=master)
[![PyPI version](https://badge.fury.io/py/pytradfri.svg)](https://badge.fury.io/py/pytradfri)

**NB:** Latest Gateway version tested and working - 1.2.42.
**NB:** Latest Gateway version tested and working - 1.3.14.

Python class to communicate with the [IKEA Trådfri](http://www.ikea.com/us/en/catalog/products/00337813/) (Tradfri) ZigBee-based Gateway. Using this library you can, by communicating with the gateway, control IKEA lights (including the RGB ones). Some of the features include:

Expand Down
59 changes: 36 additions & 23 deletions pytradfri/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
RANGE_BRIGHTNESS,
RANGE_X,
RANGE_Y,
ROOT_SWITCH,
SUPPORT_BRIGHTNESS,
SUPPORT_COLOR_TEMP,
SUPPORT_HEX_COLOR,
Expand All @@ -34,6 +35,14 @@
from .error import ColorError


def device_type(data):
"""If regular bulb=>ATTR_LIGHT_CONTROL If GU10 light=>ROOT_SWITCH."""
if ATTR_LIGHT_CONTROL in data:
return ATTR_LIGHT_CONTROL
elif ROOT_SWITCH in data:
return ROOT_SWITCH


class Device(ApiResource):
"""Base class for devices."""

Expand Down Expand Up @@ -62,11 +71,13 @@ def reachable(self):
@property
def has_light_control(self):
return (self.raw is not None and
len(self.raw.get(ATTR_LIGHT_CONTROL, "")) > 0)
(len(self.raw.get(ATTR_LIGHT_CONTROL, "")) > 0 or
len(self.raw.get(ROOT_SWITCH, "")) > 0)
)

@property
def light_control(self):
return LightControl(self)
return DeviceControl(self)

def __repr__(self):
return "<{} - {} ({})>".format(self.id, self.name,
Expand Down Expand Up @@ -140,22 +151,22 @@ def raw(self):
return self._device.raw[ATTR_DEVICE_INFO]


class LightControl:
"""Class to control the lights."""
class DeviceControl:
"""Class to control devices."""

def __init__(self, device):
self._device = device

@property
def raw(self):
"""Return raw data that it represents."""
return self._device.raw[device_type(self._device.raw)]

@property
def lights(self):
"""Return light objects of the light control."""
return [Light(self._device, i) for i in range(len(self.raw))]

@property
def raw(self):
"""Return raw data that it represents."""
return self._device.raw[ATTR_LIGHT_CONTROL]

def set_state(self, state, *, index=0):
"""Set state of a light."""
return self.set_values({
Expand Down Expand Up @@ -246,36 +257,35 @@ def set_predefined_color(self, colorname, *, index=0,
raise ColorError('Invalid color specified: %s',
colorname)

def _value_validate(self, value, rnge, identifier="Given"):
"""
Make sure a value is within a given range
"""
if value is not None and (value < rnge[0] or value > rnge[1]):
raise ValueError('%s value must be between %d and %d.'
% (identifier, rnge[0], rnge[1]))

def set_values(self, values, *, index=0):
"""
Set values on light control.

Returns a Command.
"""
assert len(self.raw) == 1, \
'Only devices with 1 light supported'

return Command('put', self._device.path, {
ATTR_LIGHT_CONTROL: [
device_type(self._device.raw): [
values
]
})

def _value_validate(self, value, rnge, identifier="Given"):
"""
Make sure a value is within a given range
"""
if value is not None and (value < rnge[0] or value > rnge[1]):
raise ValueError('%s value must be between %d and %d.'
% (identifier, rnge[0], rnge[1]))

def __repr__(self):
return '<LightControl for {} ({} lights)>'.format(self._device.name,
len(self.raw))
return '<DeviceControl for {} ({} lights)>'.format(self._device.name,
len(self.raw))


class Light:
"""Represent a light control.
"""Represent a light.

https://github.com/IPSO-Alliance/pub/blob/master/docs/IPSO-Smart-Objects.pdf
"""
Expand Down Expand Up @@ -325,7 +335,10 @@ def hsb_xy_color(self):
@property
def raw(self):
"""Return raw data that it represents."""
return self.device.raw[ATTR_LIGHT_CONTROL][self.index]
if ATTR_LIGHT_CONTROL in self.device.raw:
return self.device.raw[device_type(self.device.raw)][self.index]
elif ROOT_SWITCH in self.device.raw:
return self.device.raw[device_type(self.device.raw)][self.index]

def __repr__(self):
state = "on" if self.state else "off"
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
with open(path.join(here, 'README.md'), encoding='utf-8') as f:
long_description = f.read()

VERSION = "5.2.2"
VERSION = "5.3.0"
DOWNLOAD_URL = \
'https://github.com/ggravlingen/pytradfri/archive/{}.zip'.format(VERSION)

Expand Down
30 changes: 30 additions & 0 deletions tests/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,36 @@
'9054': 0,
}

# Retrieved from Gateway running on 1.3.002
LIGHT_GU10 = {
"9001": "mhlund #1",
"5750": 0,
"9002": 1515435391,
"9020": 1516008285,
"9003": 65540,
"9054": 0,
"9019": 1,
"3": {
"0": "IKEA of Sweden",
"1": "TRADFRI bulb GU10 WS 400lm",
"2": "",
"3": "1.2.217",
"6": 1
},
"15009": [
{
"5851": 10,
"5850": 0,
"5717": 0,
"5711": 450,
"5709": 30138,
"5710": 26909,
"5706": "efd275",
"9003": 0
}
]
}

# Retrieved from Gateway running on 1.2.42
REMOTE_CONTROL = {
'3': {'0': 'IKEA of Sweden',
Expand Down
10 changes: 7 additions & 3 deletions tests/test_light.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@
LIGHT_WS,
LIGHT_WS_CUSTOM_COLOR,
LIGHT_CWS,
LIGHT_CWS_CUSTOM_COLOR
LIGHT_CWS_CUSTOM_COLOR,
LIGHT_GU10
)


def light(raw):
return Device(raw).light_control.lights[0]


def light_device_control(raw):
return Device(raw).light_control
def test_gu10():
bulb = light(LIGHT_GU10)

assert bulb.hex_color == 'efd275'
assert bulb.xy_color == (30138, 26909)


def test_white_bulb():
Expand Down