#!/usr/bin/env bash set -euo pipefail NODE_JSON="/etc/flowercore/signage-node.json" CERT_DIR="/etc/fc-signage-player" SIGNAGE_URL="${FC_SIGNAGE_URL:-https://signage.iamworkin.lan}" NODE_ID=$(jq -r '.nodeId' "$NODE_JSON") CONNECTORS=() for dir in /sys/class/drm/card*-HDMI-A-*; do [[ -e "$dir/status" ]] || continue if [[ "$(cat "$dir/status")" == "connected" ]]; then CONNECTORS+=("$(basename "$dir")") fi done if [[ ${#CONNECTORS[@]} -eq 0 ]]; then CAPABILITIES_JSON=$(jq -n --arg id "$NODE_ID" '{ nodeId: $id, platform: "linux-arm64-pi", displayConnected: false, detectedAt: (now | todate), note: "No HDMI display detected" }') else PRIMARY="${CONNECTORS[0]}" EDID_PATH="/sys/class/drm/${PRIMARY}/edid" WIDTH=0 HEIGHT=0 REFRESH=60 HDR=false AUDIO_HDMI=false MFG="" MODEL="" PHYSICAL_SIZE=null if [[ -s "$EDID_PATH" ]] && command -v edid-decode >/dev/null 2>&1; then EDID_INFO=$(edid-decode < "$EDID_PATH" 2>/dev/null || true) MFG=$(echo "$EDID_INFO" | grep -m1 -oP 'Manufacturer:\s*\K\S+' || true) MODEL=$(echo "$EDID_INFO" | grep -m1 -oP 'Model:\s*\K\S+' || true) PREF=$(echo "$EDID_INFO" | grep -m1 -oP '\d+x\d+\s*@\s*\d+(?:\.\d+)?\s*Hz' || true) if [[ -n "$PREF" ]]; then WIDTH=$(echo "$PREF" | grep -oP '^\d+') HEIGHT=$(echo "$PREF" | grep -oP 'x\K\d+') REFRESH=$(echo "$PREF" | grep -oP '@\s*\K[\d.]+' | cut -d. -f1) fi if echo "$EDID_INFO" | grep -qiE 'HDR (Static|Dynamic) Metadata Block'; then HDR=true; fi if echo "$EDID_INFO" | grep -qiE 'CEA Audio Block|Audio Format Descriptor'; then AUDIO_HDMI=true; fi PH_W=$(echo "$EDID_INFO" | grep -m1 -oP 'Maximum image size:\s*\K\d+\s*cm\s*x\s*\d+' || true) if [[ -n "$PH_W" ]]; then PH_CM_W=$(echo "$PH_W" | grep -oP '^\d+') PH_CM_H=$(echo "$PH_W" | grep -oP 'x\s*\K\d+') if (( PH_CM_W > 0 && PH_CM_H > 0 )); then PHYSICAL_SIZE=$(awk -v w="$PH_CM_W" -v h="$PH_CM_H" 'BEGIN { printf "%.1f", sqrt(w*w + h*h)/2.54 }') fi fi fi if [[ "$WIDTH" == "0" ]] && command -v kmsprint >/dev/null 2>&1; then KMS=$(kmsprint 2>/dev/null | grep -A2 "$PRIMARY" | grep -oP '\d+x\d+' | head -1 || true) if [[ -n "$KMS" ]]; then WIDTH=$(echo "$KMS" | grep -oP '^\d+') HEIGHT=$(echo "$KMS" | grep -oP 'x\K\d+') fi fi AUDIO_ALSA=false if aplay -l 2>/dev/null | grep -qi 'card.*HDMI'; then AUDIO_ALSA=true; fi HAS_AUDIO=false if [[ "$AUDIO_HDMI" == "true" && "$AUDIO_ALSA" == "true" ]]; then HAS_AUDIO=true; fi CAPABILITIES_JSON=$(jq -n \ --arg id "$NODE_ID" \ --argjson w "$WIDTH" \ --argjson h "$HEIGHT" \ --argjson r "$REFRESH" \ --argjson hdr "$HDR" \ --argjson audio "$HAS_AUDIO" \ --arg connector "$PRIMARY" \ --arg mfg "$MFG" \ --arg model "$MODEL" \ --argjson size "$PHYSICAL_SIZE" \ '{ nodeId: $id, platform: "linux-arm64-pi", displayConnected: true, detectedAt: (now | todate), hardware: { maxResolution: { width: $w, height: $h }, nativeResolution: { width: $w, height: $h }, refreshRateHz: $r, colorDepth: ($hdr | if . then "Color30Hdr" else "Color24" end), hasAudioOutput: $audio, audioChannelCount: ($audio | if . then 2 else 0 end), physicalSizeInches: $size, connector: $connector, manufacturer: $mfg, modelName: $model }, render: { codecs: ["h264", "vp9", "mp4"] } }') fi ENDPOINT_CANDIDATES=( "${SIGNAGE_URL}/api/v1/nodes/${NODE_ID}/capabilities" "${SIGNAGE_URL}/api/v1/displays/${NODE_ID}/capability-profile" ) SUCCESS=false for url in "${ENDPOINT_CANDIDATES[@]}"; do HTTP_STATUS=$(curl -sk -o /tmp/cap-response.json -w "%{http_code}" \ --max-time 10 \ --cert "$CERT_DIR/client.crt" --key "$CERT_DIR/client.key" \ -X POST "$url" \ -H "Content-Type: application/json" \ -d "$CAPABILITIES_JSON" || echo "000") if [[ "$HTTP_STATUS" == "200" || "$HTTP_STATUS" == "201" || "$HTTP_STATUS" == "204" ]]; then SUCCESS=true break fi done mkdir -p /var/log/fc-signage-player if [[ "$SUCCESS" != "true" ]]; then echo "[$(date -Is)] capability declare: no endpoint accepted the profile; logging locally" \ | tee -a /var/log/fc-signage-player/capabilities.log echo "$CAPABILITIES_JSON" | tee -a /var/log/fc-signage-player/capabilities.log else echo "[$(date -Is)] capability declare: ok ($url)" | tee -a /var/log/fc-signage-player/capabilities.log fi echo "$CAPABILITIES_JSON"