Package blinkstick :: Module blinkstick
[frames] | no frames]

Source Code for Module blinkstick.blinkstick

   1  from ._version import  __version__ 
   2  import time 
   3  import sys 
   4  import re 
   5   
   6  if sys.platform == "win32": 
   7      import pywinusb.hid as hid 
   8      from ctypes import * 
   9  else: 
  10      import usb.core 
  11      import usb.util 
  12   
  13  from random import randint 
  14   
  15  """ 
  16  Main module to control BlinkStick and BlinkStick Pro devices. 
  17  """ 
  18   
  19  VENDOR_ID = 0x20a0 
  20  PRODUCT_ID = 0x41e5 
  21   
22 -class BlinkStickException(Exception):
23 pass
24 25
26 -class BlinkStick(object):
27 """ 28 BlinkStick class is designed to control regular BlinkStick devices, or BlinkStick Pro 29 devices in Normal or Inverse modes. Please refer to L{BlinkStick.set_mode} for more details 30 about BlinkStick Pro device modes. 31 32 Code examples on how you can use this class are available here: 33 34 U{https://github.com/arvydas/blinkstick-python/wiki} 35 """ 36 37 _names_to_hex = {'aliceblue': '#f0f8ff', 38 'antiquewhite': '#faebd7', 39 'aqua': '#00ffff', 40 'aquamarine': '#7fffd4', 41 'azure': '#f0ffff', 42 'beige': '#f5f5dc', 43 'bisque': '#ffe4c4', 44 'black': '#000000', 45 'blanchedalmond': '#ffebcd', 46 'blue': '#0000ff', 47 'blueviolet': '#8a2be2', 48 'brown': '#a52a2a', 49 'burlywood': '#deb887', 50 'cadetblue': '#5f9ea0', 51 'chartreuse': '#7fff00', 52 'chocolate': '#d2691e', 53 'coral': '#ff7f50', 54 'cornflowerblue': '#6495ed', 55 'cornsilk': '#fff8dc', 56 'crimson': '#dc143c', 57 'cyan': '#00ffff', 58 'darkblue': '#00008b', 59 'darkcyan': '#008b8b', 60 'darkgoldenrod': '#b8860b', 61 'darkgray': '#a9a9a9', 62 'darkgrey': '#a9a9a9', 63 'darkgreen': '#006400', 64 'darkkhaki': '#bdb76b', 65 'darkmagenta': '#8b008b', 66 'darkolivegreen': '#556b2f', 67 'darkorange': '#ff8c00', 68 'darkorchid': '#9932cc', 69 'darkred': '#8b0000', 70 'darksalmon': '#e9967a', 71 'darkseagreen': '#8fbc8f', 72 'darkslateblue': '#483d8b', 73 'darkslategray': '#2f4f4f', 74 'darkslategrey': '#2f4f4f', 75 'darkturquoise': '#00ced1', 76 'darkviolet': '#9400d3', 77 'deeppink': '#ff1493', 78 'deepskyblue': '#00bfff', 79 'dimgray': '#696969', 80 'dimgrey': '#696969', 81 'dodgerblue': '#1e90ff', 82 'firebrick': '#b22222', 83 'floralwhite': '#fffaf0', 84 'forestgreen': '#228b22', 85 'fuchsia': '#ff00ff', 86 'gainsboro': '#dcdcdc', 87 'ghostwhite': '#f8f8ff', 88 'gold': '#ffd700', 89 'goldenrod': '#daa520', 90 'gray': '#808080', 91 'grey': '#808080', 92 'green': '#008000', 93 'greenyellow': '#adff2f', 94 'honeydew': '#f0fff0', 95 'hotpink': '#ff69b4', 96 'indianred': '#cd5c5c', 97 'indigo': '#4b0082', 98 'ivory': '#fffff0', 99 'khaki': '#f0e68c', 100 'lavender': '#e6e6fa', 101 'lavenderblush': '#fff0f5', 102 'lawngreen': '#7cfc00', 103 'lemonchiffon': '#fffacd', 104 'lightblue': '#add8e6', 105 'lightcoral': '#f08080', 106 'lightcyan': '#e0ffff', 107 'lightgoldenrodyellow': '#fafad2', 108 'lightgray': '#d3d3d3', 109 'lightgrey': '#d3d3d3', 110 'lightgreen': '#90ee90', 111 'lightpink': '#ffb6c1', 112 'lightsalmon': '#ffa07a', 113 'lightseagreen': '#20b2aa', 114 'lightskyblue': '#87cefa', 115 'lightslategray': '#778899', 116 'lightslategrey': '#778899', 117 'lightsteelblue': '#b0c4de', 118 'lightyellow': '#ffffe0', 119 'lime': '#00ff00', 120 'limegreen': '#32cd32', 121 'linen': '#faf0e6', 122 'magenta': '#ff00ff', 123 'maroon': '#800000', 124 'mediumaquamarine': '#66cdaa', 125 'mediumblue': '#0000cd', 126 'mediumorchid': '#ba55d3', 127 'mediumpurple': '#9370d8', 128 'mediumseagreen': '#3cb371', 129 'mediumslateblue': '#7b68ee', 130 'mediumspringgreen': '#00fa9a', 131 'mediumturquoise': '#48d1cc', 132 'mediumvioletred': '#c71585', 133 'midnightblue': '#191970', 134 'mintcream': '#f5fffa', 135 'mistyrose': '#ffe4e1', 136 'moccasin': '#ffe4b5', 137 'navajowhite': '#ffdead', 138 'navy': '#000080', 139 'oldlace': '#fdf5e6', 140 'olive': '#808000', 141 'olivedrab': '#6b8e23', 142 'orange': '#ffa500', 143 'orangered': '#ff4500', 144 'orchid': '#da70d6', 145 'palegoldenrod': '#eee8aa', 146 'palegreen': '#98fb98', 147 'paleturquoise': '#afeeee', 148 'palevioletred': '#d87093', 149 'papayawhip': '#ffefd5', 150 'peachpuff': '#ffdab9', 151 'peru': '#cd853f', 152 'pink': '#ffc0cb', 153 'plum': '#dda0dd', 154 'powderblue': '#b0e0e6', 155 'purple': '#800080', 156 'red': '#ff0000', 157 'rosybrown': '#bc8f8f', 158 'royalblue': '#4169e1', 159 'saddlebrown': '#8b4513', 160 'salmon': '#fa8072', 161 'sandybrown': '#f4a460', 162 'seagreen': '#2e8b57', 163 'seashell': '#fff5ee', 164 'sienna': '#a0522d', 165 'silver': '#c0c0c0', 166 'skyblue': '#87ceeb', 167 'slateblue': '#6a5acd', 168 'slategray': '#708090', 169 'slategrey': '#708090', 170 'snow': '#fffafa', 171 'springgreen': '#00ff7f', 172 'steelblue': '#4682b4', 173 'tan': '#d2b48c', 174 'teal': '#008080', 175 'thistle': '#d8bfd8', 176 'tomato': '#ff6347', 177 'turquoise': '#40e0d0', 178 'violet': '#ee82ee', 179 'wheat': '#f5deb3', 180 'white': '#ffffff', 181 'whitesmoke': '#f5f5f5', 182 'yellow': '#ffff00', 183 'yellowgreen': '#9acd32'} 184 185 HEX_COLOR_RE = re.compile(r'^#([a-fA-F0-9]{3}|[a-fA-F0-9]{6})$') 186 187 inverse = False 188 error_reporting = True 189 max_rgb_value = 255 190
191 - def __init__(self, device=None, error_reporting=True):
192 """ 193 Constructor for the class. 194 195 @type error_reporting: Boolean 196 @param error_reporting: display errors if they occur during communication with the device 197 """ 198 self.error_reporting = error_reporting 199 200 if device: 201 self.device = device 202 if sys.platform == "win32": 203 self.device.open() 204 self.reports = self.device.find_feature_reports() 205 else: 206 self.open_device(device) 207 208 self.bs_serial = self.get_serial()
209
210 - def _usb_get_string(self, device, length, index):
211 try: 212 return usb.util.get_string(device, length, index) 213 except usb.USBError: 214 # Could not communicate with BlinkStick device 215 # attempt to find it again based on serial 216 217 if self._refresh_device(): 218 return usb.util.get_string(self.device, length, index) 219 else: 220 raise BlinkStickException("Could not communicate with BlinkStick {0} - it may have been removed".format(self.bs_serial))
221
222 - def _usb_ctrl_transfer(self, bmRequestType, bRequest, wValue, wIndex, data_or_wLength):
223 if sys.platform == "win32": 224 if bmRequestType == 0x20: 225 data = (c_ubyte * len(data_or_wLength))(*[c_ubyte(ord(c)) for c in data_or_wLength]) 226 data[0] = wValue 227 if not self.device.send_feature_report(data): 228 if self._refresh_device(): 229 self.device.send_feature_report(data) 230 else: 231 raise BlinkStickException("Could not communicate with BlinkStick {0} - it may have been removed".format(self.bs_serial)) 232 233 elif bmRequestType == 0x80 | 0x20: 234 return self.reports[wValue - 1].get() 235 else: 236 try: 237 return self.device.ctrl_transfer(bmRequestType, bRequest, wValue, wIndex, data_or_wLength) 238 except usb.USBError: 239 # Could not communicate with BlinkStick device 240 # attempt to find it again based on serial 241 242 if self._refresh_device(): 243 return self.device.ctrl_transfer(bmRequestType, bRequest, wValue, wIndex, data_or_wLength) 244 else: 245 raise BlinkStickException("Could not communicate with BlinkStick {0} - it may have been removed".format(self.bs_serial))
246
247 - def _refresh_device(self):
248 d = find_by_serial(self.bs_serial) 249 if d: 250 self.device = d.device 251 return True
252
253 - def get_serial(self):
254 """ 255 Returns the serial number of device.:: 256 257 BSnnnnnn-1.0 258 || | | |- Software minor version 259 || | |--- Software major version 260 || |-------- Denotes sequential number 261 ||----------- Denotes BlinkStick device 262 263 Software version defines the capabilities of the device 264 265 @rtype: str 266 @return: Serial number of the device 267 """ 268 if sys.platform == "win32": 269 return self.device.serial_number 270 else: 271 return self._usb_get_string(self.device, 256, 3)
272
273 - def get_manufacturer(self):
274 """ 275 Get the manufacturer of the device 276 277 @rtype: str 278 @return: Device manufacturer's name 279 """ 280 if sys.platform == "win32": 281 return self.device.vendor_name 282 else: 283 return self._usb_get_string(self.device, 256, 1)
284 285
286 - def get_description(self):
287 """ 288 Get the description of the device 289 290 @rtype: str 291 @return: Device description 292 """ 293 if sys.platform == "win32": 294 return self.device.product_name 295 else: 296 return self._usb_get_string(self.device, 256, 2)
297
298 - def set_error_reporting(self, error_reporting):
299 """ 300 Enable or disable error reporting 301 302 @type error_reporting: Boolean 303 @param error_reporting: display errors if they occur during communication with the device 304 """ 305 self.error_reporting = error_reporting
306
307 - def set_color(self, channel=0, index=0, red=0, green=0, blue=0, name=None, hex=None):
308 """ 309 Set the color to the device as RGB 310 311 @type red: int 312 @param red: Red color intensity 0 is off, 255 is full red intensity 313 @type green: int 314 @param green: Green color intensity 0 is off, 255 is full green intensity 315 @type blue: int 316 @param blue: Blue color intensity 0 is off, 255 is full blue intensity 317 @type name: str 318 @param name: Use CSS color name as defined here: U{http://www.w3.org/TR/css3-color/} 319 @type hex: str 320 @param hex: Specify color using hexadecimal color value e.g. '#FF3366' 321 """ 322 323 red, green, blue = self._determine_rgb(red=red, green=green, blue=blue, name=name, hex=hex) 324 325 r = int(round(red, 3)) 326 g = int(round(green, 3)) 327 b = int(round(blue, 3)) 328 329 if self.inverse: 330 r, g, b = 255 - r, 255 - g, 255 - b 331 332 if index == 0 and channel == 0: 333 control_string = bytes(bytearray([0, r, g, b])) 334 report_id = 0x0001 335 else: 336 control_string = bytes(bytearray([5, channel, index, r, g, b])) 337 report_id = 0x0005 338 339 if self.error_reporting: 340 self._usb_ctrl_transfer(0x20, 0x9, report_id, 0, control_string) 341 else: 342 try: 343 self._usb_ctrl_transfer(0x20, 0x9, report_id, 0, control_string) 344 except Exception as e: 345 pass
346
347 - def _determine_rgb(self, red=0, green=0, blue=0, name=None, hex=None):
348 349 try: 350 if name: 351 # Special case for name="random" 352 if name is "random": 353 red = randint(0, 255) 354 green = randint(0, 255) 355 blue = randint(0, 255) 356 else: 357 red, green, blue = self._name_to_rgb(name) 358 elif hex: 359 red, green, blue = self._hex_to_rgb(hex) 360 except ValueError: 361 red = green = blue = 0 362 363 red, green, blue = _remap_rgb_value([red, green, blue], self.max_rgb_value) 364 365 # TODO - do smarts to determine input type from red var in case it is not int 366 367 return red, green, blue
368
369 - def _get_color_rgb(self, index=0):
370 if index == 0: 371 device_bytes = self._usb_ctrl_transfer(0x80 | 0x20, 0x1, 0x0001, 0, 33) 372 if self.inverse: 373 return [255 - device_bytes[1], 255 - device_bytes[2], 255 - device_bytes[3]] 374 else: 375 return [device_bytes[1], device_bytes[2], device_bytes[3]] 376 else: 377 data = self.get_led_data((index + 1) * 3) 378 379 return [data[index * 3 + 1], data[index * 3], data[index * 3 + 2]]
380
381 - def _get_color_hex(self, index=0):
382 r, g, b = self._get_color_rgb(index) 383 return '#%02x%02x%02x' % (r, g, b)
384
385 - def get_color(self, index=0, color_format='rgb'):
386 """ 387 Get the current device color in the defined format. 388 389 Currently supported formats: 390 391 1. rgb (default) - Returns values as 3-tuple (r,g,b) 392 2. hex - returns current device color as hexadecimal string 393 394 >>> b = blinkstick.find_first() 395 >>> b.set_color(red=255,green=0,blue=0) 396 >>> (r,g,b) = b.get_color() # Get color as rbg tuple 397 (255,0,0) 398 >>> hex = b.get_color(color_format='hex') # Get color as hex string 399 '#ff0000' 400 401 @type index: int 402 @param index: the index of the LED 403 @type color_format: str 404 @param color_format: "rgb" or "hex". Defaults to "rgb". 405 406 @rtype: (int, int, int) or str 407 @return: Either 3-tuple for R, G and B values, or hex string 408 """ 409 410 # Attempt to find a function to return the appropriate format 411 get_color_func = getattr(self, "_get_color_%s" % color_format, self._get_color_rgb) 412 if callable(get_color_func): 413 return get_color_func(index) 414 else: 415 # Should never get here, as we should always default to self._get_color_rgb 416 raise BlinkStickException("Could not return current color in format %s" % color_format)
417
418 - def _determine_report_id(self, led_count):
419 report_id = 9 420 max_leds = 64 421 422 if led_count <= 8 * 3: 423 max_leds = 8 424 report_id = 6 425 elif led_count <= 16 * 3: 426 max_leds = 16 427 report_id = 7 428 elif led_count <= 32 * 3: 429 max_leds = 32 430 report_id = 8 431 elif led_count <= 64 * 3: 432 max_leds = 64 433 report_id = 9 434 435 return report_id, max_leds
436
437 - def set_led_data(self, channel, data):
438 """ 439 Send LED data frame. 440 441 @type channel: int 442 @param channel: the channel which to send data to (R=0, G=1, B=2) 443 @type data: int[0..64*3] 444 @param data: The LED data frame in GRB format 445 """ 446 447 report_id, max_leds = self._determine_report_id(len(data)) 448 449 report = [0, channel] 450 451 for i in range(0, max_leds * 3): 452 if len(data) > i: 453 report.append(data[i]) 454 else: 455 report.append(0) 456 457 self.device.ctrl_transfer(0x20, 0x9, report_id, 0, bytes(bytearray(report)))
458
459 - def get_led_data(self, count):
460 """ 461 Get LED data frame on the device. 462 463 @type count: int 464 @param count: How much data to retrieve. Can be in the range of 0..64*3 465 @rtype: int[0..64*3] 466 @return: LED data currently stored in the RAM of the device 467 """ 468 469 report_id, max_leds = self._determine_report_id(count) 470 471 device_bytes = self._usb_ctrl_transfer(0x80 | 0x20, 0x1, report_id, 0, max_leds * 3 + 2) 472 473 return device_bytes[2: 2 + count * 3]
474
475 - def set_mode(self, mode):
476 """ 477 Set device mode for BlinkStick Pro. Device currently supports the following modes: 478 479 - 0 - (default) use R, G and B channels to control single RGB LED 480 - 1 - same as 0, but inverse mode 481 - 2 - control up to 64 WS2812 individual LEDs per each R, G and B channel 482 483 You can find out more about BlinkStick Pro modes: 484 485 U{http://www.blinkstick.com/help/tutorials/blinkstick-pro-modes} 486 487 @type mode: int 488 @param mode: Device mode to set 489 """ 490 control_string = bytes(bytearray([4, mode])) 491 492 self.device.ctrl_transfer(0x20, 0x9, 0x0004, 0, control_string)
493
494 - def get_mode(self):
495 """ 496 Get BlinkStick Pro mode. Device currently supports the following modes: 497 498 - 0 - (default) use R, G and B channels to control single RGB LED 499 - 1 - same as 0, but inverse mode 500 - 2 - control up to 64 WS2812 individual LEDs per each R, G and B channel 501 502 You can find out more about BlinkStick Pro modes: 503 504 U{http://www.blinkstick.com/help/tutorials/blinkstick-pro-modes} 505 506 @rtype: int 507 @return: Device mode 508 """ 509 510 device_bytes = self.device.ctrl_transfer(0x80 | 0x20, 0x1, 0x0004, 0, 2) 511 512 if len(device_bytes) >= 2: 513 return device_bytes[1] 514 else: 515 return -1
516
517 - def get_info_block1(self):
518 """ 519 Get the infoblock1 of the device. 520 521 This is a 32 byte array that can contain any data. It's supposed to 522 hold the "Name" of the device making it easier to identify rather than 523 a serial number. 524 525 @rtype: str 526 @return: InfoBlock1 currently stored on the device 527 """ 528 529 device_bytes = self._usb_ctrl_transfer(0x80 | 0x20, 0x1, 0x0002, 0, 33) 530 result = "" 531 for i in device_bytes[1:]: 532 if i == 0: 533 break 534 result += chr(i) 535 return result
536
537 - def get_info_block2(self):
538 """ 539 Get the infoblock2 of the device. 540 541 This is a 32 byte array that can contain any data. 542 543 @rtype: str 544 @return: InfoBlock2 currently stored on the device 545 """ 546 device_bytes = self._usb_ctrl_transfer(0x80 | 0x20, 0x1, 0x0003, 0, 33) 547 result = "" 548 for i in device_bytes[1:]: 549 if i == 0: 550 break 551 result += chr(i) 552 return result
553
554 - def _data_to_message(self, data):
555 """ 556 Helper method to convert a string to byte array of 32 bytes. 557 558 @type data: str 559 @param data: The data to convert to byte array 560 561 @rtype: byte[32] 562 @return: It fills the rest of bytes with zeros. 563 """ 564 bytes = [1] 565 for c in data: 566 bytes.append(ord(c)) 567 568 for i in range(32 - len(data)): 569 bytes.append(0) 570 571 return bytes
572
573 - def set_info_block1(self, data):
574 """ 575 Sets the infoblock1 with specified string. 576 577 It fills the rest of 32 bytes with zeros. 578 579 @type data: str 580 @param data: InfoBlock1 for the device to set 581 """ 582 self._usb_ctrl_transfer(0x20, 0x9, 0x0002, 0, self._data_to_message(data))
583
584 - def set_info_block2(self, data):
585 """ 586 Sets the infoblock2 with specified string. 587 588 It fills the rest of 32 bytes with zeros. 589 590 @type data: str 591 @param data: InfoBlock2 for the device to set 592 """ 593 self._usb_ctrl_transfer(0x20, 0x9, 0x0003, 0, self._data_to_message(data))
594
595 - def set_random_color(self):
596 """ 597 Sets random color to the device. 598 """ 599 self.set_color(name="random")
600
601 - def turn_off(self):
602 """ 603 Turns off LED. 604 """ 605 self.set_color()
606
607 - def pulse(self, channel=0, index=0, red=0, green=0, blue=0, name=None, hex=None, repeats=1, duration=1000, steps=50):
608 """ 609 Morph to the specified color from black and back again. 610 611 @type red: int 612 @param red: Red color intensity 0 is off, 255 is full red intensity 613 @type green: int 614 @param green: Green color intensity 0 is off, 255 is full green intensity 615 @type blue: int 616 @param blue: Blue color intensity 0 is off, 255 is full blue intensity 617 @type name: str 618 @param name: Use CSS color name as defined here: U{http://www.w3.org/TR/css3-color/} 619 @type hex: str 620 @param hex: Specify color using hexadecimal color value e.g. '#FF3366' 621 @type repeats: int 622 @param repeats: Number of times to pulse the LED 623 @type duration: int 624 @param duration: Duration for pulse in milliseconds 625 @type steps: int 626 @param steps: Number of gradient steps 627 """ 628 r, g, b = self._determine_rgb(red=red, green=green, blue=blue, name=name, hex=hex) 629 630 self.turn_off() 631 for x in range(repeats): 632 self.morph(channel=channel, index=index, red=r, green=g, blue=b, duration=duration, steps=steps) 633 self.morph(channel=channel, index=index, red=0, green=0, blue=0, duration=duration, steps=steps)
634 662
663 - def morph(self, channel=0, index=0, red=0, green=0, blue=0, name=None, hex=None, duration=1000, steps=50):
664 """ 665 Morph to the specified color. 666 667 @type red: int 668 @param red: Red color intensity 0 is off, 255 is full red intensity 669 @type green: int 670 @param green: Green color intensity 0 is off, 255 is full green intensity 671 @type blue: int 672 @param blue: Blue color intensity 0 is off, 255 is full blue intensity 673 @type name: str 674 @param name: Use CSS color name as defined here: U{http://www.w3.org/TR/css3-color/} 675 @type hex: str 676 @param hex: Specify color using hexadecimal color value e.g. '#FF3366' 677 @type duration: int 678 @param duration: Duration for morph in milliseconds 679 @type steps: int 680 @param steps: Number of gradient steps (default 50) 681 """ 682 683 r_end, g_end, b_end = self._determine_rgb(red=red, green=green, blue=blue, name=name, hex=hex) 684 685 r_start, g_start, b_start = _remap_rgb_value_reverse(self._get_color_rgb(index), self.max_rgb_value) 686 687 if r_start > 255 or g_start > 255 or b_start > 255: 688 r_start = 0 689 g_start = 0 690 b_start = 0 691 692 gradient = [] 693 694 steps += 1 695 for n in range(1, steps): 696 d = 1.0 * n / steps 697 r = (r_start * (1 - d)) + (r_end * d) 698 g = (g_start * (1 - d)) + (g_end * d) 699 b = (b_start * (1 - d)) + (b_end * d) 700 701 gradient.append((r, g, b)) 702 703 ms_delay = float(duration) / float(1000 * steps) 704 705 self.set_color(channel=channel, index=index, red=r_start, green=g_start, blue=b_start) 706 707 for grad in gradient: 708 grad_r, grad_g, grad_b = grad 709 710 self.set_color(channel=channel, index=index, red=grad_r, green=grad_g, blue=grad_b) 711 time.sleep(ms_delay) 712 713 self.set_color(channel=channel, index=index, red=r_end, green=g_end, blue=b_end)
714
715 - def open_device(self, d):
716 """Open device. 717 @param d: Device to open 718 """ 719 if self.device is None: 720 raise BlinkStickException("Could not find BlinkStick...") 721 722 if self.device.is_kernel_driver_active(0): 723 try: 724 self.device.detach_kernel_driver(0) 725 except usb.core.USBError as e: 726 raise BlinkStickException("Could not detach kernel driver: %s" % str(e)) 727 728 return True
729
730 - def get_inverse(self):
731 """ 732 Get the value of inverse mode. This applies only to BlinkStick. Please use L{set_mode} for BlinkStick Pro 733 to permanently set the inverse mode to the device. 734 735 @rtype: bool 736 @return: True if inverse mode, otherwise false 737 """ 738 return self.inverse
739
740 - def set_inverse(self, value):
741 """ 742 Set inverse mode. This applies only to BlinkStick. Please use L{set_mode} for BlinkStick Pro 743 to permanently set the inverse mode to the device. 744 745 @type value: bool 746 @param value: True/False to set the inverse mode 747 """ 748 self.inverse = value
749
750 - def set_max_rgb_value(self, value):
751 """ 752 Set RGB color limit. {set_color} function will automatically remap 753 the values to maximum supplied. 754 755 @type value: int 756 @param value: 0..255 maximum value for each R, G and B color 757 """ 758 self.max_rgb_value = value
759
760 - def get_max_rgb_value(self, max_rgb_value):
761 """ 762 Get RGB color limit. {set_color} function will automatically remap 763 the values to maximum set. 764 765 @rtype: int 766 @return: 0..255 maximum value for each R, G and B color 767 """ 768 return self.max_rgb_value
769
770 - def _name_to_hex(self, name):
771 """ 772 Convert a color name to a normalized hexadecimal color value. 773 774 The color name will be normalized to lower-case before being 775 looked up, and when no color of that name exists in the given 776 specification, ``ValueError`` is raised. 777 778 Examples: 779 780 >>> _name_to_hex('white') 781 '#ffffff' 782 >>> _name_to_hex('navy') 783 '#000080' 784 >>> _name_to_hex('goldenrod') 785 '#daa520' 786 """ 787 normalized = name.lower() 788 try: 789 hex_value = self._names_to_hex[normalized] 790 except KeyError: 791 raise ValueError("'%s' is not defined as a named color." % (name)) 792 return hex_value
793
794 - def _hex_to_rgb(self, hex_value):
795 """ 796 Convert a hexadecimal color value to a 3-tuple of integers 797 suitable for use in an ``rgb()`` triplet specifying that color. 798 799 The hexadecimal value will be normalized before being converted. 800 801 Examples: 802 803 >>> _hex_to_rgb('#fff') 804 (255, 255, 255) 805 >>> _hex_to_rgb('#000080') 806 (0, 0, 128) 807 808 """ 809 hex_digits = self._normalize_hex(hex_value) 810 return tuple([int(s, 16) for s in (hex_digits[1:3], hex_digits[3:5], hex_digits[5:7])])
811
812 - def _normalize_hex(self, hex_value):
813 """ 814 Normalize a hexadecimal color value to the following form and 815 return the result:: 816 817 #[a-f0-9]{6} 818 819 In other words, the following transformations are applied as 820 needed: 821 822 * If the value contains only three hexadecimal digits, it is expanded to six. 823 824 * The value is normalized to lower-case. 825 826 If the supplied value cannot be interpreted as a hexadecimal color 827 value, ``ValueError`` is raised. 828 829 Examples: 830 831 >>> _normalize_hex('#0099cc') 832 '#0099cc' 833 >>> _normalize_hex('#0099CC') 834 '#0099cc' 835 >>> _normalize_hex('#09c') 836 '#0099cc' 837 >>> _normalize_hex('#09C') 838 '#0099cc' 839 >>> _normalize_hex('0099cc') 840 Traceback (most recent call last): 841 ... 842 ValueError: '0099cc' is not a valid hexadecimal color value. 843 844 """ 845 try: 846 hex_digits = self.HEX_COLOR_RE.match(hex_value).groups()[0] 847 except AttributeError: 848 raise ValueError("'%s' is not a valid hexadecimal color value." % hex_value) 849 if len(hex_digits) == 3: 850 hex_digits = ''.join([2 * s for s in hex_digits]) 851 return '#%s' % hex_digits.lower()
852
853 - def _name_to_rgb(self, name):
854 """ 855 Convert a color name to a 3-tuple of integers suitable for use in 856 an ``rgb()`` triplet specifying that color. 857 858 The color name will be normalized to lower-case before being 859 looked up, and when no color of that name exists in the given 860 specification, ``ValueError`` is raised. 861 862 Examples: 863 864 >>> _name_to_rgb('white') 865 (255, 255, 255) 866 >>> _name_to_rgb('navy') 867 (0, 0, 128) 868 >>> _name_to_rgb('goldenrod') 869 (218, 165, 32) 870 871 """ 872 return self._hex_to_rgb(self._name_to_hex(name))
873
874 -class BlinkStickPro(object):
875 """ 876 BlinkStickPro class is specifically designed to control the individually 877 addressable LEDs connected to the device. The tutorials section contains 878 all the details on how to connect them to BlinkStick Pro. 879 880 U{http://www.blinkstick.com/help/tutorials} 881 882 Code example on how you can use this class are available here: 883 884 U{https://github.com/arvydas/blinkstick-python/wiki#code-examples-for-blinkstick-pro} 885 """ 886
887 - def __init__(self, r_led_count=0, g_led_count=0, b_led_count=0, delay=0.002, max_rgb_value=255):
888 """ 889 Initialize BlinkStickPro class. 890 891 @type r_led_count: int 892 @param r_led_count: number of LEDs on R channel 893 @type g_led_count: int 894 @param g_led_count: number of LEDs on G channel 895 @type b_led_count: int 896 @param b_led_count: number of LEDs on B channel 897 @type delay: int 898 @param delay: default transmission delay between frames 899 @type max_rgb_value: int 900 @param max_rgb_value: maximum color value for RGB channels 901 """ 902 903 self.r_led_count = r_led_count 904 self.g_led_count = g_led_count 905 self.b_led_count = b_led_count 906 907 self.fps_count = -1 908 909 self.data_transmission_delay = delay 910 911 self.max_rgb_value = max_rgb_value 912 913 # initialise data store for each channel 914 # pre-populated with zeroes 915 916 self.data = [[], [], []] 917 918 for i in range(0, r_led_count): 919 self.data[0].append([0, 0, 0]) 920 921 for i in range(0, g_led_count): 922 self.data[1].append([0, 0, 0]) 923 924 for i in range(0, b_led_count): 925 self.data[2].append([0, 0, 0]) 926 927 self.bstick = None
928
929 - def set_color(self, channel, index, r, g, b, remap_values=True):
930 """ 931 Set the color of a single pixel 932 933 @type channel: int 934 @param channel: R, G or B channel 935 @type index: int 936 @param index: the index of LED on the channel 937 @type r: int 938 @param r: red color byte 939 @type g: int 940 @param g: green color byte 941 @type b: int 942 @param b: blue color byte 943 """ 944 945 if remap_values: 946 r, g, b = [_remap_color(val, self.max_rgb_value) for val in [r, g, b]] 947 948 self.data[channel][index] = [g, r, b]
949
950 - def get_color(self, channel, index):
951 """ 952 Get the current color of a single pixel. 953 954 @type channel: int 955 @param channel: the channel of the LED 956 @type index: int 957 @param index: the index of the LED 958 959 @rtype: (int, int, int) 960 @return: 3-tuple for R, G and B values 961 """ 962 963 val = self.data[channel][index] 964 return [val[1], val[0], val[2]]
965
966 - def clear(self):
967 """ 968 Set all pixels to black in the frame buffer. 969 """ 970 for x in range(0, self.r_led_count): 971 self.set_color(0, x, 0, 0, 0) 972 973 for x in range(0, self.g_led_count): 974 self.set_color(1, x, 0, 0, 0) 975 976 for x in range(0, self.b_led_count): 977 self.set_color(2, x, 0, 0, 0)
978
979 - def off(self):
980 """ 981 Set all pixels to black in on the device. 982 """ 983 self.clear() 984 self.send_data_all()
985
986 - def connect(self, serial=None):
987 """ 988 Connect to the first BlinkStick found 989 990 @type serial: str 991 @param serial: Select the serial number of BlinkStick 992 """ 993 994 if serial is None: 995 self.bstick = find_first() 996 else: 997 self.bstick = find_by_serial(serial=serial) 998 999 return self.bstick is not None
1000
1001 - def send_data(self, channel):
1002 """ 1003 Send data stored in the internal buffer to the channel. 1004 1005 @param channel: 1006 - 0 - R pin on BlinkStick Pro board 1007 - 1 - G pin on BlinkStick Pro board 1008 - 2 - B pin on BlinkStick Pro board 1009 """ 1010 packet_data = [item for sublist in self.data[channel] for item in sublist] 1011 1012 try: 1013 self.bstick.set_led_data(channel, packet_data) 1014 time.sleep(self.data_transmission_delay) 1015 except Exception as e: 1016 print "Exception: {0}".format(e)
1017
1018 - def send_data_all(self):
1019 """ 1020 Send data to all channels 1021 """ 1022 if self.r_led_count > 0: 1023 self.send_data(0) 1024 1025 if self.g_led_count > 0: 1026 self.send_data(1) 1027 1028 if self.b_led_count > 0: 1029 self.send_data(2)
1030
1031 -class BlinkStickProMatrix(BlinkStickPro):
1032 """ 1033 BlinkStickProMatrix class is specifically designed to control the individually 1034 addressable LEDs connected to the device and arranged in a matrix. The tutorials section contains 1035 all the details on how to connect them to BlinkStick Pro with matrices. 1036 1037 U{http://www.blinkstick.com/help/tutorials/blinkstick-pro-adafruit-neopixel-matrices} 1038 1039 Code example on how you can use this class are available here: 1040 1041 U{https://github.com/arvydas/blinkstick-python/wiki#code-examples-for-blinkstick-pro} 1042 1043 Matrix is driven by using L{BlinkStickProMatrix.set_color} with [x,y] coordinates and class automatically 1044 divides data into subsets and sends it to the matrices. 1045 1046 For example, if you have 2 8x8 matrices connected to BlinkStickPro and you initialize 1047 the class with 1048 1049 >>> matrix = BlinkStickProMatrix(r_columns=8, r_rows=8, g_columns=8, g_rows=8) 1050 1051 Then you can set the internal framebuffer by using {set_color} command: 1052 1053 >>> matrix.set_color(x=10, y=5, r=255, g=0, b=0) 1054 >>> matrix.set_color(x=6, y=3, r=0, g=255, b=0) 1055 1056 And send data to both matrices in one go: 1057 1058 >>> matrix.send_data_all() 1059 1060 """ 1061
1062 - def __init__(self, r_columns=0, r_rows=0, g_columns=0, g_rows=0, b_columns=0, b_rows=0, delay=0.002, max_rgb_value=255):
1063 """ 1064 Initialize BlinkStickProMatrix class. 1065 1066 @type r_columns: int 1067 @param r_columns: number of matric columns for R channel 1068 @type g_columns: int 1069 @param g_columns: number of matric columns for R channel 1070 @type b_columns: int 1071 @param b_columns: number of matric columns for R channel 1072 @type delay: int 1073 @param delay: default transmission delay between frames 1074 @type max_rgb_value: int 1075 @param max_rgb_value: maximum color value for RGB channels 1076 """ 1077 r_leds = r_columns * r_rows 1078 g_leds = g_columns * g_rows 1079 b_leds = b_columns * b_rows 1080 1081 self.r_columns = r_columns 1082 self.r_rows = r_rows 1083 self.g_columns = g_columns 1084 self.g_rows = g_rows 1085 self.b_columns = b_columns 1086 self.b_rows = b_rows 1087 1088 super(BlinkStickProMatrix, self).__init__(r_led_count=r_leds, g_led_count=g_leds, b_led_count=b_leds, delay=delay, max_rgb_value=max_rgb_value) 1089 1090 self.rows = max(r_rows, g_rows, b_rows) 1091 self.cols = r_columns + g_columns + b_columns 1092 1093 # initialise data store for matrix pre-populated with zeroes 1094 self.matrix_data = [] 1095 1096 for i in range(0, self.rows * self.cols): 1097 self.matrix_data.append([0, 0, 0])
1098
1099 - def set_color(self, x, y, r, g, b, remap_values=True):
1100 """ 1101 Set the color of a single pixel in the internal framebuffer. 1102 1103 @type x: int 1104 @param x: the x location in the matrix 1105 @type y: int 1106 @param y: the y location in the matrix 1107 @type r: int 1108 @param r: red color byte 1109 @type g: int 1110 @param g: green color byte 1111 @type b: int 1112 @param b: blue color byte 1113 @type remap_values: bool 1114 @param remap_values: Automatically remap values based on the {max_rgb_value} supplied in the constructor 1115 """ 1116 1117 if remap_values: 1118 r, g, b = [_remap_color(val, self.max_rgb_value) for val in [r, g, b]] 1119 1120 self.matrix_data[self._coord_to_index(x, y)] = [g, r, b]
1121
1122 - def _coord_to_index(self, x, y):
1123 return y * self.cols + x
1124
1125 - def get_color(self, x, y):
1126 """ 1127 Get the current color of a single pixel. 1128 1129 @type x: int 1130 @param x: x coordinate of the internal framebuffer 1131 @type y: int 1132 @param y: y coordinate of the internal framebuffer 1133 1134 @rtype: (int, int, int) 1135 @return: 3-tuple for R, G and B values 1136 """ 1137 1138 val = self.matrix_data[self._coord_to_index(x, y)] 1139 return [val[1], val[0], val[2]]
1140
1141 - def shift_left(self, remove=False):
1142 """ 1143 Shift all LED values in the matrix to the left 1144 1145 @type remove: bool 1146 @param remove: whether to remove the pixels on the last column or move the to the first column 1147 """ 1148 if not remove: 1149 temp = [] 1150 for y in range(0, self.rows): 1151 temp.append(self.get_color(0, y)) 1152 1153 for y in range(0, self.rows): 1154 for x in range(0, self.cols - 1): 1155 r, g, b = self.get_color(x + 1, y) 1156 1157 self.set_color(x, y, r, g, b, False) 1158 1159 if remove: 1160 for y in range(0, self.rows): 1161 self.set_color(self.cols - 1, y, 0, 0, 0, False) 1162 else: 1163 for y in range(0, self.rows): 1164 col = temp[y] 1165 self.set_color(self.cols - 1, y, col[0], col[1], col[2], False)
1166
1167 - def shift_right(self, remove=False):
1168 """ 1169 Shift all LED values in the matrix to the right 1170 1171 @type remove: bool 1172 @param remove: whether to remove the pixels on the last column or move the to the first column 1173 """ 1174 1175 if not remove: 1176 temp = [] 1177 for y in range(0, self.rows): 1178 temp.append(self.get_color(self.cols - 1, y)) 1179 1180 for y in range(0, self.rows): 1181 for x in reversed(range(1, self.cols)): 1182 r, g, b = self.get_color(x - 1, y) 1183 1184 self.set_color(x, y, r, g, b, False) 1185 1186 if remove: 1187 for y in range(0, self.rows): 1188 self.set_color(0, y, 0, 0, 0, False) 1189 else: 1190 for y in range(0, self.rows): 1191 col = temp[y] 1192 self.set_color(self.cols - 1, y, col[0], col[1], col[2], False)
1193
1194 - def shift_down(self, remove=False):
1195 """ 1196 Shift all LED values in the matrix down 1197 1198 @type remove: bool 1199 @param remove: whether to remove the pixels on the last column or move the to the first column 1200 """ 1201 1202 if not remove: 1203 temp = [] 1204 for x in range(0, self.cols): 1205 temp.append(self.get_color(x, self.rows - 1)) 1206 1207 for x in range(0, self.cols): 1208 for y in reversed(range(1, self.rows)): 1209 r, g, b = self.get_color(x, y - 1) 1210 1211 self.set_color(x, y, r, g, b, False) 1212 1213 if remove: 1214 for x in range(0, self.cols): 1215 self.set_color(x, 0, 0, 0, 0, False) 1216 else: 1217 for x in range(0, self.cols): 1218 col = temp[y] 1219 self.set_color(x, 0, col[0], col[1], col[2], False)
1220 1221
1222 - def shift_up(self, remove=False):
1223 """ 1224 Shift all LED values in the matrix up 1225 1226 @type remove: bool 1227 @param remove: whether to remove the pixels on the last column or move the to the first column 1228 """ 1229 1230 if not remove: 1231 temp = [] 1232 for x in range(0, self.cols): 1233 temp.append(self.get_color(x, 0)) 1234 1235 for x in range(0, self.cols): 1236 for y in range(0, self.rows - 1): 1237 r, g, b = self.get_color(x, y + 1) 1238 1239 self.set_color(x, y, r, g, b, False) 1240 1241 if remove: 1242 for x in range(0, self.cols): 1243 self.set_color(x, self.rows - 1, 0, 0, 0, False) 1244 else: 1245 for x in range(0, self.cols): 1246 col = temp[y] 1247 self.set_color(x, self.rows - 1, col[0], col[1], col[2], False)
1248
1249 - def number(self, x, y, n, r, g, b):
1250 """ 1251 Render a 3x5 number n at location x,y and r,g,b color 1252 1253 @type x: int 1254 @param x: the x location in the matrix (left of the number) 1255 @type y: int 1256 @param y: the y location in the matrix (top of the number) 1257 @type n: int 1258 @param n: number digit to render 0..9 1259 @type r: int 1260 @param r: red color byte 1261 @type g: int 1262 @param g: green color byte 1263 @type b: int 1264 @param b: blue color byte 1265 """ 1266 if n == 0: 1267 self.rectangle(x, y, x + 2, y + 4, r, g, b) 1268 elif n == 1: 1269 self.line(x + 1, y, x + 1, y + 4, r, g, b) 1270 self.line(x, y + 4, x + 2, y + 4, r, g, b) 1271 self.set_color(x, y + 1, r, g, b) 1272 elif n == 2: 1273 self.line(x, y, x + 2, y, r, g, b) 1274 self.line(x, y + 2, x + 2, y + 2, r, g, b) 1275 self.line(x, y + 4, x + 2, y + 4, r, g, b) 1276 self.set_color(x + 2, y + 1, r, g, b) 1277 self.set_color(x, y + 3, r, g, b) 1278 elif n == 3: 1279 self.line(x, y, x + 2, y, r, g, b) 1280 self.line(x, y + 2, x + 2, y + 2, r, g, b) 1281 self.line(x, y + 4, x + 2, y + 4, r, g, b) 1282 self.set_color(x + 2, y + 1, r, g, b) 1283 self.set_color(x + 2, y + 3, r, g, b) 1284 elif n == 4: 1285 self.line(x, y, x, y + 2, r, g, b) 1286 self.line(x + 2, y, x + 2, y + 4, r, g, b) 1287 self.set_color(x + 1, y + 2, r, g, b) 1288 elif n == 5: 1289 self.line(x, y, x + 2, y, r, g, b) 1290 self.line(x, y + 2, x + 2, y + 2, r, g, b) 1291 self.line(x, y + 4, x + 2, y + 4, r, g, b) 1292 self.set_color(x, y + 1, r, g, b) 1293 self.set_color(x + 2, y + 3, r, g, b) 1294 elif n == 6: 1295 self.line(x, y, x + 2, y, r, g, b) 1296 self.line(x, y + 2, x + 2, y + 2, r, g, b) 1297 self.line(x, y + 4, x + 2, y + 4, r, g, b) 1298 self.set_color(x, y + 1, r, g, b) 1299 self.set_color(x + 2, y + 3, r, g, b) 1300 self.set_color(x, y + 3, r, g, b) 1301 elif n == 7: 1302 self.line(x + 1, y + 2, x + 1, y + 4, r, g, b) 1303 self.line(x, y, x + 2, y, r, g, b) 1304 self.set_color(x + 2, y + 1, r, g, b) 1305 elif n == 8: 1306 self.line(x, y, x + 2, y, r, g, b) 1307 self.line(x, y + 2, x + 2, y + 2, r, g, b) 1308 self.line(x, y + 4, x + 2, y + 4, r, g, b) 1309 self.set_color(x, y + 1, r, g, b) 1310 self.set_color(x + 2, y + 1, r, g, b) 1311 self.set_color(x + 2, y + 3, r, g, b) 1312 self.set_color(x, y + 3, r, g, b) 1313 elif n == 9: 1314 self.line(x, y, x + 2, y, r, g, b) 1315 self.line(x, y + 2, x + 2, y + 2, r, g, b) 1316 self.line(x, y + 4, x + 2, y + 4, r, g, b) 1317 self.set_color(x, y + 1, r, g, b) 1318 self.set_color(x + 2, y + 1, r, g, b) 1319 self.set_color(x + 2, y + 3, r, g, b)
1320
1321 - def rectangle(self, x1, y1, x2, y2, r, g, b):
1322 """ 1323 Draw a rectangle with it's corners at x1:y1 and x2:y2 1324 1325 @type x1: int 1326 @param x1: the x1 location in the matrix for first corner of the rectangle 1327 @type y1: int 1328 @param y1: the y1 location in the matrix for first corner of the rectangle 1329 @type x2: int 1330 @param x2: the x2 location in the matrix for second corner of the rectangle 1331 @type y2: int 1332 @param y2: the y2 location in the matrix for second corner of the rectangle 1333 @type r: int 1334 @param r: red color byte 1335 @type g: int 1336 @param g: green color byte 1337 @type b: int 1338 @param b: blue color byte 1339 """ 1340 1341 self.line(x1, y1, x1, y2, r, g, b) 1342 self.line(x1, y1, x2, y1, r, g, b) 1343 self.line(x2, y1, x2, y2, r, g, b) 1344 self.line(x1, y2, x2, y2, r, g, b)
1345
1346 - def line(self, x1, y1, x2, y2, r, g, b):
1347 """ 1348 Draw a line from x1:y1 and x2:y2 1349 1350 @type x1: int 1351 @param x1: the x1 location in the matrix for the start of the line 1352 @type y1: int 1353 @param y1: the y1 location in the matrix for the start of the line 1354 @type x2: int 1355 @param x2: the x2 location in the matrix for the end of the line 1356 @type y2: int 1357 @param y2: the y2 location in the matrix for the end of the line 1358 @type r: int 1359 @param r: red color byte 1360 @type g: int 1361 @param g: green color byte 1362 @type b: int 1363 @param b: blue color byte 1364 """ 1365 points = [] 1366 is_steep = abs(y2 - y1) > abs(x2 - x1) 1367 if is_steep: 1368 x1, y1 = y1, x1 1369 x2, y2 = y2, x2 1370 rev = False 1371 if x1 > x2: 1372 x1, x2 = x2, x1 1373 y1, y2 = y2, y1 1374 rev = True 1375 delta_x = x2 - x1 1376 delta_y = abs(y2 - y1) 1377 error = int(delta_x / 2) 1378 y = y1 1379 y_step = None 1380 1381 if y1 < y2: 1382 y_step = 1 1383 else: 1384 y_step = -1 1385 for x in range(x1, x2 + 1): 1386 if is_steep: 1387 #print y, "~", x 1388 self.set_color(y, x, r, g, b) 1389 points.append((y, x)) 1390 else: 1391 #print x, " ", y 1392 self.set_color(x, y, r, g, b) 1393 points.append((x, y)) 1394 error -= delta_y 1395 if error < 0: 1396 y += y_step 1397 error += delta_x 1398 # Reverse the list if the coordinates were reversed 1399 if rev: 1400 points.reverse() 1401 return points
1402
1403 - def clear(self):
1404 """ 1405 Set all pixels to black in the cached matrix 1406 """ 1407 for y in range(0, self.rows): 1408 for x in range(0, self.cols): 1409 self.set_color(x, y, 0, 0, 0)
1410
1411 - def send_data(self, channel):
1412 """ 1413 Send data stored in the internal buffer to the channel. 1414 1415 @param channel: 1416 - 0 - R pin on BlinkStick Pro board 1417 - 1 - G pin on BlinkStick Pro board 1418 - 2 - B pin on BlinkStick Pro board 1419 """ 1420 1421 start_col = 0 1422 end_col = 0 1423 1424 if channel == 0: 1425 start_col = 0 1426 end_col = self.r_columns 1427 1428 if channel == 1: 1429 start_col = self.r_columns 1430 end_col = start_col + self.g_columns 1431 1432 if channel == 2: 1433 start_col = self.r_columns + self.g_columns 1434 end_col = start_col + self.b_columns 1435 1436 self.data[channel] = [] 1437 1438 #slice the huge array to individual packets 1439 for y in range(0, self.rows): 1440 start = y * self.cols + start_col 1441 end = y * self.cols + end_col 1442 1443 self.data[channel].extend(self.matrix_data[start: end]) 1444 1445 super(BlinkStickProMatrix, self).send_data(channel)
1446
1447 -def _find_blicksticks(find_all=True):
1448 if sys.platform == "win32": 1449 devices = hid.HidDeviceFilter(vendor_id = VENDOR_ID, product_id = PRODUCT_ID).get_devices() 1450 if find_all: 1451 return devices 1452 elif len(devices) > 0: 1453 return devices[0] 1454 else: 1455 return None 1456 1457 else: 1458 return usb.core.find(find_all=find_all, idVendor=VENDOR_ID, idProduct=PRODUCT_ID)
1459 1460
1461 -def find_all():
1462 """ 1463 Find all attached BlinkStick devices. 1464 1465 @rtype: BlinkStick[] 1466 @return: a list of BlinkStick objects or None if no devices found 1467 """ 1468 result = [] 1469 for d in _find_blicksticks(): 1470 result.extend([BlinkStick(device=d)]) 1471 1472 return result
1473 1474
1475 -def find_first():
1476 """ 1477 Find first attached BlinkStick. 1478 1479 @rtype: BlinkStick 1480 @return: BlinkStick object or None if no devices are found 1481 """ 1482 d = _find_blicksticks(find_all=False) 1483 1484 if d: 1485 return BlinkStick(device=d)
1486 1487
1488 -def find_by_serial(serial=None):
1489 """ 1490 Find BlinkStick device based on serial number. 1491 1492 @rtype: BlinkStick 1493 @return: BlinkStick object or None if no devices are found 1494 """ 1495 1496 devices = [] 1497 if sys.platform == "win32": 1498 devices = [d for d in _find_blicksticks() 1499 if d.serial_number == serial] 1500 else: 1501 for d in _find_blicksticks(): 1502 try: 1503 if usb.util.get_string(d, 256, 3) == serial: 1504 devices = [d] 1505 break 1506 except Exception as e: 1507 print "{0}".format(e) 1508 1509 if devices: 1510 return BlinkStick(device=devices[0])
1511 1512
1513 -def _remap(value, leftMin, leftMax, rightMin, rightMax):
1514 # Figure out how 'wide' each range is 1515 leftSpan = leftMax - leftMin 1516 rightSpan = rightMax - rightMin 1517 1518 # Convert the left range into a 0-1 range (float) 1519 valueScaled = float(value - leftMin) / float(leftSpan) 1520 1521 # Convert the 0-1 range into a value in the right range. 1522 return int(rightMin + (valueScaled * rightSpan))
1523
1524 -def _remap_color(value, max_value):
1525 return _remap(value, 0, 255, 0, max_value)
1526
1527 -def _remap_color_reverse(value, max_value):
1528 return _remap(value, 0, max_value, 0, 255)
1529
1530 -def _remap_rgb_value(rgb_val, max_value):
1531 return [_remap_color(rgb_val[0], max_value), 1532 _remap_color(rgb_val[1], max_value), 1533 _remap_color(rgb_val[2], max_value)]
1534
1535 -def _remap_rgb_value_reverse(rgb_val, max_value):
1536 return [_remap_color_reverse(rgb_val[0], max_value), 1537 _remap_color_reverse(rgb_val[1], max_value), 1538 _remap_color_reverse(rgb_val[2], max_value)]
1539
1540 -def get_blinkstick_package_version():
1541 return __version__
1542