From 78dcb6facb7261d6656946bfc448ef2f7635f81c Mon Sep 17 00:00:00 2001 From: John Park Date: Mon, 22 Jan 2024 10:44:49 -0800 Subject: [PATCH 1/2] first commit wireless osc remote for memento --- MEMENTO/Wireless_Remote/code.py | 290 ++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 MEMENTO/Wireless_Remote/code.py diff --git a/MEMENTO/Wireless_Remote/code.py b/MEMENTO/Wireless_Remote/code.py new file mode 100644 index 000000000..dc646fecb --- /dev/null +++ b/MEMENTO/Wireless_Remote/code.py @@ -0,0 +1,290 @@ +# SPDX-FileCopyrightText: 2023 Jeff Epler & John Park for Adafruit Industries +# +# SPDX-License-Identifier: MIT +''' Wireless remote for MEMENTO camera with TouchOSC''' + +import time +import os +import bitmaptools +import displayio +import gifio +import ulab.numpy as np +import adafruit_pycamera +import wifi +import socketpool +import microosc + +UDP_HOST = "" +UDP_PORT = 8000 +ssid = os.getenv("CIRCUITPY_WIFI_SSID") +password = os.getenv("CIRCUITPY_WIFI_PASSWORD") +print("connecting to WiFi", ssid) +wifi.radio.connect(ssid, password) +print("my ip address:", wifi.radio.ipv4_address) +socket_pool = socketpool.SocketPool(wifi.radio) + +pycam = adafruit_pycamera.PyCamera() +pycam.autofocus_init() + +settings = (None, "resolution", "effect", "mode", "led_level", "led_color") +curr_setting = 0 + +print("Starting!") +last_frame = displayio.Bitmap(pycam.camera.width, pycam.camera.height, 65535) +onionskin = displayio.Bitmap(pycam.camera.width, pycam.camera.height, 65535) + +pycam.tone(800, 0.1) +pycam.tone(1200, 0.05) + +def snap_jpeg(): + pycam.tone(600, 0.1) + try: + pycam.display_message("Snap!", color=0x0000FF) + pycam.capture_jpeg() + pycam.live_preview_mode() + except TypeError as e: + pycam.display_message("Failed", color=0xFF0000) + time.sleep(0.5) + pycam.live_preview_mode() + except RuntimeError as e: + pycam.display_message("Error\nNo SD Card", color=0xFF0000) + time.sleep(0.5) + +def snap_gboy(): + pycam.tone(600, 0.1) + try: + f = pycam.open_next_image("gif") + pycam.display_message("Snap!", color=0x00ff44) + except RuntimeError as e: + pycam.display_message("Error\nNo SD Card", color=0xFF0000) + time.sleep(0.5) + + with gifio.GifWriter( + f, + pycam.camera.width, + pycam.camera.height, + displayio.Colorspace.RGB565_SWAPPED, + dither=True, + ) as g: + g.add_frame(last_frame, 1) + +def snap_gif(): + pycam.tone(600, 0.1) + try: + f = pycam.open_next_image("gif") + except RuntimeError as e: + pycam.display_message("Error\nNo SD Card", color=0xFF0000) + time.sleep(0.5) + i = 0 + ft = [] + pycam._mode_label.text = "RECORDING" # pylint: disable=protected-access + + pycam.display.refresh() + with gifio.GifWriter( + f, + pycam.camera.width, + pycam.camera.height, + displayio.Colorspace.RGB565_SWAPPED, + dither=True, + ) as g: + t00 = t0 = time.monotonic() + while (i < 15) or not pycam.shutter_button.value: + i += 1 + _gifframe = pycam.continuous_capture() + g.add_frame(_gifframe, 0.12) + pycam.blit(_gifframe) + t1 = time.monotonic() + ft.append(1 / (t1 - t0)) + print(end=".") + t0 = t1 + pycam._mode_label.text = "GIF" # pylint: disable=protected-access + print(f"\nfinal size {f.tell()} for {i} frames") + print(f"average framerate {i/(t1-t00)}fps") + print(f"best {max(ft)} worst {min(ft)} std. deviation {np.std(ft)}") + f.close() + pycam.display.refresh() + pycam.tone(1200, 0.15) + +def snap_stop(): + pycam.tone(600, 0.1) + pycam.capture_into_bitmap(last_frame) + pycam.stop_motion_frame += 1 + try: + pycam.display_message("Snap!", color=0x0000FF) + pycam.capture_jpeg() + except TypeError as e: + pycam.display_message("Failed", color=0xFF0000) + time.sleep(0.5) + except RuntimeError as e: + pycam.display_message("Error\nNo SD Card", color=0xFF0000) + time.sleep(0.5) + pycam.live_preview_mode() + +def toggle_handler(msg): + addr = msg.addr + tog_num = int(addr.replace('/1/toggle','')) + if msg.args[0] == 1.0: + print(tog_num, "is ON") + else: + print(tog_num, "is off") + +def fader_handler(msg): # faders + """Used to handle 'fader' OscMsgs, printing it as a '*' text progress bar + :param OscMsg msg: message with one required float32 value + """ + osc_addr = msg.addr.split('/') # chop up the address into parts + # page_num = osc_addr[1] + fader_num = int(osc_addr[2].replace('fader', '')) # get the number only + if fader_num == 1: # led level + led_val = int(msg.args[0] * 5) + pycam.led_level = led_val + +mode_texts = ("JPEG", "GIF", "GBOY", "STOP") + +def radio_handler(msg): # Radio buttons + osc_addr = msg.addr.split('/') # chop up the address into parts + print(osc_addr) + page_num = osc_addr[1] + print("page_num:", page_num) + rad_num = int(osc_addr[2].replace('radio', '')) # get the number only + print("rad_num:", rad_num) + if rad_num == 1: # MODE + print("switched mode to", mode_texts[msg.args[0]]) + pycam.mode = msg.args[0] + if rad_num == 2: # resolution + print("switched resolution") + pycam.resolution = msg.args[0] + if rad_num == 3: # LED color + print("set color") + pycam.led_color = msg.args[0] + if rad_num == 4: # effects + print("switched effect") + pycam.effect = msg.args[0] + +def button_handler(msg): # buttons + addr = msg.addr + button_num = int(addr.replace('/1/button','')) + if msg.args[0] == 1.0: + print(button_num, "is ON") + if button_num == 1: + pycam.tone(1200, 0.05) + pycam.tone(1600, 0.05) + if pycam.mode_text == "JPEG": + snap_jpeg() + if pycam.mode_text == "GBOY": + snap_gboy() + if pycam.mode_text == "GIF": + snap_gif() + if pycam.mode_text == "STOP": + snap_stop() + + if button_num == 2: # focus + pycam.tone(1800, 0.05) + print("FOCUS") + print(pycam.autofocus_status) + pycam.autofocus() + print(pycam.autofocus_status) + pycam.tone(1400, 0.05) + + else: + print(button_num, "is off") + +dispatch_map = { + "/": lambda msg: print("msg:", msg.addr, msg.args), # prints all messages + "/1/fader": fader_handler, + "/2/fader": fader_handler, + "/1/toggle": toggle_handler, + "/1/button": button_handler, + "/1/radio": radio_handler, + "/2/radio": radio_handler +} + +osc_server = microosc.OSCServer(socket_pool, UDP_HOST, UDP_PORT, dispatch_map) +print("MicroOSC server started on ", UDP_HOST, UDP_PORT) + + +while True: + osc_server.poll() # check for incoming OSC messages + + if pycam.mode_text == "STOP" and pycam.stop_motion_frame != 0: + # alpha blend + new_frame = pycam.continuous_capture() + bitmaptools.alphablend( + onionskin, last_frame, new_frame, displayio.Colorspace.RGB565_SWAPPED + ) + pycam.blit(onionskin) + elif pycam.mode_text == "GBOY": + bitmaptools.dither( + last_frame, pycam.continuous_capture(), displayio.Colorspace.RGB565_SWAPPED + ) + pycam.blit(last_frame) + else: + pycam.blit(pycam.continuous_capture()) + + pycam.keys_debounce() + + if pycam.shutter.long_press: + print("FOCUS") + print(pycam.autofocus_status) + pycam.autofocus() + print(pycam.autofocus_status) + + if pycam.shutter.short_count: + print("Shutter released") + if pycam.mode_text == "STOP": + snap_stop() + + if pycam.mode_text == "GBOY": + snap_gboy() + + if pycam.mode_text == "GIF": + snap_gif() + + if pycam.mode_text == "JPEG": + snap_jpeg() + + if pycam.card_detect.fell: + print("SD card removed") + pycam.unmount_sd_card() + pycam.display.refresh() + if pycam.card_detect.rose: + print("SD card inserted") + pycam.display_message("Mounting\nSD Card", color=0xFFFFFF) + for _ in range(3): + try: + print("Mounting card") + pycam.mount_sd_card() + print("Success!") + break + except OSError as e: + print("Retrying!", e) + time.sleep(0.5) + else: + pycam.display_message("SD Card\nFailed!", color=0xFF0000) + time.sleep(0.5) + pycam.display.refresh() + + if pycam.up.fell: + print("UP") + key = settings[curr_setting] + if key: + setattr(pycam, key, getattr(pycam, key) + 1) + if pycam.down.fell: + print("DN") + key = settings[curr_setting] + if key: + setattr(pycam, key, getattr(pycam, key) - 1) + if pycam.left.fell: + print("LF") + curr_setting = (curr_setting + 1) % len(settings) + print(settings[curr_setting]) + pycam.select_setting(settings[curr_setting]) + if pycam.right.fell: + print("RT") + curr_setting = (curr_setting - 1 + len(settings)) % len(settings) + print(settings[curr_setting]) + pycam.select_setting(settings[curr_setting]) + if pycam.select.fell: + print("SEL") + if pycam.ok.fell: + print("OK") From 956adc1a6ca6095d5ccfbed112e870796aa54a0e Mon Sep 17 00:00:00 2001 From: John Park Date: Mon, 22 Jan 2024 11:06:29 -0800 Subject: [PATCH 2/2] fixed unused 'e' error variables --- MEMENTO/Wireless_Remote/code.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MEMENTO/Wireless_Remote/code.py b/MEMENTO/Wireless_Remote/code.py index dc646fecb..a0750006a 100644 --- a/MEMENTO/Wireless_Remote/code.py +++ b/MEMENTO/Wireless_Remote/code.py @@ -42,6 +42,7 @@ def snap_jpeg(): pycam.display_message("Snap!", color=0x0000FF) pycam.capture_jpeg() pycam.live_preview_mode() + # pylint: disable=unused-variable except TypeError as e: pycam.display_message("Failed", color=0xFF0000) time.sleep(0.5) @@ -55,6 +56,7 @@ def snap_gboy(): try: f = pycam.open_next_image("gif") pycam.display_message("Snap!", color=0x00ff44) + # pylint: disable=unused-variable except RuntimeError as e: pycam.display_message("Error\nNo SD Card", color=0xFF0000) time.sleep(0.5) @@ -72,6 +74,7 @@ def snap_gif(): pycam.tone(600, 0.1) try: f = pycam.open_next_image("gif") + # pylint: disable=unused-variable except RuntimeError as e: pycam.display_message("Error\nNo SD Card", color=0xFF0000) time.sleep(0.5) @@ -112,6 +115,7 @@ def snap_stop(): try: pycam.display_message("Snap!", color=0x0000FF) pycam.capture_jpeg() + # pylint: disable=unused-variable except TypeError as e: pycam.display_message("Failed", color=0xFF0000) time.sleep(0.5)