# 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) time.sleep(10) # delay so people can get the IP address 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() # pylint: disable=unused-variable 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) # pylint: disable=unused-variable 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") # pylint: disable=unused-variable 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() # pylint: disable=unused-variable 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")