From 803cd039f3b93398591713f15e2d9bb66afddb35 Mon Sep 17 00:00:00 2001 From: Kattni Date: Mon, 19 Feb 2018 17:21:32 -0500 Subject: [PATCH] Files for Ikea lamp hacking guide --- Hacking_Ikea_Lamps_With_CPX/CPX_Blink.py | 6 + .../CPX_Blink_Monotonic.py | 13 ++ .../CPX_Blink_NeoPixel.py | 6 + .../CPX_Left_Rotation_State_Machine.py | 37 ++++++ .../CPX_Sjopenna_Remote_Lamp.py | 53 ++++++++ .../CPX_Spoka_Generators.py | 70 ++++++++++ .../CPX_Spoka_Motion_Lamp.py | 122 ++++++++++++++++++ .../CPX_Touch_NeoPixel_Dictionary.py | 16 +++ .../CPX_Touch_NeoPixel_if_elif.py | 17 +++ 9 files changed, 340 insertions(+) create mode 100644 Hacking_Ikea_Lamps_With_CPX/CPX_Blink.py create mode 100644 Hacking_Ikea_Lamps_With_CPX/CPX_Blink_Monotonic.py create mode 100644 Hacking_Ikea_Lamps_With_CPX/CPX_Blink_NeoPixel.py create mode 100644 Hacking_Ikea_Lamps_With_CPX/CPX_Left_Rotation_State_Machine.py create mode 100644 Hacking_Ikea_Lamps_With_CPX/CPX_Sjopenna_Remote_Lamp.py create mode 100644 Hacking_Ikea_Lamps_With_CPX/CPX_Spoka_Generators.py create mode 100755 Hacking_Ikea_Lamps_With_CPX/CPX_Spoka_Motion_Lamp.py create mode 100644 Hacking_Ikea_Lamps_With_CPX/CPX_Touch_NeoPixel_Dictionary.py create mode 100644 Hacking_Ikea_Lamps_With_CPX/CPX_Touch_NeoPixel_if_elif.py diff --git a/Hacking_Ikea_Lamps_With_CPX/CPX_Blink.py b/Hacking_Ikea_Lamps_With_CPX/CPX_Blink.py new file mode 100644 index 000000000..e91362733 --- /dev/null +++ b/Hacking_Ikea_Lamps_With_CPX/CPX_Blink.py @@ -0,0 +1,6 @@ +import time +from adafruit_circuitplayground.express import cpx + +while True: + cpx.red_led = not cpx.red_led + time.sleep(0.5) \ No newline at end of file diff --git a/Hacking_Ikea_Lamps_With_CPX/CPX_Blink_Monotonic.py b/Hacking_Ikea_Lamps_With_CPX/CPX_Blink_Monotonic.py new file mode 100644 index 000000000..959462a38 --- /dev/null +++ b/Hacking_Ikea_Lamps_With_CPX/CPX_Blink_Monotonic.py @@ -0,0 +1,13 @@ +import time +from adafruit_circuitplayground.express import cpx + +blink_speed = 0.5 + +cpx.pixels[0] = (0, 0, 0) + +initial_time = time.monotonic() +while True: + current_time = time.monotonic() + if current_time - initial_time > blink_speed: + initial_time = current_time + cpx.pixels[0] = (abs(cpx.pixels[0][0] - 255), 0, 0) \ No newline at end of file diff --git a/Hacking_Ikea_Lamps_With_CPX/CPX_Blink_NeoPixel.py b/Hacking_Ikea_Lamps_With_CPX/CPX_Blink_NeoPixel.py new file mode 100644 index 000000000..ab6b7941b --- /dev/null +++ b/Hacking_Ikea_Lamps_With_CPX/CPX_Blink_NeoPixel.py @@ -0,0 +1,6 @@ +import time +from adafruit_circuitplayground.express import cpx + +while True: + cpx.pixels[0] = (abs(cpx.pixels[0][0] - 255), 0, 0) + time.sleep(0.5) diff --git a/Hacking_Ikea_Lamps_With_CPX/CPX_Left_Rotation_State_Machine.py b/Hacking_Ikea_Lamps_With_CPX/CPX_Left_Rotation_State_Machine.py new file mode 100644 index 000000000..4ba507458 --- /dev/null +++ b/Hacking_Ikea_Lamps_With_CPX/CPX_Left_Rotation_State_Machine.py @@ -0,0 +1,37 @@ +import time +from adafruit_circuitplayground.express import cpx + + +# pylint: disable=redefined-outer-name +def upright(x, y, z): + return abs(x) < accel_threshold and abs(y) < accel_threshold and abs(9.8 - z) < accel_threshold + + +def left_side(x, y, z): + return abs(9.8 - x) < accel_threshold and abs(y) < accel_threshold and abs(z) < accel_threshold +# pylint: enable=redefined-outer-name + + +state = None +hold_end = None + +accel_threshold = 2 +hold_time = 1 + +while True: + x, y, z = cpx.acceleration + if left_side(x, y, z): + if state is None or not state.startswith("left"): + hold_end = time.monotonic() + hold_time + state = "left" + print("Entering state 'left'") + elif (state == "left" + and hold_end is not None + and time.monotonic() >= hold_end): + state = "left-done" + print("Entering state 'left-done'") + elif upright(x, y, z): + if state != "upright": + hold_end = None + state = "upright" + print("Entering state 'upright'") diff --git a/Hacking_Ikea_Lamps_With_CPX/CPX_Sjopenna_Remote_Lamp.py b/Hacking_Ikea_Lamps_With_CPX/CPX_Sjopenna_Remote_Lamp.py new file mode 100644 index 000000000..1e9723acd --- /dev/null +++ b/Hacking_Ikea_Lamps_With_CPX/CPX_Sjopenna_Remote_Lamp.py @@ -0,0 +1,53 @@ +import adafruit_irremote +import board +import neopixel +import pulseio + +pixels = neopixel.NeoPixel(board.NEOPIXEL, 10) + +pulsein = pulseio.PulseIn(board.REMOTEIN, maxlen=120, idle_state=True) +decoder = adafruit_irremote.GenericDecode() + +last_command = None + +brightness_up = 95 # Up arrow +brightness_down = 79 # Down arrow + +command_to_color = { # button = color + 247: (255, 0, 0), # 1 = red + 119: (255, 40, 0), # 2 = orange + 183: (255, 150, 0), # 3 = yellow + 215: (0, 255, 0), # 4 = green + 87: (0, 255, 120), # 5 = teal + 151: (0, 255, 255), # 6 = cyan + 231: (0, 0, 255), # 7 = blue + 103: (180, 0, 255), # 8 = purple + 167: (255, 0, 20), # 9 = magenta + 207: (255, 255, 255), # 0 = white + 127: (0, 0, 0), # Play/Pause = off +} + +while True: + pulses = decoder.read_pulses(pulsein, max_pulse=5000) + command = None + try: + code = decoder.decode_bits(pulses) + if len(code) > 3: + command = code[2] + print("Decoded:", command) + print("-------------") + except adafruit_irremote.IRNECRepeatException: # Catches the repeat signal + command = last_command + except adafruit_irremote.IRDecodeException: # Failed to decode + pass + + if not command: + continue + last_command = command + + if command == brightness_up: + pixels.brightness += 0.1 + elif command == brightness_down: + pixels.brightness -= 0.1 + elif command in command_to_color: + pixels.fill(command_to_color[command]) diff --git a/Hacking_Ikea_Lamps_With_CPX/CPX_Spoka_Generators.py b/Hacking_Ikea_Lamps_With_CPX/CPX_Spoka_Generators.py new file mode 100644 index 000000000..897aebd38 --- /dev/null +++ b/Hacking_Ikea_Lamps_With_CPX/CPX_Spoka_Generators.py @@ -0,0 +1,70 @@ +import time +from adafruit_circuitplayground.express import cpx + + +def wheel(pos): + # Input a value 0 to 255 to get a color value. + # The colours are a transition r - g - b - back to r. + if pos < 0 or pos > 255: + return 0, 0, 0 + if pos < 85: + return int(255 - pos*3), int(pos*3), 0 + if pos < 170: + pos -= 85 + return 0, int(255 - pos*3), int(pos*3) + pos -= 170 + return int(pos * 3), 0, int(255 - (pos*3)) + + +def cycle_sequence(seq): + while True: + for elem in seq: + yield elem + + +def rainbow_lamp(seq): + g = cycle_sequence(seq) + while True: + # pylint: disable=stop-iteration-return + cpx.pixels.fill(wheel(next(g))) + yield + + +color_sequences = cycle_sequence([ + range(256), # rainbow_cycle + [0], # red + [10], # orange + [30], # yellow + [85], # green + [137], # cyan + [170], # blue + [213], # purple + [0, 10, 30, 85, 137, 170, 213], # party mode +]) + +heart_rates = cycle_sequence([0, 0.5, 1.0]) + +heart_rate = 0 +last_heart_beat = time.monotonic() +next_heart_beat = last_heart_beat + heart_rate + +rainbow = None + +cpx.detect_taps = 2 +cpx.pixels.brightness = 0.2 + +while True: + now = time.monotonic() + + if cpx.tapped or rainbow is None: + rainbow = rainbow_lamp(next(color_sequences)) + + if cpx.shake(shake_threshold=20): + heart_rate = next(heart_rates) + last_heart_beat = now + next_heart_beat = last_heart_beat + heart_rate + + if now >= next_heart_beat: + next(rainbow) + last_heart_beat = now + next_heart_beat = last_heart_beat + heart_rate diff --git a/Hacking_Ikea_Lamps_With_CPX/CPX_Spoka_Motion_Lamp.py b/Hacking_Ikea_Lamps_With_CPX/CPX_Spoka_Motion_Lamp.py new file mode 100755 index 000000000..1b335192e --- /dev/null +++ b/Hacking_Ikea_Lamps_With_CPX/CPX_Spoka_Motion_Lamp.py @@ -0,0 +1,122 @@ +import time +from adafruit_circuitplayground.express import cpx + + +def wheel(pos): + # Input a value 0 to 255 to get a color value. + # The colours are a transition r - g - b - back to r. + if pos < 0 or pos > 255: + return 0, 0, 0 + if pos < 85: + return int(255 - pos*3), int(pos*3), 0 + if pos < 170: + pos -= 85 + return 0, int(255 - pos*3), int(pos*3) + pos -= 170 + return int(pos * 3), 0, int(255 - (pos*3)) + + +# pylint: disable=redefined-outer-name +def upright(x, y, z): + return abs(x) < accel_threshold and abs(y) < accel_threshold and abs(9.8 - z) < accel_threshold + + +def right_side(x, y, z): + return abs(-9.8 - x) < accel_threshold and abs(y) < accel_threshold and abs(z) < accel_threshold + + +def left_side(x, y, z): + return abs(9.8 - x) < accel_threshold and abs(y) < accel_threshold and abs(z) < accel_threshold +# pylint: enable=redefined-outer-name + + +def cycle_sequence(seq): + while True: + for elem in seq: + yield elem + + +def rainbow_lamp(seq): + g = cycle_sequence(seq) + while True: + # pylint: disable=stop-iteration-return + cpx.pixels.fill(wheel(next(g))) + yield + + +def brightness_lamp(): + brightness_value = cycle_sequence([0.4, 0.6, 0.8, 1, 0.2]) + while True: + # pylint: disable=stop-iteration-return + cpx.pixels.brightness = next(brightness_value) + yield + + +color_sequences = cycle_sequence([ + range(256), # rainbow_cycle + [0], # red + [10], # orange + [30], # yellow + [85], # green + [137], # cyan + [170], # blue + [213], # purple + [0, 10, 30, 85, 137, 170, 213], # party mode +]) + +heart_rates = cycle_sequence([0, 0.5, 1.0]) + +brightness = brightness_lamp() + +heart_rate = 0 +last_heart_beat = time.monotonic() +next_heart_beat = last_heart_beat + heart_rate + +rainbow = None +state = None +hold_end = None + +cpx.detect_taps = 2 +accel_threshold = 2 +cpx.pixels.brightness = 0.2 +hold_time = 1 + +while True: + now = time.monotonic() + x, y, z = cpx.acceleration + + if left_side(x, y, z): + if state is None or not state.startswith("left"): + hold_end = now + hold_time + state = "left" + elif (state == "left" + and hold_end is not None + and now >= hold_end): + state = "left-done" + next(brightness) + elif right_side(x, y, z): + if state is None or not state.startswith("right"): + hold_end = now + hold_time + state = "right" + elif (state == "right" + and hold_end is not None + and now >= hold_end): + state = "right-done" + heart_rate = next(heart_rates) + last_heart_beat = now + next_heart_beat = last_heart_beat + heart_rate + elif upright(x, y, z): + if state != "upright": + hold_end = None + state = "upright" + + if cpx.tapped or rainbow is None: + rainbow = rainbow_lamp(next(color_sequences)) + + if now >= next_heart_beat: + next(rainbow) + last_heart_beat = now + next_heart_beat = last_heart_beat + heart_rate + + if cpx.shake(shake_threshold=20): + cpx.pixels.brightness = 0 diff --git a/Hacking_Ikea_Lamps_With_CPX/CPX_Touch_NeoPixel_Dictionary.py b/Hacking_Ikea_Lamps_With_CPX/CPX_Touch_NeoPixel_Dictionary.py new file mode 100644 index 000000000..acbd3ab31 --- /dev/null +++ b/Hacking_Ikea_Lamps_With_CPX/CPX_Touch_NeoPixel_Dictionary.py @@ -0,0 +1,16 @@ +from adafruit_circuitplayground.express import cpx + +touchpad_to_color = { + "touch_A1": (255, 0, 0), # red + "touch_A2": (255, 40, 0), # orange + "touch_A3": (255, 150, 0), # yellow + "touch_A4": (0, 255, 0), # green + "touch_A5": (0, 0, 255), # blue + "touch_A6": (180, 0, 255), # purple + "touch_A7": (0, 0, 0), # off +} + +while True: + for touchpad in touchpad_to_color: + if getattr(cpx, touchpad): + cpx.pixels.fill(touchpad_to_color[touchpad]) diff --git a/Hacking_Ikea_Lamps_With_CPX/CPX_Touch_NeoPixel_if_elif.py b/Hacking_Ikea_Lamps_With_CPX/CPX_Touch_NeoPixel_if_elif.py new file mode 100644 index 000000000..32513ddfc --- /dev/null +++ b/Hacking_Ikea_Lamps_With_CPX/CPX_Touch_NeoPixel_if_elif.py @@ -0,0 +1,17 @@ +from adafruit_circuitplayground.express import cpx + +while True: + if cpx.touch_A1: + cpx.pixels.fill((255, 0, 0)) # red + elif cpx.touch_A2: + cpx.pixels.fill((255, 40, 0)) # orange + elif cpx.touch_A3: + cpx.pixels.fill((255, 150, 0)) # yellow + elif cpx.touch_A4: + cpx.pixels.fill((0, 255, 0)) # green + elif cpx.touch_A5: + cpx.pixels.fill((0, 0, 255)) # blue + elif cpx.touch_A6: + cpx.pixels.fill((180, 0, 255)) # purple + elif cpx.touch_A7: + cpx.pixels.fill((0, 0, 0)) # off