From 76f3b1780fa1bc18163f0571c7eca7867cc1c8af Mon Sep 17 00:00:00 2001 From: root Date: Sun, 22 Oct 2017 10:10:05 +0200 Subject: [PATCH] GIT initial: Produktivstand --- endless.sh | 8 + mount_sda1.sh | 7 + photobox.py | 413 +++++++++++++++++++++++++++++++++++++++++++++++ upload-daemon.sh | 59 +++++++ 4 files changed, 487 insertions(+) create mode 100755 endless.sh create mode 100755 mount_sda1.sh create mode 100755 photobox.py create mode 100755 upload-daemon.sh diff --git a/endless.sh b/endless.sh new file mode 100755 index 0000000..b07f942 --- /dev/null +++ b/endless.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +cd $(dirname "$0") + +while true; do + xinit /opt/photobox/photobox.py + sleep 1 +done diff --git a/mount_sda1.sh b/mount_sda1.sh new file mode 100755 index 0000000..9d7f12e --- /dev/null +++ b/mount_sda1.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +if [ -e /dev/sda1 ]; then + if ! mount | grep sda1; then + mount /dev/sda1 /fotobox + fi +fi diff --git a/photobox.py b/photobox.py new file mode 100755 index 0000000..4cdaf3b --- /dev/null +++ b/photobox.py @@ -0,0 +1,413 @@ +#!/usr/bin/python + +import sys, os, inspect +import pytz, datetime +from time import sleep +from PIL import Image +from shutil import copyfile +from math import floor +import RPi.GPIO as GPIO + +import picamera +import pygame +import random +import time + + + + +__all__ = ["monotonic_time"] + +import ctypes + +CLOCK_MONOTONIC_RAW = 4 # see + +class timespec(ctypes.Structure): + _fields_ = [ + ('tv_sec', ctypes.c_long), + ('tv_nsec', ctypes.c_long) + ] + +librt = ctypes.CDLL('librt.so.1', use_errno=True) +clock_gettime = librt.clock_gettime +clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)] + +def monotonic_time(): + t = timespec() + if clock_gettime(CLOCK_MONOTONIC_RAW , ctypes.pointer(t)) != 0: + errno_ = ctypes.get_errno() + raise OSError(errno_, os.strerror(errno_)) + return t.tv_sec + t.tv_nsec * 1e-9 + + + + +os.chdir(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) + + +# CONFIGURATION +WIDTH = 800 +HEIGHT = 480 +FONTSIZE = 500 +PIC_INTERVAL = 0.5 +TEXT_INTERVAL = 0.5 +TEXT_POS = (250, -40) +OVERLAY_ALPHA = 64 +COLOR_BACK = pygame.Color(0, 0, 0) +COLOR_FLASH = pygame.Color(255, 255, 255) +GRAPHICS_DIR = "./graphics" +IMAGE_DIR = "/var/www/html/current_images" +COUNTDOWN = 3 +SHOT_COUNT = 3 +BORDER = 10 + +THUMB_WIDTH = int((800 - BORDER) / SHOT_COUNT - BORDER) +THUMB_HEIGHT = int(THUMB_WIDTH / 1.333) + + + +# global variables +session_start = monotonic_time() + + + +# CREATE DIRECTORIES +try: + os.makedirs(GRAPHICS_DIR) +except OSError: + pass + +try: + os.makedirs(IMAGE_DIR) +except OSError: + pass + +try: + os.makedirs(IMAGE_DIR + "/original") +except OSError: + pass + +try: + os.makedirs(IMAGE_DIR + "/todo") +except OSError: + pass + + + +# INIT GPIO +GPIO.setmode(GPIO.BOARD) +GPIO.setwarnings(False) +GPIO.setup(7, GPIO.OUT) +GPIO.output(7, GPIO.LOW) +sleep(0.02) +GPIO.output(7, GPIO.HIGH) +sleep(0.02) +GPIO.output(7, GPIO.LOW) +sleep(0.02) +GPIO.output(7, GPIO.HIGH) +sleep(0.02) +GPIO.output(7, GPIO.LOW) +sleep(0.02) +GPIO.output(7, GPIO.HIGH) +sleep(0.02) +GPIO.output(7, GPIO.LOW) + + + +# INIT PYGAME +pygame.init() +pygame.mouse.set_visible(False) +screen = pygame.display.set_mode((WIDTH,HEIGHT)) + + + +# LOAD OVERLAYS +loading = pygame.image.load(GRAPHICS_DIR + "/loading.png") +loading_rect = loading.get_rect() + +begin = pygame.image.load(GRAPHICS_DIR + "/begin.png") +begin_rect = begin.get_rect() + +yes = pygame.image.load(GRAPHICS_DIR + "/yes.png") +yes_rect = yes.get_rect() +yes_rect.y = 340 + +no = pygame.image.load(GRAPHICS_DIR + "/no.png") +no_rect = no.get_rect() +no_rect.y = 340 + +end_yes = pygame.image.load(GRAPHICS_DIR + "/end_yes.png") +end_yes_rect = end_yes.get_rect() + +end_no = pygame.image.load(GRAPHICS_DIR + "/end_no.png") +end_no_rect = end_no.get_rect() + +saved = pygame.image.load(GRAPHICS_DIR + "/saved.png") +saved_rect = saved.get_rect() + +canceled = pygame.image.load(GRAPHICS_DIR + "/canceled.png") +canceled_rect = canceled.get_rect() + +#~ img_info = Image.open(GRAPHICS_DIR + '/info.png') + + + +# LOAD COUNTDOWN OVERLAYS +img_cdn = [] +pad_cdn = [] +for i in range(0, COUNTDOWN): + img = Image.open(GRAPHICS_DIR + "/%s.png" % (COUNTDOWN - i)) + 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) + + + +# LOAD INFORMATION OVERLAY +img_info = Image.open(GRAPHICS_DIR + '/info.png') +pad_info = Image.new('RGB', ( + ((img_info.size[0] + 31) // 32) * 32, + ((img_info.size[1] + 15) // 16) * 16, +)) +pad_info.paste(img_info, (0, 0)) + + + +# FUNCTIONS ======================================================================================== + +def waitForEvent(): + pygame.event.clear() + while 1: + 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 + + + +def waitForTouch(): + pos = (-1, -1) + while True: + events = waitForEvent() + for event in events: + if event.type == pygame.MOUSEMOTION: + pos = event.pos + elif event.type == pygame.MOUSEBUTTONUP: + return pos + + + +def maintainance(): + screen.fill(COLOR_BACK) + screen.blit(maintain, maintain_rect) + pygame.display.flip() + + # wait + pos = waitForTouch() + + + + +def waitForBegin(): + screen.fill(COLOR_BACK) + screen.blit(begin, begin_rect) + pygame.display.flip() + + # wait + pos = waitForTouch() + if pos[0] > 720 and pos[1] > 400: + maintainance() + + + +def countdown(camera, pad, img, flash): + sleep(PIC_INTERVAL) + o = camera.add_overlay(pad.tostring(), size=img.size) + o.alpha = OVERLAY_ALPHA + o.layer = 3 +# if flash: +# GPIO.output(7, GPIO.HIGH) +# sleep(0.01) +# GPIO.output(7, GPIO.LOW) + sleep(TEXT_INTERVAL) + camera.remove_overlay(o) + + + +def makePhotos(): + # CLEAR SCREEN + screen.fill(COLOR_BACK) + pygame.display.update() + + # INIT CAMERA + camera = picamera.PiCamera() + camera.vflip = False + camera.hflip = True + camera.resolution = (2592, 1944) + camera.rotation = 90 + + # PREVIEW + camera.start_preview() + o = camera.add_overlay(pad_info.tostring(), size=img_info.size) + o.alpha = 255 + o.layer = 3 + sleep(3) + camera.remove_overlay(o) + sleep(1) + + # COUNTDOWN + GPIO.output(7, GPIO.HIGH) + for i in range(0, COUNTDOWN): + countdown(camera, pad_cdn[i], img_cdn[i], True) + GPIO.output(7, GPIO.LOW) + + # SHOTS + for i in range(0, SHOT_COUNT): + # SHOT! + sleep(PIC_INTERVAL) + GPIO.output(7, GPIO.HIGH) + screen.fill(COLOR_FLASH) + pygame.display.update() + camera.stop_preview() + camera.capture("./tmp%s.jpg" % i, format='jpeg', quality=100, thumbnail=None) + GPIO.output(7, GPIO.LOW) + + # 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(): + # clear screen + screen.fill(COLOR_BACK) + screen.blit(loading, loading_rect) + pygame.display.update() + + # load images from disk + img_tmp = [] + rect_tmp = [] + choices = [] + x = 12 + for i in range(0, SHOT_COUNT): + img = pygame.image.load("tmp%s.jpg" % i) + img = pygame.transform.scale(img, (THUMB_WIDTH, THUMB_HEIGHT)) + rect = img.get_rect() + rect.x = x + rect.y = 146 + + img_tmp.append(img) + rect_tmp.append(rect) + choices.append(0) + + x = x + THUMB_WIDTH + BORDER + + + save = False + cancel = False + any_choice = False + while not cancel and (not save or not any_choice): + # reset save (due to no choice made) + save = False + + # draw background + screen.fill(COLOR_BACK) + if any_choice: + screen.blit(end_yes, end_yes_rect) + else: + screen.blit(end_no, end_no_rect) + + # draw images + for i in range(0, SHOT_COUNT): + screen.blit(img_tmp[i], rect_tmp[i]) + + # draw choices + x = 12 + for choice in choices: + if choice > 0: + yes_rect.x = x + (THUMB_WIDTH - yes_rect.width) / 2 + screen.blit(yes, yes_rect) + else: + no_rect.x = x + (THUMB_WIDTH - no_rect.width) / 2 + screen.blit(no, no_rect) + + x = x + THUMB_WIDTH + BORDER + + # update display + pygame.display.flip() + + # wait for new event (touch screen / mouse / keyboard) + pos = waitForTouch() + if pos[1] > 140: + # toggle image + i = int(floor((pos[0] - BORDER / 2) / (THUMB_WIDTH + BORDER))) + if i >= 0 and i < SHOT_COUNT: + choices[i] = (choices[i] + 1) % 2 + elif pos[1] < 100: + # top menu buttons + if pos[0] > 0 and pos[0] < 266: + cancel = True + elif pos[0] > 533 and pos[0] < 800 and (choices[0] > 0 or choices[1] > 0 or choices[2] > 0): + save = True + + any_choice = False + for choice in choices: + if choice > 0: + any_choice = True + break + + # END: choice + #~ print("# END: choice") + + return (choices, save) + + + +def saveImages(choices): + local = datetime.datetime.now() + session_age = (monotonic_time() - session_start) + + 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) + os.rename("tmp%s.jpg" % i, IMAGE_DIR + "/original/" + filename) + copyfile(IMAGE_DIR + "/original/" + filename, IMAGE_DIR + "/todo/" + filename) + + # show message + screen.fill(COLOR_BACK) + screen.blit(saved, saved_rect) + pygame.display.flip() + sleep(2) + + + +while 1: + waitForBegin() + makePhotos() + (choices, save) = chooseImages() + + if save: + saveImages(choices); + else: + # show message + screen.fill(COLOR_BACK) + screen.blit(canceled, canceled_rect) + pygame.display.flip() + sleep(2) + +pygame.quit() diff --git a/upload-daemon.sh b/upload-daemon.sh new file mode 100755 index 0000000..3382353 --- /dev/null +++ b/upload-daemon.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +INTERVAL="10" +FAILURE_PAUSE="10" +LOCAL_FILES="/var/www/html/current_images" + +BASE_URL="https://fotobox.online/upload" +#BASE_URL="http://fotobox.online:8888/upload" +#BASE_URL="http://10.50.0.30:8888/upload" + +FOTOBOX_ID="1" +FOTOBOX_KEY="eDAOMohrcJY3" + +EVENT_ID="20" + + + +mkdir -p "$LOCAL_FILES/todo" 2> /dev/null +mkdir -p "$LOCAL_FILES/upload" 2> /dev/null +mkdir -p "$LOCAL_FILES/lowres" 2> /dev/null + +while true; do + date=$(date +'%Y-%m-%d %H:%M:%S') + + cd "$LOCAL_FILES/todo" + todos="$(ls ./)" + if [ "$todos" != "" ]; then + echo "$date: uploading files:" + for todo in $todos; do + echo "converting..." + convert "$todo" -resize 1000x -quality 0.7 "../lowres/$todo" && cp "../lowres/$todo" "../upload/$todo" && rm -f "$todo" + done + echo "" + fi + + cd "$LOCAL_FILES/upload" + uploads="$(ls ./)" + if [ "$uploads" != "" ]; then + echo "$date: uploading files:" + for upload in $uploads; do + echo "uploading..." + timestamp_fotobox=$(date +'%Y-%m-%dT%H:%M:%S.%N%z') + timestamp_shot=$(basename "$upload" | sed 's|.jpg||g') + url="$BASE_URL/$FOTOBOX_ID/$FOTOBOX_KEY/$EVENT_ID/$timestamp_fotobox/$timestamp_shot/" + echo "$url" + result=$(curl -s --form "image=@$upload" "$url" 2>&1) + echo "$result" + if [ "$result" == "OK" ]; then + rm -f "$upload" + else + sleep $FAILURE_PAUSE + fi + done + echo "" + fi + + # SLEEP + sleep $INTERVAL +done