Files
picUploadApi/demo/capture-upload.sh

290 lines
9.6 KiB
Bash

#!/bin/bash
# capture-upload.sh - Capture from USB webcam and upload to PicUpper
# For Raspberry Pi 3 with Logitech USB webcam
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="${SCRIPT_DIR}/picupper.conf"
# ==============================================================================
# Load Configuration
# ==============================================================================
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "ERROR: Configuration file not found: $CONFIG_FILE"
echo "Please copy picupper.conf.example to picupper.conf and configure it."
exit 1
fi
# shellcheck source=/dev/null
source "$CONFIG_FILE"
# Validate required settings
if [[ -z "${API_KEY:-}" || "$API_KEY" == "your-api-key-here" ]]; then
echo "ERROR: API_KEY not configured in $CONFIG_FILE"
exit 1
fi
# Set defaults for optional settings
API_URL="${API_URL:-https://dev.seedheads.de/picUploadApi/upload}"
CAMERA_ID="${CAMERA_ID:-rpi-webcam}"
VIDEO_DEVICE="${VIDEO_DEVICE:-/dev/video0}"
RESOLUTION="${RESOLUTION:-1920x1080}"
SKIP_FRAMES="${SKIP_FRAMES:-5}"
TEMP_DIR="${TEMP_DIR:-/tmp}"
LOG_FILE="${LOG_FILE:-${SCRIPT_DIR}/picupper.log}"
TIMEOUT="${TIMEOUT:-30}"
MAX_RETRIES="${MAX_RETRIES:-3}"
RETRY_DELAY="${RETRY_DELAY:-5}"
# ==============================================================================
# Helper Functions
# ==============================================================================
log() {
local timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local msg="[$timestamp] $*"
echo "$msg"
echo "$msg" >> "$LOG_FILE" 2>/dev/null || true
}
log_error() {
log "ERROR: $*" >&2
}
cleanup() {
rm -f "${TEMP_FILE:-}" 2>/dev/null || true
}
trap cleanup EXIT
# ==============================================================================
# Test Mode
# ==============================================================================
if [[ "${1:-}" == "--test" ]]; then
echo "=== PicUpper Test Mode ==="
echo "Config file: $CONFIG_FILE"
echo "API URL: $API_URL"
echo "Camera ID: $CAMERA_ID"
echo "Video device: $VIDEO_DEVICE"
echo "Resolution: $RESOLUTION"
echo ""
# Check video device
if [[ ! -e "$VIDEO_DEVICE" ]]; then
echo "❌ Video device not found: $VIDEO_DEVICE"
echo " Available devices:"
ls -la /dev/video* 2>/dev/null || echo " No video devices found"
exit 1
fi
echo "✓ Video device exists: $VIDEO_DEVICE"
# Check fswebcam
if ! command -v fswebcam &>/dev/null; then
echo "❌ fswebcam not installed. Run: sudo apt install fswebcam"
exit 1
fi
echo "✓ fswebcam installed"
# Try capture
TEST_FILE="${TEMP_DIR}/picupper_test_$(date +%s).jpg"
echo "Capturing test image to: $TEST_FILE"
if fswebcam -d "$VIDEO_DEVICE" -r "$RESOLUTION" -S "$SKIP_FRAMES" --no-banner "$TEST_FILE" 2>/dev/null; then
FILE_SIZE=$(stat -f%z "$TEST_FILE" 2>/dev/null || stat -c%s "$TEST_FILE" 2>/dev/null)
echo "✓ Capture successful: $TEST_FILE (${FILE_SIZE} bytes)"
echo ""
echo "To view the image: gpicview $TEST_FILE"
else
echo "❌ Capture failed. Check webcam connection and permissions."
exit 1
fi
exit 0
fi
# ==============================================================================
# Main Capture & Upload
# ==============================================================================
TEMP_FILE="${TEMP_DIR}/picupper_${CAMERA_ID}_$(date +%s).jpg"
# Check video device
if [[ ! -e "$VIDEO_DEVICE" ]]; then
log_error "Video device not found: $VIDEO_DEVICE"
exit 1
fi
# Fetch and apply camera settings from server
apply_camera_settings() {
# Check if v4l2-ctl is available
if ! command -v v4l2-ctl &>/dev/null; then
log "v4l2-ctl not installed, skipping camera settings"
return
fi
# Derive settings URL from upload URL (replace /upload with /settings)
local SETTINGS_URL="${API_URL%/upload}/settings/$CAMERA_ID"
log "Fetching camera settings from server..."
local SETTINGS_RESPONSE
SETTINGS_RESPONSE=$(curl -s --max-time 10 \
-H "X-API-Key: $API_KEY" \
"$SETTINGS_URL" 2>/dev/null) || true
if [[ -z "$SETTINGS_RESPONSE" ]]; then
log "Could not fetch settings, using camera defaults"
return
fi
# Check if server has custom settings (look for updatedAt field)
local has_custom_settings=false
if command -v jq &>/dev/null; then
local updated_at
updated_at=$(echo "$SETTINGS_RESPONSE" | jq -r '.settings.updatedAt // empty')
if [[ -n "$updated_at" && "$updated_at" != "null" ]]; then
has_custom_settings=true
fi
else
if echo "$SETTINGS_RESPONSE" | grep -q '"updatedAt"'; then
has_custom_settings=true
fi
fi
if [[ "$has_custom_settings" == "false" ]]; then
# No custom settings on server - upload current camera settings
log "No settings on server, uploading current camera settings..."
upload_current_settings
return
fi
# Apply settings from server
if command -v jq &>/dev/null; then
local settings
settings=$(echo "$SETTINGS_RESPONSE" | jq -r '.settings // empty')
if [[ -n "$settings" ]]; then
for ctrl in focus_automatic_continuous focus_absolute exposure_auto exposure_absolute brightness contrast; do
local value
value=$(echo "$settings" | jq -r ".$ctrl // empty")
if [[ -n "$value" && "$value" != "null" ]]; then
v4l2-ctl -d "$VIDEO_DEVICE" --set-ctrl="${ctrl}=${value}" 2>/dev/null || true
fi
done
log "Applied camera settings from server"
fi
else
for ctrl in focus_automatic_continuous focus_absolute exposure_auto exposure_absolute brightness contrast; do
local value
value=$(echo "$SETTINGS_RESPONSE" | grep -o "\"${ctrl}\":[0-9-]*" | cut -d: -f2)
if [[ -n "$value" ]]; then
v4l2-ctl -d "$VIDEO_DEVICE" --set-ctrl="${ctrl}=${value}" 2>/dev/null || true
fi
done
log "Applied camera settings from server"
fi
}
# Read current camera settings and upload to server
upload_current_settings() {
local SETTINGS_URL="${API_URL%/upload}/settings/$CAMERA_ID"
# Read current values from camera
local focus_auto focus_abs exp_auto exp_abs brightness contrast
focus_auto=$(v4l2-ctl -d "$VIDEO_DEVICE" --get-ctrl=focus_automatic_continuous 2>/dev/null | cut -d: -f2 | tr -d ' ') || focus_auto=""
focus_abs=$(v4l2-ctl -d "$VIDEO_DEVICE" --get-ctrl=focus_absolute 2>/dev/null | cut -d: -f2 | tr -d ' ') || focus_abs=""
exp_auto=$(v4l2-ctl -d "$VIDEO_DEVICE" --get-ctrl=exposure_auto 2>/dev/null | cut -d: -f2 | tr -d ' ') || exp_auto=""
exp_abs=$(v4l2-ctl -d "$VIDEO_DEVICE" --get-ctrl=exposure_absolute 2>/dev/null | cut -d: -f2 | tr -d ' ') || exp_abs=""
brightness=$(v4l2-ctl -d "$VIDEO_DEVICE" --get-ctrl=brightness 2>/dev/null | cut -d: -f2 | tr -d ' ') || brightness=""
contrast=$(v4l2-ctl -d "$VIDEO_DEVICE" --get-ctrl=contrast 2>/dev/null | cut -d: -f2 | tr -d ' ') || contrast=""
# Build JSON payload
local json_parts=()
[[ -n "$focus_auto" ]] && json_parts+=("\"focus_automatic_continuous\": $focus_auto")
[[ -n "$focus_abs" ]] && json_parts+=("\"focus_absolute\": $focus_abs")
[[ -n "$exp_auto" ]] && json_parts+=("\"exposure_auto\": $exp_auto")
[[ -n "$exp_abs" ]] && json_parts+=("\"exposure_absolute\": $exp_abs")
[[ -n "$brightness" ]] && json_parts+=("\"brightness\": $brightness")
[[ -n "$contrast" ]] && json_parts+=("\"contrast\": $contrast")
if [[ ${#json_parts[@]} -eq 0 ]]; then
log "Could not read camera settings"
return
fi
# Join with commas
local IFS=','
local json_body="{${json_parts[*]}}"
# Upload to server
local response
response=$(curl -s --max-time 10 \
-X PUT \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "$json_body" \
"$SETTINGS_URL" 2>/dev/null) || true
if echo "$response" | grep -q '"success"'; then
log "Uploaded current camera settings to server"
else
log "Failed to upload camera settings"
fi
}
apply_camera_settings
# Capture image
log "Capturing from $VIDEO_DEVICE ($RESOLUTION)"
if ! fswebcam -d "$VIDEO_DEVICE" -r "$RESOLUTION" -S "$SKIP_FRAMES" --no-banner "$TEMP_FILE" 2>/dev/null; then
log_error "Capture failed"
exit 1
fi
FILE_SIZE=$(stat -c%s "$TEMP_FILE" 2>/dev/null || echo "unknown")
log "Captured: $TEMP_FILE ($FILE_SIZE bytes)"
# Upload with retry
upload_success=false
attempt=1
while [[ $attempt -le $MAX_RETRIES ]]; do
log "Upload attempt $attempt/$MAX_RETRIES"
HTTP_RESPONSE=$(curl -s -w "\n%{http_code}" \
--max-time "$TIMEOUT" \
-X POST \
-H "X-API-Key: $API_KEY" \
-F "image=@$TEMP_FILE" \
-F "cameraId=$CAMERA_ID" \
"$API_URL" 2>/dev/null) || true
HTTP_CODE=$(echo "$HTTP_RESPONSE" | tail -n1)
RESPONSE_BODY=$(echo "$HTTP_RESPONSE" | sed '$d')
if [[ "$HTTP_CODE" == "200" ]]; then
log "Upload successful (HTTP $HTTP_CODE)"
upload_success=true
break
else
log_error "Upload failed (HTTP $HTTP_CODE): $RESPONSE_BODY"
if [[ $attempt -lt $MAX_RETRIES ]]; then
log "Retrying in $RETRY_DELAY seconds..."
sleep "$RETRY_DELAY"
fi
fi
((attempt++))
done
if [[ "$upload_success" != "true" ]]; then
log_error "All upload attempts failed"
exit 1
fi
log "Done"