Skip to content

Commit 09beee9

Browse files
merged
2 parents 3ccebe0 + c8cb71b commit 09beee9

File tree

10 files changed

+244
-11
lines changed

10 files changed

+244
-11
lines changed

limitlessled/bridge.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from limitlessled.group.wrgb import WrgbGroup, WRGB
1212
from limitlessled.group.rgbww import RgbwwGroup, RGBWW
1313
from limitlessled.group.white import WhiteGroup, WHITE
14+
from limitlessled.group.dimmer import DimmerGroup, DIMMER
1415

1516

1617
BRIDGE_PORT = 5987
@@ -36,7 +37,7 @@ def group_factory(bridge, number, name, led_type):
3637
:param bridge: Member of this bridge.
3738
:param number: Group number (1-4).
3839
:param name: Name of group.
39-
:param led_type: Either `RGBW`, `WRGB`, `RGBWW`, `WHITE` or `BRIDGE_LED`.
40+
:param led_type: Either `RGBW`, `WRGB`, `RGBWW`, `WHITE`, `DIMMER` or `BRIDGE_LED`.
4041
:returns: New group.
4142
"""
4243
if led_type in [RGBW, BRIDGE_LED]:
@@ -45,6 +46,8 @@ def group_factory(bridge, number, name, led_type):
4546
return RgbwwGroup(bridge, number, name)
4647
elif led_type == WHITE:
4748
return WhiteGroup(bridge, number, name)
49+
elif led_type == DIMMER:
50+
return DimmerGroup(bridge, number, name)
4851
elif led_type == WRGB:
4952
return WrgbGroup(bridge, number, name)
5053
else:
@@ -145,7 +148,7 @@ def add_group(self, number, name, led_type):
145148
146149
:param number: Group number (1-4).
147150
:param name: Group name.
148-
:param led_type: Either `RGBW`, `WRGB`, `RGBWW`, `WHITE` or `BRIDGE_LED`.
151+
:param led_type: Either `RGBW`, `WRGB`, `RGBWW`, `WHITE`, `DIMMER` or `BRIDGE_LED`.
149152
:returns: Added group.
150153
"""
151154
group = group_factory(self, number, name, led_type)

limitlessled/group/commands/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ def command_set_factory(bridge, group_number, led_type):
1414
CommandSetWhiteLegacy, CommandSetRgbwLegacy)
1515
from limitlessled.group.commands.v6 import (
1616
CommandSetBridgeLightV6, CommandSetWhiteV6,
17-
CommandSetRgbwV6, CommandSetRgbwwV6, CommandSetWrgbV6)
17+
CommandSetDimmerV6, CommandSetRgbwV6,
18+
CommandSetRgbwwV6, CommandSetWrgbV6)
1819

