This commit is contained in:
sebseb7
2025-12-21 22:48:26 +01:00
parent c90477aa52
commit bd6b20e6ed
8 changed files with 1209 additions and 142 deletions

View File

@@ -168,15 +168,136 @@ if [[ "$CAPTURE_METHOD" == "fswebcam" ]]; then
fi
fi
# Discover available v4l2 controls and report them to server
discover_and_report_controls() {
if ! command -v v4l2-ctl &>/dev/null; then
log "v4l2-ctl not installed, skipping control discovery"
return
fi
local AVAILABLE_URL="${API_URL%/upload}/settings/$CAMERA_ID/available"
log "Discovering available camera controls..."
# Parse v4l2-ctl -L output into JSON
# Example lines:
# brightness 0x00980900 (int) : min=-64 max=64 step=1 default=0 value=0
# exposure_auto 0x009a0901 (menu) : min=0 max=3 default=3 value=3
# 1: Manual Mode
# 3: Aperture Priority Mode
local controls_json="["
local current_values_json="{"
local first_control=true
local first_value=true
local current_ctrl=""
local ctrl_json=""
local menu_options=""
local in_menu=false
while IFS= read -r line || [[ -n "$line" ]]; do
# Check if this is a control line (starts with control name)
if [[ "$line" =~ ^[[:space:]]*([a-z_]+)[[:space:]]+0x[0-9a-f]+[[:space:]]+\(([a-z]+)\)[[:space:]]*:[[:space:]]*(.*) ]]; then
# Save previous control if exists
if [[ -n "$current_ctrl" ]]; then
if [[ "$in_menu" == "true" && -n "$menu_options" ]]; then
ctrl_json="${ctrl_json%, }, \"options\": {${menu_options%,}}}"
else
ctrl_json="${ctrl_json%,}}"
fi
if [[ "$first_control" == "true" ]]; then
first_control=false
else
controls_json+=","
fi
controls_json+="$ctrl_json"
fi
current_ctrl="${BASH_REMATCH[1]}"
local ctrl_type="${BASH_REMATCH[2]}"
local params="${BASH_REMATCH[3]}"
ctrl_json="{\"name\": \"$current_ctrl\", \"type\": \"$ctrl_type\","
menu_options=""
in_menu=false
# Parse parameters
if [[ "$params" =~ min=(-?[0-9]+) ]]; then
ctrl_json+=" \"min\": ${BASH_REMATCH[1]},"
fi
if [[ "$params" =~ max=(-?[0-9]+) ]]; then
ctrl_json+=" \"max\": ${BASH_REMATCH[1]},"
fi
if [[ "$params" =~ step=([0-9]+) ]]; then
ctrl_json+=" \"step\": ${BASH_REMATCH[1]},"
fi
if [[ "$params" =~ default=(-?[0-9]+) ]]; then
ctrl_json+=" \"default\": ${BASH_REMATCH[1]},"
fi
if [[ "$params" =~ value=(-?[0-9]+) ]]; then
local current_value="${BASH_REMATCH[1]}"
if [[ "$first_value" == "true" ]]; then
first_value=false
else
current_values_json+=","
fi
current_values_json+="\"$current_ctrl\": $current_value"
fi
if [[ "$ctrl_type" == "menu" ]]; then
in_menu=true
fi
# Check if this is a menu option line (indented with number: description)
elif [[ "$in_menu" == "true" && "$line" =~ ^[[:space:]]+([0-9]+):[[:space:]]+(.+)$ ]]; then
local opt_val="${BASH_REMATCH[1]}"
local opt_name="${BASH_REMATCH[2]}"
menu_options+="\"$opt_val\": \"$opt_name\","
fi
done < <(v4l2-ctl -d "$VIDEO_DEVICE" -L 2>/dev/null)
# Save last control
if [[ -n "$current_ctrl" ]]; then
if [[ "$in_menu" == "true" && -n "$menu_options" ]]; then
ctrl_json="${ctrl_json%, }, \"options\": {${menu_options%,}}}"
else
ctrl_json="${ctrl_json%,}}"
fi
if [[ "$first_control" != "true" ]]; then
controls_json+=","
fi
controls_json+="$ctrl_json"
fi
controls_json+="]"
current_values_json+="}"
# POST to server
local payload="{\"controls\": $controls_json, \"currentValues\": $current_values_json}"
local response
response=$(curl -s --max-time 10 \
-X POST \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "$payload" \
"$AVAILABLE_URL" 2>/dev/null) || true
if echo "$response" | grep -q '"success"'; then
local count
count=$(echo "$response" | grep -o '"controlsRegistered":[0-9]*' | cut -d: -f2)
log "Reported $count available controls to server"
else
log "Failed to report available controls: $response"
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..."
@@ -186,105 +307,67 @@ apply_camera_settings() {
"$SETTINGS_URL" 2>/dev/null) || true
if [[ -z "$SETTINGS_RESPONSE" ]]; then
log "Could not fetch settings, using camera defaults"
log "Could not fetch settings, discovering and reporting controls..."
discover_and_report_controls
return
fi
# Check if server has custom settings (look for updatedAt field)
local has_custom_settings=false
# Check if server has available controls registered
local has_controls=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
local ctrl_count
ctrl_count=$(echo "$SETTINGS_RESPONSE" | jq -r '.availableControls | length // 0')
if [[ "$ctrl_count" -gt 0 ]]; then
has_controls=true
fi
else
if echo "$SETTINGS_RESPONSE" | grep -q '"updatedAt"'; then
has_custom_settings=true
if echo "$SETTINGS_RESPONSE" | grep -q '"availableControls":\[{'; then
has_controls=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
if [[ "$has_controls" == "false" ]]; then
log "No controls registered, discovering and reporting..."
discover_and_report_controls
return
fi
# Apply settings from server
# Apply all values from server dynamically
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
local values
values=$(echo "$SETTINGS_RESPONSE" | jq -r '.values // {}')
local keys
keys=$(echo "$values" | jq -r 'keys[]' 2>/dev/null) || true
local applied=0
for ctrl in $keys; do
local value
value=$(echo "$values" | jq -r ".[\"$ctrl\"] // empty")
if [[ -n "$value" && "$value" != "null" ]]; then
if v4l2-ctl -d "$VIDEO_DEVICE" --set-ctrl="${ctrl}=${value}" 2>/dev/null; then
((applied++))
fi
fi
done
log "Applied $applied camera settings from server"
else
# Fallback: grep-based parsing for values
local values_block
values_block=$(echo "$SETTINGS_RESPONSE" | grep -o '"values":{[^}]*}' | sed 's/"values"://')
if [[ -n "$values_block" ]]; then
# Extract key:value pairs
while [[ "$values_block" =~ \"([a-z_]+)\":(-?[0-9]+) ]]; do
local ctrl="${BASH_REMATCH[1]}"
local value="${BASH_REMATCH[2]}"
v4l2-ctl -d "$VIDEO_DEVICE" --set-ctrl="${ctrl}=${value}" 2>/dev/null || true
values_block="${values_block#*${BASH_REMATCH[0]}}"
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
}
# Only handle settings upload/apply for fswebcam/v4l2 for now
# Only handle settings for fswebcam/v4l2
if [[ "$CAPTURE_METHOD" == "fswebcam" ]]; then
apply_camera_settings
fi