fotobox/fotobox.py

253 lines
7.4 KiB
Python
Executable File

#!/usr/bin/env python
import os
import sys
import subprocess
import time
import _thread
import RPi.GPIO as GPIO
import pygame
import pygame.freetype
# wled blitz und effekt
from wled_controller_async import WLEDController
current_rotation = 0
rotations = ["normal", "right", "inverted", "left"]
sys.path.append("home/pi/go/bin/")
wled = WLEDController("192.168.4.2")
GPIO.setmode(GPIO.BCM)
GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_UP) # input
GPIO.setup(18, GPIO.OUT) # LED
GPIO.setup(17, GPIO.OUT) # green led
WIDTH = 1920
HEIGHT = 1080
POSX_QR = (WIDTH/5)*4
POSY_QR = int((HEIGHT/5)*3.2)
def get_canon_device_id():
"""
Executes 'lsusb' to find the Bus/Device ID of the connected Canon camera.
Returns the Bus/Device ID as a string (e.g., '001/008'), or None if not found.
"""
try:
# Run lsusb and capture the output
result = subprocess.run(["lsusb"], capture_output=True, text=True, check=True)
# Find the line that contains "Canon"
for line in result.stdout.split("\n"):
if "Canon" in line:
parts = line.split()
bus = parts[1]
device = parts[3].strip(":") # Remove the colon
device_id = f"{bus}/{device}"
return device_id
except subprocess.CalledProcessError as e:
print(f"Error running lsusb: {e}")
return None
def reset_usb_device(device_id):
"""
Resets the USB device using 'usbreset'.
"""
try:
usb_path = f"/dev/bus/usb/{device_id}"
print(f"Starting USB reset: {usb_path}")
# Run the usbreset command
subprocess.run(["sudo", "./usbreset", usb_path], check=True)
print("Done calling USB reset")
except subprocess.CalledProcessError as e:
print(f"Error resetting USB device: {e}")
def reset_camera():
"""
Finds the Canon camera and resets it before using gphoto2.
"""
device_id = get_canon_device_id()
if device_id:
print(f"Found Canon Camera at: {device_id}")
reset_usb_device(device_id)
else:
print("No Canon camera found.")
def io_remote():
# switch on ready
print("ready...")
GPIO.output(17, 1)
print("wait...")
# wait for button press, this is blocking
GPIO.wait_for_edge(21, GPIO.RISING, bouncetime=100)
print("green...")
# switch of green light
GPIO.output(17, 0)
def create_file_name(output_folder):
# name mit Timestamp versehen
ts = time.gmtime()
readable_ts = time.strftime("%H_%M_%S", ts)
photo_name = "/hs_2025_" + readable_ts + ".jpg"
path = output_folder + photo_name
print(f"Foto path: {path}")
return path
def display_image(screen, img, width, height, posx, posy):
try:
img = pygame.transform.scale(img, (width, height))
screen.blit(img, (posx, posy))
pygame.display.flip()
pygame.display.update()
except:
print("Cant display image: {0}".format(img))
def display_text(screen, text, color=(20, 240, 100), size=70):
font = pygame.freetype.Font(
"/usr/share/fonts/truetype/liberation2/LiberationSans-Bold.ttf", size
)
text_rendered, text_rect = font.render(text, color)
screen_rect = screen.get_rect()
text_rect.centerx = screen_rect.centerx
screen.blit(text_rendered, (50, 50))
pygame.display.update()
def signal_hook(running=True):
global current_rotation
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.KEYDOWN and event.key == pygame.K_f:
pygame.display.toggle_fullscreen()
"""
elif event.type == pygame.KEYDOWN and event.key == pygame.K_r:
print("r kez pressed")
current_rotation = (current_rotation + 1) % 4
new_rotation = rotations[current_rotation]
os.system(f"xrandr --output default --rotate {new_rotation}")
"""
def sync_photo(photo_path):
# hochladen des bildes
print("Uploading file..")
print(os.path.isfile(photo_path))
subprocess.run(
["rclone", "copy", "{}".format(photo_path), "haslachcloud:Fotobox"]
)
print("photo uploaded!")
def load_image(img_path):
return pygame.image.load(img_path).convert_alpha()
class Fotobox:
def __init__(self, output_folder, qr_path):
self.qr_img = None
self.screen = None
self.current_photo = None
self.output_folder = output_folder
self.qr_path = qr_path
self.setup()
def setup(self):
print("Initializing Fotobox...")
print("Calling init pygame")
pygame.init()
print("Finished initializing pygame")
wled.phase1()
# screen = pygame.display.set_mode((WIDTH, HEIGHT), 0, 0)
os.environ["DISPLAY"] = ":0.0"
flags = pygame.FULLSCREEN
self.screen = pygame.display.set_mode((0, 0), flags)
print("finished setting up pygame screen")
_thread.start_new_thread(signal_hook, ())
print("finish set up hook")
self.qr_img = load_image(self.qr_path)
print("finished loading qr")
print("Starting...")
GPIO.output(18, 0)
def display_qr_code(self):
display_image(self.screen, self.qr_img, 350, 350, POSX_QR, POSY_QR)
def display_photo(self):
display_image(self.screen, self.current_photo, WIDTH, HEIGHT, 0, 0)
def run(self):
while 1:
wled.phase1()
display_text(self.screen, "Kamera is breit!", color=(20, 230, 20))
self.display_qr_code()
# wait for button press
io_remote()
if self.current_photo:
self.display_photo()
self.display_qr_code()
display_text(self.screen, "Geschafft! Erstmal chillen...", color=(10, 50, 255))
wled.phase2()
# shoot picture
photo_path = create_file_name(self.output_folder)
# Capture photo
try:
subprocess.run(
[
"gphoto2",
"--capture-image-and-download",
"--camera='Canon EOS 350D (normal mode)'",
"--filename={}".format(photo_path),
"--force-overwrite",
]
)
wled.blitz()
except:
wled.phase1()
print("Subprocess crashed")
continue
# check if photo_path exists
if os.path.isfile(photo_path):
print("Loading photo from: {0}".format(photo_path))
self.current_photo = load_image(photo_path)
self.display_photo()
# sync_photo(photo_path)
else:
print("Did not find file: {0}".format(photo_path))
if self.current_photo:
self.display_photo()
self.display_qr_code()
display_text(self.screen, "Ups, probiers nochmal!", color=(230, 120, 20))
if __name__ == "__main__":
photo_folder = "/home/pi/fotobox_bilder_haslach"
qr_image = "/home/pi/Desktop/haslach.png"
my_photobox = Fotobox(photo_folder, qr_image)
my_photobox.run()
# gdrive about --service-account fotobox-265418-e52db5a765c2.json
# gdrive --service-account fotobox-265418-e52db5a765c2.json share ~/fotobox_bilder
# gdrive --service-account fotobox-265418-e52db5a765c2.json sync list