Skip to content

Commit f08869e

Browse files
authored
Merge pull request #2716 from jedgarpark/memento-remote
first commit wireless osc remote for memento
2 parents 4033e68 + 956adc1 commit f08869e

File tree

1 file changed

+294
-0
lines changed

1 file changed

+294
-0
lines changed

MEMENTO/Wireless_Remote/code.py

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
# SPDX-FileCopyrightText: 2023 Jeff Epler & John Park for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
''' Wireless remote for MEMENTO camera with TouchOSC'''
5+
6+
import time
7+
import os
8+
import bitmaptools
9+
import displayio
10+
import gifio
11+
import ulab.numpy as np
12+
import adafruit_pycamera
13+
import wifi
14+
import socketpool
15+
import microosc
16+
17+
UDP_HOST = ""
18+
UDP_PORT = 8000
19+
ssid = os.getenv("CIRCUITPY_WIFI_SSID")
20+
password = os.getenv("CIRCUITPY_WIFI_PASSWORD")
21+
print("connecting to WiFi", ssid)
22+
wifi.radio.connect(ssid, password)
23+
print("my ip address:", wifi.radio.ipv4_address)
24+
socket_pool = socketpool.SocketPool(wifi.radio)
25+
26+
pycam = adafruit_pycamera.PyCamera()
27+
pycam.autofocus_init()
28+
29+
settings = (None, "resolution", "effect", "mode", "led_level", "led_color")
30+
curr_setting = 0
31+
32+
print("Starting!")
33+
last_frame = displayio.Bitmap(pycam.camera.width, pycam.camera.height, 65535)
34+
onionskin = displayio.Bitmap(pycam.camera.width, pycam.camera.height, 65535)
35+
36+
pycam.tone(800, 0.1)
37+
pycam.tone(1200, 0.05)
38+
39+
def snap_jpeg():
40+
pycam.tone(600, 0.1)
41+
try:
42+
pycam.display_message("Snap!", color=0x0000FF)
43+
pycam.capture_jpeg()
44+
pycam.live_preview_mode()
45+
# pylint: disable=unused-variable
46+
except TypeError as e:
47+
pycam.display_message("Failed", color=0xFF0000)
48+
time.sleep(0.5)
49+
pycam.live_preview_mode()
50+
except RuntimeError as e:
51+
pycam.display_message("Error\nNo SD Card", color=0xFF0000)
52+
time.sleep(0.5)
53+
54+
def snap_gboy():
55+
pycam.tone(600, 0.1)
56+
try:
57+
f = pycam.open_next_image("gif")
58+
pycam.display_message("Snap!", color=0x00ff44)
59+
# pylint: disable=unused-variable
60+
except RuntimeError as e:
61+
pycam.display_message("Error\nNo SD Card", color=0xFF0000)
62+
time.sleep(0.5)
63+
64+
with gifio.GifWriter(
65+
f,
66+
pycam.camera.width,
67+
pycam.camera.height,
68+
displayio.Colorspace.RGB565_SWAPPED,
69+
dither=True,
70+
) as g:
71+
g.add_frame(last_frame, 1)
72+
73+
def snap_gif():
74+
pycam.tone(600, 0.1)
75+
try:
76+
f = pycam.open_next_image("gif")
77+
# pylint: disable=unused-variable
78+
except RuntimeError as e:
79+
pycam.display_message("Error\nNo SD Card", color=0xFF0000)
80+
time.sleep(0.5)
81+
i = 0
82+
ft = []
83+
pycam._mode_label.text = "RECORDING" # pylint: disable=protected-access
84+
85+
pycam.display.refresh()
86+
with gifio.GifWriter(
87+
f,
88+
pycam.camera.width,
89+
pycam.camera.height,
90+
displayio.Colorspace.RGB565_SWAPPED,
91+
dither=True,
92+
) as g:
93+
t00 = t0 = time.monotonic()
94+
while (i < 15) or not pycam.shutter_button.value:
95+
i += 1
96+
_gifframe = pycam.continuous_capture()
97+
g.add_frame(_gifframe, 0.12)
98+
pycam.blit(_gifframe)
99+
t1 = time.monotonic()
100+
ft.append(1 / (t1 - t0))
101+
print(end=".")
102+
t0 = t1
103+
pycam._mode_label.text = "GIF" # pylint: disable=protected-access
104+
print(f"\nfinal size {f.tell()} for {i} frames")
105+
print(f"average framerate {i/(t1-t00)}fps")
106+
print(f"best {max(ft)} worst {min(ft)} std. deviation {np.std(ft)}")
107+
f.close()
108+
pycam.display.refresh()
109+
pycam.tone(1200, 0.15)
110+
111+
def snap_stop():
112+
pycam.tone(600, 0.1)
113+
pycam.capture_into_bitmap(last_frame)
114+
pycam.stop_motion_frame += 1
115+
try:
116+
pycam.display_message("Snap!", color=0x0000FF)
117+
pycam.capture_jpeg()
118+
# pylint: disable=unused-variable
119+
except TypeError as e:
120+
pycam.display_message("Failed", color=0xFF0000)
121+
time.sleep(0.5)
122+
except RuntimeError as e:
123+
pycam.display_message("Error\nNo SD Card", color=0xFF0000)
124+
time.sleep(0.5)
125+
pycam.live_preview_mode()
126+
127+
def toggle_handler(msg):
128+
addr = msg.addr
129+
tog_num = int(addr.replace('/1/toggle',''))
130+
if msg.args[0] == 1.0:
131+
print(tog_num, "is ON")
132+
else:
133+
print(tog_num, "is off")
134+
135+
def fader_handler(msg): # faders
136+
"""Used to handle 'fader' OscMsgs, printing it as a '*' text progress bar
137+
:param OscMsg msg: message with one required float32 value
138+
"""
139+
osc_addr = msg.addr.split('/') # chop up the address into parts
140+
# page_num = osc_addr[1]
141+
fader_num = int(osc_addr[2].replace('fader', '')) # get the number only
142+
if fader_num == 1: # led level
143+
led_val = int(msg.args[0] * 5)
144+
pycam.led_level = led_val
145+
146+
mode_texts = ("JPEG", "GIF", "GBOY", "STOP")
147+
148+
def radio_handler(msg): # Radio buttons
149+
osc_addr = msg.addr.split('/') # chop up the address into parts
150+
print(osc_addr)
151+
page_num = osc_addr[1]
152+
print("page_num:", page_num)
153+
rad_num = int(osc_addr[2].replace('radio', '')) # get the number only
154+
print("rad_num:", rad_num)
155+
if rad_num == 1: # MODE
156+
print("switched mode to", mode_texts[msg.args[0]])
157+
pycam.mode = msg.args[0]
158+
if rad_num == 2: # resolution
159+
print("switched resolution")
160+
pycam.resolution = msg.args[0]
161+
if rad_num == 3: # LED color
162+
print("set color")
163+
pycam.led_color = msg.args[0]
164+
if rad_num == 4: # effects
165+
print("switched effect")
166+
pycam.effect = msg.args[0]
167+
168+
def button_handler(msg): # buttons
169+
addr = msg.addr
170+
button_num = int(addr.replace('/1/button',''))
171+
if msg.args[0] == 1.0:
172+
print(button_num, "is ON")
173+
if button_num == 1:
174+
pycam.tone(1200, 0.05)
175+
pycam.tone(1600, 0.05)
176+
if pycam.mode_text == "JPEG":
177+
snap_jpeg()
178+
if pycam.mode_text == "GBOY":
179+
snap_gboy()
180+
if pycam.mode_text == "GIF":
181+
snap_gif()
182+
if pycam.mode_text == "STOP":
183+
snap_stop()
184+
185+
if button_num == 2: # focus
186+
pycam.tone(1800, 0.05)
187+
print("FOCUS")
188+
print(pycam.autofocus_status)
189+
pycam.autofocus()
190+
print(pycam.autofocus_status)
191+
pycam.tone(1400, 0.05)
192+
193+
else:
194+
print(button_num, "is off")
195+
196+
dispatch_map = {
197+
"/": lambda msg: print("msg:", msg.addr, msg.args), # prints all messages
198+
"/1/fader": fader_handler,
199+
"/2/fader": fader_handler,
200+
"/1/toggle": toggle_handler,
201+
"/1/button": button_handler,
202+
"/1/radio": radio_handler,
203+
"/2/radio": radio_handler
204+
}
205+
206+
osc_server = microosc.OSCServer(socket_pool, UDP_HOST, UDP_PORT, dispatch_map)
207+
print("MicroOSC server started on ", UDP_HOST, UDP_PORT)
208+
209+
210+
while True:
211+
osc_server.poll() # check for incoming OSC messages
212+
213+
if pycam.mode_text == "STOP" and pycam.stop_motion_frame != 0:
214+
# alpha blend
215+
new_frame = pycam.continuous_capture()
216+
bitmaptools.alphablend(
217+
onionskin, last_frame, new_frame, displayio.Colorspace.RGB565_SWAPPED
218+
)
219+
pycam.blit(onionskin)
220+
elif pycam.mode_text == "GBOY":
221+
bitmaptools.dither(
222+
last_frame, pycam.continuous_capture(), displayio.Colorspace.RGB565_SWAPPED
223+
)
224+
pycam.blit(last_frame)
225+
else:
226+
pycam.blit(pycam.continuous_capture())
227+
228+
pycam.keys_debounce()
229+
230+
if pycam.shutter.long_press:
231+
print("FOCUS")
232+
print(pycam.autofocus_status)
233+
pycam.autofocus()
234+
print(pycam.autofocus_status)
235+
236+
if pycam.shutter.short_count:
237+
print("Shutter released")
238+
if pycam.mode_text == "STOP":
239+
snap_stop()
240+
241+
if pycam.mode_text == "GBOY":
242+
snap_gboy()
243+
244+
if pycam.mode_text == "GIF":
245+
snap_gif()
246+
247+
if pycam.mode_text == "JPEG":
248+
snap_jpeg()
249+
250+
if pycam.card_detect.fell:
251+
print("SD card removed")
252+
pycam.unmount_sd_card()
253+
pycam.display.refresh()
254+
if pycam.card_detect.rose:
255+
print("SD card inserted")
256+
pycam.display_message("Mounting\nSD Card", color=0xFFFFFF)
257+
for _ in range(3):
258+
try:
259+
print("Mounting card")
260+
pycam.mount_sd_card()
261+
print("Success!")
262+
break
263+
except OSError as e:
264+
print("Retrying!", e)
265+
time.sleep(0.5)
266+
else:
267+
pycam.display_message("SD Card\nFailed!", color=0xFF0000)
268+
time.sleep(0.5)
269+
pycam.display.refresh()
270+
271+
if pycam.up.fell:
272+
print("UP")
273+
key = settings[curr_setting]
274+
if key:
275+
setattr(pycam, key, getattr(pycam, key) + 1)
276+
if pycam.down.fell:
277+
print("DN")
278+
key = settings[curr_setting]
279+
if key:
280+
setattr(pycam, key, getattr(pycam, key) - 1)
281+
if pycam.left.fell:
282+
print("LF")
283+
curr_setting = (curr_setting + 1) % len(settings)
284+
print(settings[curr_setting])
285+
pycam.select_setting(settings[curr_setting])
286+
if pycam.right.fell:
287+
print("RT")
288+
curr_setting = (curr_setting - 1 + len(settings)) % len(settings)
289+
print(settings[curr_setting])
290+
pycam.select_setting(settings[curr_setting])
291+
if pycam.select.fell:
292+
print("SEL")
293+
if pycam.ok.fell:
294+
print("OK")

0 commit comments

Comments
 (0)