Skip to content

Commit 4626260

Browse files
committed
Dimmer and Brightness Functions
1 parent 1918ed8 commit 4626260

3 files changed

Lines changed: 91 additions & 16 deletions

File tree

README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ Classes
144144
145145
BulbDevice
146146
set_colour(r, g, b):
147+
set_hsv(h, s, v):
147148
set_white(brightness, colourtemp):
148149
set_white_percentage(brightness=100, colourtemp=0):
149150
set_brightness(brightness):
@@ -169,12 +170,14 @@ Starting with v1.2.0 TinyTuya functions will return error details in the JSON da
169170
170171
The "Err" number will be one of these:
171172
172-
* 900 - Invalid JSON Response from Device
173-
* 901 - Network Error: Unable to Connect
174-
* 902 - Timeout Waiting for Device
175-
* 903 - Specified Value Out of Range
176-
* 904 - Unexpected Payload from Device
177-
* 905 - Network Error: Device Unreachable
173+
* 900 (ERR_JSON) - Invalid JSON Response from Device
174+
* 901 (ERR_CONNECT) - Network Error: Unable to Connect
175+
* 902 (ERR_TIMEOUT) - Timeout Waiting for Device
176+
* 903 (ERR_RANGE) - Specified Value Out of Range
177+
* 904 (ERR_PAYLOAD) - Unexpected Payload from Device
178+
* 905 (ERR_OFFLINE) - Network Error: Device Unreachable
179+
* 906 (ERR_STATE) - Device in Unknown State
180+
* 907 (ERR_FUNCTION) - Function Not Supported by Device
178181
179182
### Example Usage
180183

RELEASE.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
* Add socket.shutdown(socket.SHUT_RDWR)
77
* Add function to send multiple DPS index updates with one call
88

9-
## v1.2.3 - Dimmer Function
9+
## v1.2.3 - Dimmer and Brightness Functions
1010

1111
* PyPi Version 1.2.3
12-
* Added `set_dimmer()` to OutletDevice class
12+
* Added `set_dimmer()` to OutletDevice class.
13+
* Added `set_hsv()` to BulbDevice class.
14+
* Updated `set_brightness()` in BulbDevice to handle *white* and *colour* modes. Issue #30
15+
* BulbDevice determines features of device and presents boolean variables `has_colour`, `has_brightness` and `has_colourtemp` to ignore requests that do not exist (returns error).
1316

1417
## v1.2.2 - Bug Fix for Bulb Functions
1518

tinytuya/__init__.py

Lines changed: 77 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@
183183
ERR_RANGE = 903
184184
ERR_PAYLOAD = 904
185185
ERR_OFFLINE = 905
186+
ERR_STATE = 906
187+
ERR_FUNCTION = 907
186188

187189
error_codes = {
188190
ERR_JSON: 'Invalid JSON Response from Device',
@@ -191,6 +193,8 @@
191193
ERR_RANGE: 'Specified Value Out of Range',
192194
ERR_PAYLOAD: 'Unexpected Payload from Device',
193195
ERR_OFFLINE: 'Network Error: Device Unreachable',
196+
ERR_STATE: 'Device in Unknown State',
197+
ERR_FUNCTION: 'Function Not Supported by Device',
194198
None: 'Unknown Error'
195199
}
196200

@@ -1047,8 +1051,11 @@ class BulbDevice(Device):
10471051
'24': 'colour',
10481052
}
10491053

1050-
# Default Bulb Type
1054+
# Set Default Bulb Types
10511055
bulb_type = 'A'
1056+
has_brightness = False
1057+
has_colourtemp = False
1058+
has_colour = False
10521059