1920
command_sets = [CommandSetWhiteLegacy, CommandSetRgbwLegacy,
2021
CommandSetBridgeLightV6, CommandSetWhiteV6,
21-
CommandSetRgbwV6, CommandSetRgbwwV6, CommandSetWrgbV6]
22+
CommandSetDimmerV6, CommandSetRgbwV6,
23+
CommandSetRgbwwV6, CommandSetWrgbV6]
2224
try:
2325
cls = next(cs for cs in command_sets if
2426
bridge.version in cs.SUPPORTED_VERSIONS and

limitlessled/group/commands/legacy.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class CommandSetWhiteLegacy(CommandSetLegacy):
9090
SUPPORTED_LED_TYPES = [WHITE]
9191
ON_BYTES = [0x38, 0x3D, 0x37, 0x32]
9292
OFF_BYTES = [0x3B, 0x33, 0x3A, 0x36]
93+
NIGHT_BYTES = [0xBB, 0xB3, 0xBA, 0xB6]
9394
BRIGHTNESS_STEPS = 10
9495
TEMPERATURE_STEPS = 10
9596

@@ -115,6 +116,14 @@ def off(self):
115116
"""
116117
return self._build_command(self.OFF_BYTES[self._group_number - 1])
117118

119+
def night_light(self):
120+
"""
121+
Build command for turning the led to night light mode.
122+
:return: The command.
123+
"""
124+
return self._build_command(self.NIGHT_BYTES[self._group_number - 1],
125+
select=True, select_command=self.off())
126+
118127
def dimmer(self):
119128
"""
120129
Build command for setting the brightness one step dimmer.
@@ -173,6 +182,14 @@ def off(self):
173182
"""
174183
return self._build_command(self._offset(0x46))
175184

185+
def night_light(self):
186+
"""
187+
Build command for turning the led to night light mode.
188+
:return: The command.
189+
"""
190+
return self._build_command(self._offset(0xC6),
191+
select=True, select_command=self.off())
192+
176193
def white(self):
177194
"""
178195
Build command for turning the led into white mode.

limitlessled/group/commands/v6.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from limitlessled.group.rgbww import RGBWW
88
from limitlessled.group.wrgb import WRGB
99
from limitlessled.group.white import WHITE
10+
from limitlessled.group.dimmer import DIMMER
1011
from limitlessled.group.commands import CommandSet, Command
1112

1213

@@ -242,6 +243,47 @@ def temperature(self, temperature):
242243
"""
243244
return self._build_command(0x01, self.convert_temperature(temperature))
244245

246+
class CommandSetDimmerV6(CommandSetV6):
247+
""" Command set for Dimmer LED dimmer (1CH MiLight dimmer) connected to wifi bridge v6. """
248+
249+
SUPPORTED_LED_TYPES = [DIMMER]
250+
REMOTE_STYLE = 0x03
251+
252+
def __init__(self, group_number):
253+
"""
254+
Initializes the command set.
255+
:param group_number: The group number.
256+
"""
257+
super().__init__(group_number, self.REMOTE_STYLE)
258+
259+
def on(self):
260+
"""
261+
Build command for turning the dimmer on.
262+
:return: The command.
263+
"""
264+
return self._build_command(0x04, 0x03)
265+
266+
def off(self):
267+
"""
268+
Build command for turning the dimmer off.
269+
:return: The command.
270+
"""
271+
return self._build_command(0x04, 0x04)
272+
273+
def night_light(self):
274+
"""
275+
Build command for turning the dimmer into night light mode.
276+
:return: The command.
277+
"""
278+
return self._build_command(0x04, 0x02)
279+
280+
def brightness(self, brightness):
281+
"""
282+
Build command for setting the brightness of the controller.
283+
:param brightness: Value to set (0.0-1.0).
284+
:return: The command.
285+
"""
286+
return self._build_command(0x01, self.convert_brightness(brightness))
245287

246288
class CommandSetRgbwV6(CommandSetV6):
247289
""" Command set for RGBW led light connected to wifi bridge v6. """

limitlessled/group/dimmer.py

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
""" Dimmer controller LimitlessLED group. """
2+
3+
import time
4+
5+
from limitlessled import util
6+
from limitlessled.group import Group, rate
7+
from limitlessled.util import steps
8+
9+
DIMMER = 'dimmer'
10+
11+
12+
class DimmerGroup(Group):
13+
""" Dimmer LimitlessLED group. """
14+
15+
def __init__(self, bridge, number, name):
16+
""" Initialize dimmer group.
17+
18+
Brightness must be initialized
19+
to some value.
20+
21+
:param bridge: Associated bridge.
22+
:param number: Group number (1-4).
23+
:param name: Group name.
24+
"""
25+
super().__init__(bridge, number, name, DIMMER)
26+
27+
@property
28+
def brightness(self):
29+
""" Brightness property.
30+
31+
:returns: Brightness.
32+
"""
33+
return self._brightness
34+
35+
@brightness.setter
36+
def brightness(self, brightness):
37+
""" Set the brightness.
38+
39+
:param brightness: Value to set (0.0-1.0).
40+
"""
41+
try:
42+
cmd = self.command_set.brightness(brightness)
43+
self.send(cmd)
44+
self._brightness = brightness
45+
except AttributeError:
46+
self._setter('_brightness', brightness,
47+
self._dimmest, self._brightest,
48+
self._to_brightness)
49+
50+
def transition(self, duration, brightness=None):
51+
""" Transition wrapper.
52+
53+
Short-circuit transition if necessary.
54+
55+
:param duration: Duration of transition.
56+
:param brightness: Transition to this brightness.
57+
"""
58+
if duration == 0:
59+
if brightness is not None:
60+
self.brightness = brightness
61+
return
62+
if brightness != self.brightness:
63+
self._transition(duration, brightness)
64+
65+
@rate(reps=1)
66+
def _transition(self, duration, brightness):
67+
""" Complete a transition.
68+
69+
:param duration: Duration of transition.
70+
:param brightness: Transition to this brightness.
71+
"""
72+
# Set initial value.
73+
b_start = self.brightness
74+
# Compute ideal step amount.
75+
b_steps = 0
76+
if brightness is not None:
77+
b_steps = steps(self.brightness, brightness,
78+
self.command_set.brightness_steps)
79+
# Compute ideal step amount (at least one).
80+
# Calculate wait.
81+
wait = self._wait(duration, b_steps, b_steps)
82+
# Scale down steps if no wait time.
83+
if wait == 0:
84+
b_steps = self._scale_steps(duration, b_steps,
85+
b_steps)
86+
# Perform transition.
87+
for i in range(b_steps):
88+
# Brightness.
89+
if b_steps > 0:
90+
self.brightness = util.transition(i, b_steps,
91+
b_start, brightness)
92+
time.sleep(wait)
93+
94+
def _setter(self, attr, value, bottom, top, to_step):
95+
""" Set a value.
96+
97+
:param attr: Attribute to set.
98+
:param value: Value to use.
99+
:param bottom: Get to bottom value.
100+
:param top: Get to top value.
101+
:param to_step: Get to intermediary value.
102+
"""
103+
if value < 0 or value > 1:
104+
raise ValueError("out of range")
105+
if value == 0.0:
106+
bottom()
107+
elif value == 1.0:
108+
top()
109+
else:
110+
to_step(value)
111+
setattr(self, attr, value)
112+
113+
def _to_brightness(self, brightness):
114+
""" Step to a given brightness.
115+
116+
:param brightness: Get to this brightness.
117+
"""
118+
self._to_value(self._brightness, brightness,
119+
self.command_set.brightness_steps,
120+
self._dimmer, self._brighter)
121+
122+
@rate(reps=1)
123+
def _to_value(self, current, target, max_steps, step_down, step_up):
124+
""" Step to a value
125+
126+
:param current: Current value.
127+
:param target: Target value.
128+
:param max_steps: Maximum number of steps.
129+
:param step_down: Down function.
130+
:param step_up: Up function.
131+
"""
132+
for _ in range(steps(current, target, max_steps)):
133+
if (current - target) > 0:
134+
step_down()
135+
else:
136+
step_up()
137+
138+
@rate(wait=0.025, reps=2)
139+
def _brightest(self):
140+
""" Group as bright as possible. """
141+
for _ in range(steps(self.brightness, 1.0,
142+
self.command_set.brightness_steps)):
143+
self._brighter()
144+
145+
@rate(wait=0.025, reps=2)
146+
def _dimmest(self):
147+
""" Group brightness as dim as possible. """
148+
for _ in range(steps(self.brightness, 0.0,
149+
self.command_set.brightness_steps)):
150+
self._dimmer()
151+
152+
def _brighter(self):
153+
""" One step brighter. """
154+
self.send(self.command_set.brighter())
155+
156+
def _dimmer(self):
157+
""" One step dimmer. """
158+
self.send(self.command_set.dimmer())

limitlessled/group/rgbw.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from limitlessled import Color, util
77
from limitlessled.group import Group, rate
8-
from limitlessled.util import steps, hue_of_color
8+
from limitlessled.util import steps, hue_of_color, saturation_of_color
99

1010

1111
RGBW = 'rgbw'
@@ -44,7 +44,7 @@ def color(self, color):
4444
4545
:param color: RGB color tuple.
4646
"""
47-
if color == RGB_WHITE:
47+
if saturation_of_color(color) == 0:
4848
self.white()
4949
return
5050
self._color = color

limitlessled/group/rgbww.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,10 @@ def color(self, color):
4444
4545
:param color: RGB color tuple.
4646
"""
47-
if color == RGB_WHITE:
48-
self.white()
49-
return
5047
self._color = color
51-
self.hue = hue_of_color(color)
5248
self.saturation = saturation_of_color(color)
49+
if self.saturation != 0:
50+
self.hue = hue_of_color(color)
5351

5452
def white(self):
5553
""" Set color to white. """

limitlessled/group/white.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ def __init__(self, bridge, number, name):
2525
super().__init__(bridge, number, name, WHITE)
2626
self._temperature = 0.5
2727

28+
def night_light(self):
29+
""" Set night light mode. """
30+
cmd = self.command_set.night_light()
31+
self.send(cmd)
32+
2833
@property
2934
def brightness(self):
3035
""" Brightness property.

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setup(
44
name='limitlessled',
5-
version='1.0.10',
5+
version='1.1.0',
66
description='Control LimitlessLED products.',
77
url='https://github.com/happyleavesaoc/python-limitlessled/',
88
license='MIT',

tests/test_legacy_commands.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ def test_on(self):
2929
def test_off(self):
3030
self.assertEqual(self.commands.off(), CommandLegacy(0x3b, None, 1))
3131

32+
def test_night_light(self):
33+
sc = CommandLegacy(0x3b, None, 1)
34+
self.assertEqual(self.commands.night_light(), CommandLegacy(0xbb, None, 1, select=True, select_command=sc))
35+
3236
def test_dimmer(self):
3337
sc = CommandLegacy(0x38, None, 1)
3438
self.assertEqual(self.commands.dimmer(), CommandLegacy(0x34, None, 1, select=True, select_command=sc))
@@ -57,6 +61,10 @@ def test_on(self):
5761
def test_off(self):
5862
self.assertEqual(self.commands.off(), CommandLegacy(0x46, None, 1))
5963

64+
def test_night_light(self):
65+
sc = CommandLegacy(0x46, None, 1)
66+
self.assertEqual(self.commands.night_light(), CommandLegacy(0xc6, None, 1, select=True, select_command=sc))
67+
6068
def test_white(self):
6169
sc = CommandLegacy(0x45, None, 1)
6270
self.assertEqual(self.commands.white(), CommandLegacy(0xc5, None, 1, select=True, select_command=sc))

0 commit comments

Comments
 (0)