class Bulb(object): def __init__(self, ip, mac, multizone=False): self.rapid = False if multizone: self.bulb = MultiZoneLight(mac, ip) else: self.bulb = Light(mac, ip) def supports_multizone(self): return self.bulb.supports_multizone() def get_color_zones(self): return self.bulb.get_color_zones() def set_zone_color(self, startZone, endZone, color, duration=5): return self.bulb.set_zone_color(startZone, endZone, color, duration=duration, rapid=self.rapid) def set_zone_colors(self, colors, duration=5): return self.bulb.set_zone_colors(colors, duration=duration, rapid=self.rapid) def set_power(self, power, duration=5): if duration: self.bulb.set_power(power, duration=duration, rapid=self.rapid) else: self.bulb.set_power(power) def get_power(self): return self.bulb.get_power() def set_color(self, color, duration=5): if duration: self.bulb.set_color(color, duration=duration, rapid=self.rapid) else: self.bulb.set_color(color) def get_color(self): return self.bulb.get_color() def get_label(self): return self.bulb.get_label() def get_brightness(self): return self.bulb.get_color()[2] def set_brightness(self, brightness, duration=5): return self.bulb.set_brightness(brightness, duration, rapid=self.rapid) def fast_mode(self, hostIP=None): self.rapid = True def slow_mode(self): self.rapid = False
def main(): bulb = Light("d0:73:d5:28:0b:4a", "10.0.0.16") print("Selected {}".format(bulb.get_label())) # get original state original_power = bulb.get_power() original_color = bulb.get_color() bulb.set_power("on") sleep(0.2) # to look pretty print("Toggling power...") toggle_device_power(bulb, 0.2) print("Toggling color...") toggle_light_color(bulb, 0.2) # restore original color # color can be restored after the power is turned off as well print("Restoring original color and power...") bulb.set_color(original_color) sleep(1) # to look pretty. # restore original power bulb.set_power(original_power)
def _update_light(light: Light, midi_message: MidiMessage): # TODO: Probably need to fiddle with these and see what happens. They could become parameters. MIN_BRIGHTNESS = 500 # 0 - 65535 BRIGHTNESS_INCREASE_SPEED = 100 # 0-? BRIGHTNESS_DROP_SPEED = 200 # 0-? in ms, so 1000 is 1s velocity = midi_message.getVelocity() mapped_velocity = _map_value_to_range(value=velocity, from_min=MIDI_VALUE_MIN, from_max=MIDI_VALUE_MAX, to_min=LIFX_VALUE_MIN, to_max=LIFX_VALUE_MAX) ######## # TODO: We should try some different stuff here, but I'm making something up that I think will be interesting? ######## # Set the color to w/e the velocity is. This could be really erratic, so maybe add duration # which transitions to the given color over the # of ms. Just not sure if it blocks execution. light.set_hue(hue=mapped_velocity, rapid=True) # Push the brightness up by some function of the velocity. Will need to mess with this. def _new_brightness(current_brightness: int): return current_brightness + BRIGHTNESS_INCREASE_SPEED light.set_brightness(brightness=_new_brightness(current_brightness=light.get_color()[2]), rapid=True) # Then start to lower the brightness to some min level slowly light.set_brightness(brightness=MIN_BRIGHTNESS, duration=BRIGHTNESS_DROP_SPEED, rapid=True)
def state(self, device): bulbRef = Light(device['mac'], device['ip']) hsbk = bulbRef.get_color() dev = Device(device['mac'], device['ip'], bulbRef.get_power(), hsbk[0], hsbk[1], hsbk[2], hsbk[3]) return json.dumps(dev.__dict__)
def light_to_dict(light: Light): return { 'name': light.get_label(), 'power': bool(light.get_power()), 'color': light.get_color(), 'macAddress': light.get_mac_addr() }
def blink_light(mac, ip): """ Run a rapid blink on a light to provide a notification. """ light = Light(mac, ip) colors = light.get_color() power_state = light.get_power() repeats = 3 delay = 0.25 light.set_power(1) for _ in range(repeats): light.set_color(RED, rapid=True) sleep(delay) light.set_color(GREEN, rapid=True) sleep(delay) light.set_color(BLUE, rapid=True) sleep(delay) if power_state: light.set_color(colors) else: light.set_color(COLD_WHITE) sleep(1) light.set_color(colors) light.set_power(power_state)
def toggle_light_color(light: lifxlan.Light, interval=0.5, num_cycles=3): original_color = light.get_color() rapid = True if interval < 1 else False for i in range(num_cycles): light.set_color(lifxlan.BLUE, rapid=rapid) sleep(interval) light.set_color(lifxlan.GREEN, rapid=rapid) sleep(interval) light.set_color(original_color)
async def get_light_color(name: str, light: lifx.Light): try: return ( name, light.get_color(), ) except lifx.WorkflowException as e: logging.exception("Failed to communicate with lights") return ( name, None, )
def set_brightness(self, br): br = br * 65535 try: for x in self.lifx_lights: mac, ip = x[0], x[1] light = Light(mac, ip) current_hue, current_sat, current_br, current_ke = light.get_color( ) light.set_color([current_hue, current_sat, br, current_ke], duration=.1 * 1000, rapid=False) except Exception as e: print(e)
async def set_light_color(name: str, light: lifx.Light, new_color: dict): try: orig_color = light.get_color() color = list(orig_color) for i, param in enumerate(["hue", "saturation", "brightness", "kelvin"]): if param in new_color: color[i] = new_color[param] if tuple(color) != orig_color: light.set_color(color, 500) return ( name, color, ) except lifx.WorkflowException as e: logging.exception("Failed to communicate with lights") return ( name, None, )
def set_lights(self, postvars={}): sched.pause() resp = 'no post data found' l = None if any(postvars): resp = 'vars!' mac = postvars.get('mac', None) if mac: ip = postvars.get('ip', None) if ip: l = Light(mac[0], ip[0]) light = postvars.get('light', None) if light: logging.debug(light) if light[0] in LIGHTS: logging.debug('found {}'.format(light[0])) light = LIGHTS.get(light[0]) mac = light.get('mac') ip = light.get('ip') colour = light.get('colour') l = Light(mac, ip) else: logging.debug(LIGHTS) l = self.devices.get_device_by_name(light[0]) if l: colour = l.get_color() if l: level = postvars.get('level', None) dim = postvars.get('dim', None) white = postvars.get('white', None) if level is not None: try: if (level[0] == 'full'): h, s, b, k = colour b = 65535 l.set_power('on') l.set_color([h, s, b, k], 300) else: l.set_power(level[0]) resp = 'set power {}'.format(level) except Exception as e: resp = 'err... {}'.format(repr(e)) elif dim is not None: switch_after_dim = False try: h, s, b, k = colour if l.get_power() == 0: switch_after_dim = True b = 0 dim = dim[0] if dim not in ('up', 'down'): dim = LIGHTS[l.get_label()].get('last_dim', None) if dim is None or b in (0, 65535): if b > 32000: dim = 'down' else: dim = 'up' if dim == 'down': b -= 6554 if dim == 'up': b += 6554 if b < 0: b = 0 if b > 65535: b = 65535 l.set_color([h, s, b, k], 600) if LIGHTS.get(l.get_label(), None) is None: LIGHTS[l.get_label()] = {'mac': l.get_mac_addr(), 'ip': l.get_ip_addr(), 'colour': l.get_color(), 'last_dim': dim} else: LIGHTS[l.get_label()]['colour'] = [h, s, b, k] LIGHTS[l.get_label()]['last_dim'] = dim if switch_after_dim is True: l.set_power('on') resp = 'set brightness {}'.format(b) except Exception as e: resp = 'dim... {}'.format(repr(e)) elif white is not None: try: h, s, b, k = colour white = white[0] if white not in ('warm', 'cool'): k = int(white) if white == 'warm': k -= 500 if white == 'cool': k += 500 if k < 2500: k = 2500 if k > 9000: k = 9000 l.set_color([h, s, b, k], 500) if LIGHTS.get(l.get_label(), None) is None: LIGHTS[l.get_label()] = {'mac': l.get_mac_addr(), 'ip': l.get_ip_addr(), 'colour': l.get_color()} else: LIGHTS[l.get_label()]['colour'] = [h, s, b, k] resp = 'set white level {}'.format(k) except Exception as e: resp = 'white... {}'.format(repr(e)) else: try: if l.get_power() > 0: l.set_power(0) else: l.set_power('on') except: resp = 'nope...' else: resp = "<p>Light not found ):</p>" sched.resume() return resp
# Scaling line_length to 0-255 for display saturation = scaleValue(line_length, 0, 255, 300, 0) cv2.putText(image, 'Saturation: {}'.format(saturation), (yellowCenter[0] - 60, yellowCenter[1] - 60), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2) # Scaling line_length to 0-65535 for LIFX saturation = scaleValue(line_length, 0, 65535, 300, 0) prev_saturation = max( saturation_lineDeque ) if saturation_lineDeque.__len__() > 0 else 0 saturation_lineDeque.append(saturation) current_saturation = max(saturation_lineDeque) current_saturation = current_saturation if current_saturation < 65535 else 65535 if math.fabs(current_saturation - prev_saturation) > 10: light_color = light.get_color() new_light_color = (light_color[0], current_saturation, light_color[2], light_color[3]) light.set_color(new_light_color, rapid=True) hue_angle = int( math.atan2(greenCenter[1] - yellowCenter[1], greenCenter[0] - yellowCenter[0]) * -180 / math.pi + 180) prev_hue_angle = max( hue_angleDeque) if hue_angleDeque.__len__() > 0 else 0 hue_angleDeque.append(hue_angle) current_hue_angle = max(hue_angleDeque) if math.fabs(current_hue_angle - prev_hue_angle) > 1: light_color = light.get_color()
class LifxController: def __init__(self, bulb_mac=None, bulb_ip=None): logging.debug("Initialising LifxController.") self.lan = LifxLAN() self.bulbs = None self.groups = None self.bulb_labels: list = [] self.group_labels: list = [] self.bulb = None self.group = None self.bulb_mac = bulb_mac self.bulb_ip = bulb_ip # Logger config self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.DEBUG) self.ch = logging.StreamHandler() self.ch.setLevel(logging.DEBUG) self.formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s') self.ch.setFormatter(self.formatter) self.logger.addHandler(self.ch) # When loading config, we don't need to discover the bulb if self.bulb_mac and self.bulb_ip: from lifxlan import Light self.bulb = Light(self.bulb_mac, self.bulb_ip) def discover_bulbs(self): """ Discovers individual bulbs, then groups """ logging.debug("discover_bulbs: Discovering individual bulbs.") # Discover bulbs on the LAN self.bulbs = self.lan.get_devices() logging.debug( f"discover_bulbs: Discovery complete. {len(self.lan.devices)} bulbs found." ) for bulb in self.bulbs: # Build a list of bulb names bulb_name = bulb.get_label() if bulb_name not in self.bulb_labels: self.bulb_labels.append(bulb_name) # Figure out what groups exist from their group_labels # There is no way to simply discover what groups are available group = bulb.get_group_label() if group: if group not in self.group_labels: self.group_labels.append(group) def select_target(self): """ Creates menu to select target bulb or group. """ title = "Would you like to target a single bulb, or groups of bulbs?" options = ["Single", "Group"] _, selection = pick(options, title) print(type(selection), selection) if selection == 0: logging.debug("User is going to target a single bulb.") title = "Select the bulb to target" _, selection = pick(self.bulb_labels, title) self.bulb = self.bulbs[selection] elif selection == 1: logging.debug("User is going to target a group of bulbs.") title = "Select the target group" _, selection = pick(self.group_labels, title) self.group = self.groups[selection] def get_colour(self): """ Obtains the current colour of the bulb. """ if self.bulb: return self.bulb.get_color() elif self.group: return self.group.get_color() def set_colour(self, colour): """ Sets colour of selected bulb to input. Input is HSBK format, which seems to be specific to LifX and really poorly documented at the time of this comment. https://api.developer.lifx.com/docs/colors input: list """ if self.bulb: return self.bulb.set_color(colour) if self.group: return self.group.set_color(colour) def get_config(self): """ Returns bulb config, to save for later. return: dict """ if self.bulb: bulb_config: dict = { "mac_addr": self.bulb.get_mac_addr(), "ip_addr": self.bulb.get_ip_addr(), "label": self.bulb.get_label() } return bulb_config else: logging.debug("get_config: Returning group config")