10531060
def __init__(self, dev_id, address, local_key="", dev_type="default"):
10541061
super(BulbDevice, self).__init__(dev_id, address, local_key, dev_type)
@@ -1146,9 +1153,9 @@ def _hexvalue_to_hsv(hexvalue, bulb='A'):
11461153
hexvalue(string): The hex representation generated by BulbDevice._rgb_to_hexvalue()
11471154
"""
11481155
if(bulb == 'A'):
1149-
h = int(hexvalue[7:10], 16) / 360
1150-
s = int(hexvalue[10:12], 16) / 255
1151-
v = int(hexvalue[12:14], 16) / 255
1156+
h = int(hexvalue[7:10], 16) / 360.0
1157+
s = int(hexvalue[10:12], 16) / 255.0
1158+
v = int(hexvalue[12:14], 16) / 255.0
11521159
if(bulb == 'B'):
11531160
# hexvalue is in hsv
11541161
h = int(hexvalue[0:4], 16)/360.0
@@ -1165,11 +1172,18 @@ def set_version(self, version):
11651172
Type B has keys 20-29
11661173
"""
11671174
self.version = version
1168-
# Try to determine type of BulbDevice Type based on switch DPS
1175+
1176+
# Try to determine type of BulbDevice Type based on DPS indexes
11691177
status = self.status()
11701178
if 'dps' in status:
11711179
if '1' not in status['dps']:
11721180
self.bulb_type = 'B'
1181+
if self.DPS_INDEX_BRIGHTNESS[self.bulb_type] in status['dps']:
1182+
self.has_brightness = True
1183+
if self.DPS_INDEX_COLOURTEMP[self.bulb_type] in status['dps']:
1184+
self.has_colourtemp = True
1185+
if self.DPS_INDEX_COLOUR[self.bulb_type] in status['dps']:
1186+
self.has_colour = True
11731187
else:
11741188
# response has no dps
11751189
self.bulb_type = 'B'
@@ -1236,6 +1250,8 @@ def set_colour(self, r, g, b):
12361250
g(int): Value for the colour green as int from 0-255.
12371251
b(int): Value for the colour blue as int from 0-255.
12381252
"""
1253+
if not self.has_colour:
1254+
return error_json(ERR_FUNCTION, "set_colour: Device does not support color.")
12391255
if not 0 <= r <= 255:
12401256
return error_json(ERR_RANGE,
12411257
"set_colour: The value for red needs to be between 0 and 255.")
@@ -1254,6 +1270,36 @@ def set_colour(self, r, g, b):
12541270
data = self._send_receive(payload)
12551271
return data
12561272

1273+
def set_hsv(self, h, s, v):
1274+
"""
1275+
Set colour of an rgb bulb using h, s, v.
1276+
1277+
Args:
1278+
h(float): colour Hue as int from 0-1
1279+
s(float): colour Saturation as int from 0-1
1280+
v(float): colour Value as int from 0-1
1281+
"""
1282+
if not self.has_colour:
1283+
return error_json(ERR_FUNCTION, "set_colour: Device does not support color.")
1284+
if not 0 <= h <= 1.0:
1285+
return error_json(ERR_RANGE,
1286+
"set_colour: The value for Hue needs to be between 0 and 1.")
1287+
if not 0 <= s <= 1.0:
1288+
return error_json(ERR_RANGE,
1289+
"set_colour: The value for Saturation needs to be between 0 and 1.")
1290+
if not 0 <= v <= 1.0:
1291+
return error_json(ERR_RANGE,
1292+
"set_colour: The value for Value needs to be between 0 and 1.")
1293+
1294+
(r,g,b) = colorsys.hsv_to_rgb(h,s,v)
1295+
hexvalue = BulbDevice._rgb_to_hexvalue(r*255.0, g*255.0, b*255.0, self.bulb_type)
1296+
1297+
payload = self.generate_payload(CONTROL, {
1298+
self.DPS_INDEX_MODE[self.bulb_type]: self.DPS_MODE_COLOUR,
1299+
self.DPS_INDEX_COLOUR[self.bulb_type]: hexvalue})
1300+
data = self._send_receive(payload)
1301+
return data
1302+
12571303
def set_white_percentage(self, brightness=100, colourtemp=0):
12581304
"""
12591305
Set white coloured theme of an rgb bulb.
@@ -1349,9 +1395,28 @@ def set_brightness(self, brightness):
13491395
if self.bulb_type == 'B' and not (10 <= brightness <= 1000):
13501396
return error_json(ERR_RANGE,"set_brightness: The brightness needs to be between 10 and 1000.")
13511397

1352-
payload = self.generate_payload(
1353-
CONTROL, {self.DPS_INDEX_BRIGHTNESS[self.bulb_type]: brightness})
1354-
data = self._send_receive(payload)
1398+
# Determine which mode bulb is in and adjust accordingly
1399+
state = self.state()
1400+
data = error_json(ERR_STATE,"set_brightness: Unknown bulb state.")
1401+
1402+
if 'mode' in state:
1403+
if state['mode'] == 'white':
1404+
# for white mode use DPS for brightness
1405+
if not self.has_brightness:
1406+
return error_json(ERR_FUNCTION, "set_colour: Device does not support brightness.")
1407+
payload = self.generate_payload(
1408+
CONTROL, {self.DPS_INDEX_BRIGHTNESS[self.bulb_type]: brightness})
1409+
data = self._send_receive(payload)
1410+
1411+
if state['mode'] == 'colour':
1412+
# for colour mode use hsv to increase brightness
1413+
if self.bulb_type == 'A':
1414+
value = brightness / 255.0
1415+
else:
1416+
value = brightness / 1000.0
1417+
(h,s,v) = self.colour_hsv()
1418+
data = self.set_hsv(h,s,value)
1419+
13551420
return data
13561421

13571422
def set_colourtemp_percentage(self, colourtemp=100):
@@ -1377,6 +1442,8 @@ def set_colourtemp(self, colourtemp):
13771442
Args:
13781443
colourtemp(int): Value for the colour temperature (0-255).
13791444
"""
1445+
if not self.has_colourtemp:
1446+
return error_json(ERR_FUNCTION, "set_colourtemp: Device does not support colortemp.")
13801447
if self.bulb_type == 'A' and not (0 <= colourtemp <= 255):
13811448
return error_json(ERR_RANGE,
13821449
"set_colourtemp: The colour temperature needs to be between 0 and 255.")
@@ -1411,6 +1478,8 @@ def state(self):
14111478
"""Return state of Bulb"""
14121479
status = self.status()
14131480
state = {}
1481+
if not status:
1482+
return error_json(ERR_JSON,"state: empty response")
14141483

14151484
for key in status[self.DPS].keys():
14161485
if(key in self.DPS_2_STATE):

0 commit comments

Comments
 (0)