This commit is contained in:
Patrick Haßel 2018-08-15 12:19:10 +02:00
parent 0e23e048da
commit 50a3d6f29f
2 changed files with 278 additions and 299 deletions

View File

@ -3,9 +3,9 @@
import json import json
import socket import socket
UDP_IP = "255.255.255.255" UDP_IP = "255.255.255.255"
UDP_PORT = 32145 UDP_PORT = 32145
MESSAGE = {"subject": "Fotobox Broadcast", "port": 80} MESSAGE = {"subject": "Fotobox Broadcast", "port": 80}
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

View File

@ -1,125 +1,118 @@
#!/usr/bin/python #!/usr/bin/python
import sys, os, inspect import datetime
import pytz, datetime import inspect
from time import sleep import os
from PIL import Image import sys
from shutil import copyfile
from math import floor from math import floor
import RPi.GPIO as GPIO from shutil import copyfile
from time import sleep
import RPi.GPIO as GPIO
import picamera import picamera
import pygame import pygame
import random from PIL import Image
import time
# ~ import server # ~ import server
__all__ = ["monotonic_time"] __all__ = ["monotonic_time"]
import ctypes import ctypes
CLOCK_MONOTONIC_RAW = 4 # see <linux/time.h> CLOCK_MONOTONIC_RAW = 4 # see <linux/time.h>
class timespec(ctypes.Structure): class timespec(ctypes.Structure):
_fields_ = [ _fields_ = [
('tv_sec', ctypes.c_long), ('tv_sec', ctypes.c_long),
('tv_nsec', ctypes.c_long) ('tv_nsec', ctypes.c_long)
] ]
librt = ctypes.CDLL('librt.so.1', use_errno=True) librt = ctypes.CDLL('librt.so.1', use_errno=True)
clock_gettime = librt.clock_gettime clock_gettime = librt.clock_gettime
clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)] clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)]
def monotonic_time(): def monotonic_time():
t = timespec() t = timespec()
if clock_gettime(CLOCK_MONOTONIC_RAW , ctypes.pointer(t)) != 0: if clock_gettime(CLOCK_MONOTONIC_RAW, ctypes.pointer(t)) != 0:
errno_ = ctypes.get_errno() errno_ = ctypes.get_errno()
raise OSError(errno_, os.strerror(errno_)) raise OSError(errno_, os.strerror(errno_))
return t.tv_sec + t.tv_nsec * 1e-9 return t.tv_sec + t.tv_nsec * 1e-9
os.chdir(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) os.chdir(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))))
# CONFIGURATION # CONFIGURATION
WIDTH = 800 WIDTH = 800
HEIGHT = 480 HEIGHT = 480
FONTSIZE = 500 FONTSIZE = 500
PIC_INTERVAL = 0.5 PIC_INTERVAL = 0.5
TEXT_INTERVAL = 0.5 TEXT_INTERVAL = 0.5
TEXT_POS = (250, -40) TEXT_POS = (250, -40)
OVERLAY_ALPHA = 64 OVERLAY_ALPHA = 64
COLOR_BACK = pygame.Color(0, 0, 0) COLOR_BACK = pygame.Color(0, 0, 0)
COLOR_FLASH = pygame.Color(255, 255, 255) COLOR_FLASH = pygame.Color(255, 255, 255)
GRAPHICS_DIR = "graphics" GRAPHICS_DIR = "graphics"
IMAGE_DIR = "images/0-CURRENT" IMAGE_DIR = "images/0-CURRENT"
COUNTDOWN = 3 COUNTDOWN = 3
SHOT_COUNT = 3 SHOT_COUNT = 3
BORDER = 10 BORDER = 10
GPIO_LED_BORDER = 7 GPIO_LED_BORDER = 7
GPIO_SPOT_RIGHT = 35 GPIO_SPOT_RIGHT = 35
GPIO_SPOT_LEFT = 37 GPIO_SPOT_LEFT = 37
GPIO_BUTTON_LED = 36 GPIO_BUTTON_LED = 36
GPIO_BUTTON = 38 GPIO_BUTTON = 38
THUMB_WIDTH = int((800 - BORDER) / SHOT_COUNT - BORDER)
THUMB_HEIGHT = int(THUMB_WIDTH / 1.333)
IMAGES_ORIGINAL = os.path.join(IMAGE_DIR, "original")
IMAGES_TODO = os.path.join(IMAGE_DIR, "todo")
THUMB_WIDTH = int((800 - BORDER) / SHOT_COUNT - BORDER)
THUMB_HEIGHT = int(THUMB_WIDTH / 1.333)
IMAGES_ORIGINAL = os.path.join(IMAGE_DIR, "original")
IMAGES_TODO = os.path.join(IMAGE_DIR, "todo")
# global variables # global variables
spot_mode = 0 spot_mode = 0
session_start = monotonic_time() session_start = monotonic_time()
# GPIO helpers # GPIO helpers
def led_border(state): def led_border(state):
global GPIO_LED_BORDER global GPIO_LED_BORDER
GPIO.output(GPIO_LED_BORDER, state) GPIO.output(GPIO_LED_BORDER, state)
def set_spot_mode(new_mode): def set_spot_mode(new_mode):
global spot_mode global spot_mode
spot_mode = new_mode % 4 spot_mode = new_mode % 4
GPIO.output(GPIO_SPOT_LEFT, not (spot_mode & 1)) GPIO.output(GPIO_SPOT_LEFT, not (spot_mode & 1))
GPIO.output(GPIO_SPOT_RIGHT, not (spot_mode & 2)) GPIO.output(GPIO_SPOT_RIGHT, not (spot_mode & 2))
def next_spot_mode(): def next_spot_mode():
global spot_mode global spot_mode
set_spot_mode(spot_mode + 1) set_spot_mode(spot_mode + 1)
# user interface # user interface
def button_press(gpio_id): def button_press(gpio_id):
next_spot_mode() next_spot_mode()
# INIT GPIO # INIT GPIO
GPIO.setmode(GPIO.BOARD) GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False) GPIO.setwarnings(False)
GPIO.setup(GPIO_SPOT_RIGHT, GPIO.OUT, initial=GPIO.HIGH) GPIO.setup(GPIO_SPOT_RIGHT, GPIO.OUT, initial=GPIO.HIGH)
GPIO.setup(GPIO_SPOT_LEFT, GPIO.OUT, initial=GPIO.HIGH) GPIO.setup(GPIO_SPOT_LEFT, GPIO.OUT, initial=GPIO.HIGH)
GPIO.setup(GPIO_LED_BORDER, GPIO.OUT, initial=GPIO.LOW) GPIO.setup(GPIO_LED_BORDER, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(GPIO_BUTTON_LED, GPIO.OUT, initial=GPIO.LOW) GPIO.setup(GPIO_BUTTON_LED, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(GPIO_BUTTON, GPIO.IN) GPIO.setup(GPIO_BUTTON, GPIO.IN)
GPIO.add_event_detect(GPIO_BUTTON, GPIO.FALLING, button_press, bouncetime=300) GPIO.add_event_detect(GPIO_BUTTON, GPIO.FALLING, button_press, bouncetime=300)
led_border(False) led_border(False)
@ -136,26 +129,24 @@ led_border(True)
sleep(0.02) sleep(0.02)
led_border(False) led_border(False)
# INIT PYGAME # INIT PYGAME
pygame.init() pygame.init()
pygame.mouse.set_visible(False) pygame.mouse.set_visible(False)
screen = pygame.display.set_mode((WIDTH,HEIGHT)) screen = pygame.display.set_mode((WIDTH, HEIGHT))
# LOAD GRAPHICS # LOAD GRAPHICS
gfx = {} gfx = {}
def _load(name): def _load(name):
filename = "%s.png" % name filename = "%s.png" % name
path = os.path.join(GRAPHICS_DIR, filename) path = os.path.join(GRAPHICS_DIR, filename)
img = pygame.image.load(path) img = pygame.image.load(path)
rect = img.get_rect() rect = img.get_rect()
gfx[name] = (img, rect) gfx[name] = (img, rect)
_load("begin") _load("begin")
_load("loading") _load("loading")
@ -166,261 +157,249 @@ _load("end_no")
_load("saved") _load("saved")
_load("canceled") _load("canceled")
# LOAD COUNTDOWN OVERLAYS # LOAD COUNTDOWN OVERLAYS
img_cdn = [] img_cdn = []
pad_cdn = [] pad_cdn = []
for i in range(0, COUNTDOWN): for i in range(0, COUNTDOWN):
filename = "%s.png" % (COUNTDOWN - i) filename = "%s.png" % (COUNTDOWN - i)
path = os.path.join(GRAPHICS_DIR, filename) path = os.path.join(GRAPHICS_DIR, filename)
img = Image.open(path)
pad = Image.new('RGB', (
((img.size[0] + 31) // 32) * 32,
((img.size[1] + 15) // 16) * 16,
))
pad.paste(img, (0, 0))
img_cdn.append(img)
pad_cdn.append(pad)
img = Image.open(path)
pad = Image.new('RGB', (
((img.size[0] + 31) // 32) * 32,
((img.size[1] + 15) // 16) * 16,
))
pad.paste(img, (0, 0))
img_cdn.append(img)
pad_cdn.append(pad)
# FUNCTIONS ======================================================================================== # FUNCTIONS ========================================================================================
def waitForEvent(): def waitForEvent():
pygame.event.clear() pygame.event.clear()
while 1: while 1:
sleep(0.25) sleep(0.25)
events = pygame.event.get()
if len(events) > 0:
for event in events:
if event.type == pygame.QUIT:
sys.exit(0)
return events
events = pygame.event.get()
if len(events) > 0:
for event in events:
if event.type == pygame.QUIT:
sys.exit(0)
return events
def waitForTouch(): def waitForTouch():
pos = (-1, -1) pos = (-1, -1)
while True: while True:
events = waitForEvent() events = waitForEvent()
for event in events: for event in events:
if event.type == pygame.MOUSEMOTION: if event.type == pygame.MOUSEMOTION:
pos = event.pos pos = event.pos
elif event.type == pygame.MOUSEBUTTONUP: elif event.type == pygame.MOUSEBUTTONUP:
return pos return pos
def maintainance(): def maintainance():
screen.fill(COLOR_BACK) screen.fill(COLOR_BACK)
screen.blit(maintain, maintain_rect) screen.blit(maintain, maintain_rect)
pygame.display.flip() pygame.display.flip()
# wait
pos = waitForTouch()
# wait
pos = waitForTouch()
def waitForBegin(): def waitForBegin():
screen.fill(COLOR_BACK) screen.fill(COLOR_BACK)
screen.blit(*gfx["begin"]) screen.blit(*gfx["begin"])
pygame.display.flip() pygame.display.flip()
# wait
pos = waitForTouch()
if pos[0] > 720 and pos[1] > 400:
maintainance()
# wait
pos = waitForTouch()
if pos[0] > 720 and pos[1] > 400:
maintainance()
def countdown(camera, pad, img): def countdown(camera, pad, img):
sleep(PIC_INTERVAL) sleep(PIC_INTERVAL)
o = camera.add_overlay(pad.tostring(), size=img.size) o = camera.add_overlay(pad.tostring(), size=img.size)
o.alpha = OVERLAY_ALPHA o.alpha = OVERLAY_ALPHA
o.layer = 3 o.layer = 3
sleep(TEXT_INTERVAL) sleep(TEXT_INTERVAL)
camera.remove_overlay(o) camera.remove_overlay(o)
def makePhotos(): def makePhotos():
# CLEAR SCREEN # CLEAR SCREEN
screen.fill(COLOR_BACK) screen.fill(COLOR_BACK)
pygame.display.update() pygame.display.update()
# INIT CAMERA
camera = picamera.PiCamera()
camera.vflip = False
camera.hflip = True
camera.resolution = (2592, 1944)
camera.rotation = 90
camera.start_preview()
# COUNTDOWN
led_border(True)
for i in range(0, COUNTDOWN):
countdown(camera, pad_cdn[i], img_cdn[i])
led_border(False)
# SHOTS
for i in range(0, SHOT_COUNT):
# SHOT!
sleep(PIC_INTERVAL)
led_border(True)
camera.capture("./tmp%s.jpg" % i, format='jpeg', quality=100, thumbnail=None)
led_border(False)
# PAUSE
if i < SHOT_COUNT - 1:
screen.fill(COLOR_BACK)
pygame.display.update()
camera.start_preview()
sleep(TEXT_INTERVAL)
# CLOSE CAMERA
camera.close()
# INIT CAMERA
camera = picamera.PiCamera()
camera.vflip = False
camera.hflip = True
camera.resolution = (2592, 1944)
camera.rotation = 90
camera.start_preview()
# COUNTDOWN
led_border(True)
for i in range(0, COUNTDOWN):
countdown(camera, pad_cdn[i], img_cdn[i])
led_border(False)
# SHOTS
for i in range(0, SHOT_COUNT):
# SHOT!
sleep(PIC_INTERVAL)
led_border(True)
camera.capture("./tmp%s.jpg" % i, format='jpeg', quality=100, thumbnail=None)
led_border(False)
# PAUSE
if i < SHOT_COUNT - 1:
screen.fill(COLOR_BACK)
pygame.display.update()
camera.start_preview()
sleep(TEXT_INTERVAL)
# CLOSE CAMERA
camera.close()
def chooseImages(): def chooseImages():
# clear screen # clear screen
screen.fill(COLOR_BACK) screen.fill(COLOR_BACK)
screen.blit(*gfx["loading"]) screen.blit(*gfx["loading"])
pygame.display.update() pygame.display.update()
# load images from disk # load images from disk
img_tmp = [] img_tmp = []
rect_tmp = [] rect_tmp = []
choices = [] choices = []
x = 12 x = 12
for i in range(0, SHOT_COUNT): for i in range(0, SHOT_COUNT):
img = pygame.image.load("tmp%s.jpg" % i) img = pygame.image.load("tmp%s.jpg" % i)
img = pygame.transform.scale(img, (THUMB_WIDTH, THUMB_HEIGHT)) img = pygame.transform.scale(img, (THUMB_WIDTH, THUMB_HEIGHT))
rect = img.get_rect() rect = img.get_rect()
rect.x = x rect.x = x
rect.y = 146 rect.y = 146
img_tmp.append(img) img_tmp.append(img)
rect_tmp.append(rect) rect_tmp.append(rect)
choices.append(0) choices.append(0)
x = x + THUMB_WIDTH + BORDER x = x + THUMB_WIDTH + BORDER
save = False
save = False cancel = False
cancel = False any_choice = False
any_choice = False while not cancel and (not save or not any_choice):
while not cancel and (not save or not any_choice): # reset save (if nothing selected)
# reset save (if nothing selected) save = False
save = False
# draw background
# draw background screen.fill(COLOR_BACK)
screen.fill(COLOR_BACK) if any_choice:
if any_choice: screen.blit(*gfx["end_yes"])
screen.blit(*gfx["end_yes"]) else:
else: screen.blit(*gfx["end_no"])
screen.blit(*gfx["end_no"])
# draw images
# draw images for i in range(0, SHOT_COUNT):
for i in range(0, SHOT_COUNT): screen.blit(img_tmp[i], rect_tmp[i])
screen.blit(img_tmp[i], rect_tmp[i])
# draw choices
# draw choices x = 12
x = 12 for choice in choices:
for choice in choices: if choice > 0:
if choice > 0: (img, rect) = gfx["yes"]
(img, rect) = gfx["yes"] else:
else: (img, rect) = gfx["no"]
(img, rect) = gfx["no"]
rect.x = x + (THUMB_WIDTH - rect.width) / 2
rect.x = x + (THUMB_WIDTH - rect.width) / 2 rect.y = 340
rect.y = 340 screen.blit(img, rect)
screen.blit(img, rect)
x = x + THUMB_WIDTH + BORDER
x = x + THUMB_WIDTH + BORDER
# update display
# update display pygame.display.flip()
pygame.display.flip()
# wait for new event (touch screen / mouse / keyboard)
# wait for new event (touch screen / mouse / keyboard) pos = waitForTouch()
pos = waitForTouch() if pos[1] > 140:
if pos[1] > 140: # toggle image
# toggle image i = int(floor((pos[0] - BORDER / 2) / (THUMB_WIDTH + BORDER)))
i = int(floor((pos[0] - BORDER / 2) / (THUMB_WIDTH + BORDER))) if i >= 0 and i < SHOT_COUNT:
if i >= 0 and i < SHOT_COUNT: choices[i] = (choices[i] + 1) % 2
choices[i] = (choices[i] + 1) % 2
elif pos[1] < 100:
elif pos[1] < 100: # top menu buttons
# top menu buttons if pos[0] > 0 and pos[0] < 266:
if pos[0] > 0 and pos[0] < 266: cancel = True
cancel = True elif pos[0] > 533 and pos[0] < 800 and (choices[0] > 0 or choices[1] > 0 or choices[2] > 0):
elif pos[0] > 533 and pos[0] < 800 and (choices[0] > 0 or choices[1] > 0 or choices[2] > 0): save = True
save = True
any_choice = False
any_choice = False for choice in choices:
for choice in choices: if choice > 0:
if choice > 0: any_choice = True
any_choice = True break
break
return (choices, save)
return (choices, save)
def saveImages(choices): def saveImages(choices):
local = datetime.datetime.now() local = datetime.datetime.now()
session_age = (monotonic_time() - session_start) session_age = (monotonic_time() - session_start)
try:
os.makedirs(IMAGES_ORIGINAL)
except OSError:
pass
try:
os.makedirs(IMAGES_TODO)
except OSError:
pass
print("saving images...")
for i in range(0, SHOT_COUNT):
if choices[i] > 0:
print(" saving image #%s" % i)
filename = "%s-%s-session_age=%05d.jpg" % (local.strftime("%Y%m%dT%H:%M:%S.%f%z"), i, session_age)
path_tmp = "tmp%s.jpg" % i
path_original = os.path.join(IMAGES_ORIGINAL, filename)
path_todo = os.path.join(IMAGES_TODO, filename)
os.rename(path_tmp, path_original)
copyfile(path_original, path_todo)
try:
os.makedirs(IMAGES_ORIGINAL)
except OSError:
pass
try:
os.makedirs(IMAGES_TODO)
except OSError:
pass
print("saving images...")
for i in range(0, SHOT_COUNT):
if choices[i] > 0:
print(" saving image #%s" % i)
filename = "%s-%s-session_age=%05d.jpg" % (local.strftime("%Y%m%dT%H:%M:%S.%f%z"), i, session_age)
path_tmp = "tmp%s.jpg" % i
path_original = os.path.join(IMAGES_ORIGINAL, filename)
path_todo = os.path.join(IMAGES_TODO, filename)
os.rename(path_tmp, path_original)
copyfile(path_original, path_todo)
try: try:
while 1: while 1:
waitForBegin() waitForBegin()
makePhotos() makePhotos()
(choices, save) = chooseImages() (choices, save) = chooseImages()
if save: if save:
saveImages(choices); saveImages(choices);
screen.fill(COLOR_BACK) screen.fill(COLOR_BACK)
screen.blit(*gfx["saved"]) screen.blit(*gfx["saved"])
pygame.display.flip() pygame.display.flip()
else: else:
screen.fill(COLOR_BACK) screen.fill(COLOR_BACK)
screen.blit(*gfx["canceled"]) screen.blit(*gfx["canceled"])
pygame.display.flip() pygame.display.flip()
sleep(2) sleep(2)
except KeyboardInterrupt: except KeyboardInterrupt:
print("") print("")
finally: finally:
led_border(False) led_border(False)
pygame.quit() pygame.quit()