183183ERR_RANGE = 903
184184ERR_PAYLOAD = 904
185185ERR_OFFLINE = 905
186+ ERR_STATE = 906
187+ ERR_FUNCTION = 907
186188
187189error_codes = {
188190 ERR_JSON : 'Invalid JSON Response from Device' ,
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