Tutorial

Nuevas actualizaciones y mejoras para Macfleet.

Aviso importante

Los ejemplos de código y scripts proporcionados en estos tutoriales son solo para propósitos educativos. Macfleet no es responsable de ningún problema, daño o vulnerabilidad de seguridad que pueda surgir del uso, modificación o implementación de estos ejemplos. Siempre revisa y prueba el código en un entorno seguro antes de usarlo en sistemas de producción.

Remote Ring and Device Location Management on macOS

Manage device location and audio alerts across your MacFleet devices with comprehensive remote ring functionality, location tracking, and enterprise device recovery solutions. This tutorial covers remote ring implementation, audio management, and fleet-wide device location services.

Understanding Remote Ring and Device Location

Remote ring functionality on macOS provides essential device location capabilities:

  • Audio Alerts - Playing sounds to help locate nearby devices
  • Device Location - Finding misplaced or lost devices in enterprise environments
  • Fleet Management - Centralized device tracking and recovery
  • Security Enhancement - Anti-theft and device recovery capabilities

Enterprise Use Cases

Remote ring and location services benefit enterprise environments:

  • Asset Recovery - Quickly locate misplaced devices in large offices
  • Security Response - Audio alerts for theft prevention and device recovery
  • Inventory Management - Track device locations during audits and transitions
  • Emergency Protocols - Locate devices during evacuations or emergencies
  • User Assistance - Help users find their devices without IT intervention

Basic Remote Ring Implementation

Simple Remote Ring Script

#!/bin/bash

# Basic remote ring implementation
basic_remote_ring() {
    local ring_count="${1:-5}"
    local sound_file="${2:-/System/Library/Sounds/Submarine.aiff}"
    
    echo "=== Basic Remote Ring ==="
    echo "Ring count: $ring_count"
    echo "Sound file: $sound_file"
    echo ""
    
    # Validate sound file exists
    if [[ ! -f "$sound_file" ]]; then
        echo "Error: Sound file not found: $sound_file"
        echo "Using default system sound..."
        sound_file="/System/Library/Sounds/Ping.aiff"
    fi
    
    # Execute remote ring
    local count=1
    while [[ $count -le $ring_count ]]; do
        echo "Playing ring $count of $ring_count"
        afplay "$sound_file"
        count=$(( count + 1 ))
        
        # Add small delay between rings for better audio separation
        sleep 1
    done
    
    echo "Remote ring completed: $ring_count rings played"
}

# Enhanced remote ring with validation
enhanced_remote_ring() {
    local ring_count="${1:-5}"
    local sound_file="${2:-/System/Library/Sounds/Submarine.aiff}"
    local volume_level="${3:-75}"
    
    echo "=== Enhanced Remote Ring ==="
    echo "Ring count: $ring_count"
    echo "Sound file: $sound_file"
    echo "Volume level: $volume_level%"
    echo ""
    
    # Set system volume
    osascript -e "set volume output volume $volume_level"
    
    # Validate parameters
    if [[ $ring_count -lt 1 || $ring_count -gt 50 ]]; then
        echo "Warning: Ring count should be between 1 and 50, using default of 5"
        ring_count=5
    fi
    
    # Play rings with enhanced feedback
    local count=1
    while [[ $count -le $ring_count ]]; do
        echo "Ring $count/$ring_count - $(date '+%H:%M:%S')"
        
        if afplay "$sound_file" 2>/dev/null; then
            echo "✓ Ring played successfully"
        else
            echo "✗ Failed to play ring"
        fi
        
        count=$(( count + 1 ))
        
        # Progressive delay (shorter for multiple rings)
        if [[ $ring_count -gt 1 ]]; then
            sleep 0.5
        fi
    done
    
    echo "Enhanced remote ring completed at $(date '+%H:%M:%S')"
}

# Usage examples
# basic_remote_ring 3
# enhanced_remote_ring 5 "/System/Library/Sounds/Glass.aiff" 80

Available System Sounds

#!/bin/bash

# List and test available system sounds
list_system_sounds() {
    echo "=== Available System Sounds ==="
    echo "Location: /System/Library/Sounds/"
    echo ""
    
    local sounds_dir="/System/Library/Sounds"
    
    if [[ -d "$sounds_dir" ]]; then
        echo "Available sound files:"
        ls -1 "$sounds_dir"/*.aiff 2>/dev/null | while read -r sound_file; do
            local sound_name=$(basename "$sound_file" .aiff)
            echo "  - $sound_name"
        done
    else
        echo "System sounds directory not found"
    fi
    
    echo ""
    echo "Popular choices for remote ring:"
    echo "  - Submarine.aiff (deep, attention-getting)"
    echo "  - Glass.aiff (clear, distinctive)"
    echo "  - Ping.aiff (sharp, noticeable)"
    echo "  - Sosumi.aiff (classic Mac sound)"
    echo "  - Purr.aiff (softer option)"
}

# Test specific sound file
test_sound_file() {
    local sound_file="$1"
    
    if [[ -z "$sound_file" ]]; then
        echo "Usage: test_sound_file <sound_file_path>"
        return 1
    fi
    
    echo "Testing sound file: $sound_file"
    
    if [[ -f "$sound_file" ]]; then
        echo "Playing test sound..."
        afplay "$sound_file"
        echo "✓ Sound test completed"
    else
        echo "✗ Sound file not found: $sound_file"
        return 1
    fi
}

# Usage
list_system_sounds

Volume and Audio Management

#!/bin/bash

# Manage system volume for remote ring
manage_system_volume() {
    local action="${1:-get}"
    local volume_level="${2:-50}"
    
    case "$action" in
        "get")
            echo "=== Current System Volume ==="
            local current_volume=$(osascript -e "output volume of (get volume settings)")
            echo "Current volume: $current_volume%"
            
            # Check if muted
            local mute_status=$(osascript -e "output muted of (get volume settings)")
            if [[ "$mute_status" == "true" ]]; then
                echo "Status: MUTED"
            else
                echo "Status: UNMUTED"
            fi
            ;;
        "set")
            echo "=== Setting System Volume ==="
            echo "Target volume: $volume_level%"
            
            # Unmute if muted
            osascript -e "set volume without output muted"
            
            # Set volume level
            osascript -e "set volume output volume $volume_level"
            
            echo "✓ Volume set to $volume_level%"
            ;;
        "mute")
            echo "=== Muting System ==="
            osascript -e "set volume with output muted"
            echo "✓ System muted"
            ;;
        "unmute")
            echo "=== Unmuting System ==="
            osascript -e "set volume without output muted"
            echo "✓ System unmuted"
            ;;
        "max")
            echo "=== Setting Maximum Volume ==="
            osascript -e "set volume without output muted"
            osascript -e "set volume output volume 100"
            echo "✓ Volume set to maximum (100%)"
            ;;
        *)
            echo "Usage: manage_system_volume [get|set|mute|unmute|max] [volume_level]"
            return 1
            ;;
    esac
}

# Emergency volume override for remote ring
emergency_volume_override() {
    echo "=== Emergency Volume Override ==="
    echo "Overriding all audio settings for maximum audibility"
    
    # Store current settings
    local current_volume=$(osascript -e "output volume of (get volume settings)")
    local current_mute=$(osascript -e "output muted of (get volume settings)")
    
    echo "Current settings saved - Volume: $current_volume%, Muted: $current_mute"
    
    # Set emergency volume
    osascript -e "set volume without output muted"
    osascript -e "set volume output volume 100"
    
    echo "✓ Emergency volume activated (100%, unmuted)"
    
    # Return function to restore settings
    echo "To restore previous settings, run:"
    echo "osascript -e \"set volume output volume $current_volume\""
    if [[ "$current_mute" == "true" ]]; then
        echo "osascript -e \"set volume with output muted\""
    fi
}

# Usage
manage_system_volume "get"

Advanced Remote Ring Features

Intelligent Remote Ring System

#!/bin/bash

# Intelligent remote ring with adaptive behavior
intelligent_remote_ring() {
    local ring_pattern="${1:-standard}"
    local duration="${2:-30}"
    local priority_level="${3:-normal}"
    
    echo "=== Intelligent Remote Ring System ==="
    echo "Pattern: $ring_pattern"
    echo "Duration: ${duration}s"
    echo "Priority: $priority_level"
    echo ""
    
    # Set volume based on priority
    case "$priority_level" in
        "low")
            local volume=40
            local sound="/System/Library/Sounds/Purr.aiff"
            ;;
        "normal")
            local volume=70
            local sound="/System/Library/Sounds/Submarine.aiff"
            ;;
        "high")
            local volume=85
            local sound="/System/Library/Sounds/Glass.aiff"
            ;;
        "emergency")
            local volume=100
            local sound="/System/Library/Sounds/Sosumi.aiff"
            emergency_volume_override
            ;;
        *)
            local volume=70
            local sound="/System/Library/Sounds/Submarine.aiff"
            ;;
    esac
    
    # Set system volume
    osascript -e "set volume output volume $volume"
    
    # Execute ring pattern
    case "$ring_pattern" in
        "standard")
            standard_ring_pattern "$duration" "$sound"
            ;;
        "pulse")
            pulse_ring_pattern "$duration" "$sound"
            ;;
        "escalating")
            escalating_ring_pattern "$duration" "$sound"
            ;;
        "morse_sos")
            morse_sos_pattern "$duration" "$sound"
            ;;
        "heartbeat")
            heartbeat_pattern "$duration" "$sound"
            ;;
        *)
            echo "Unknown pattern: $ring_pattern, using standard"
            standard_ring_pattern "$duration" "$sound"
            ;;
    esac
}

# Standard ring pattern
standard_ring_pattern() {
    local duration="$1"
    local sound="$2"
    local end_time=$(($(date +%s) + duration))
    
    echo "Playing standard ring pattern for ${duration}s"
    
    while [[ $(date +%s) -lt $end_time ]]; do
        afplay "$sound"
        sleep 2
    done
}

# Pulse ring pattern (quick bursts)
pulse_ring_pattern() {
    local duration="$1"
    local sound="$2"
    local end_time=$(($(date +%s) + duration))
    
    echo "Playing pulse ring pattern for ${duration}s"
    
    while [[ $(date +%s) -lt $end_time ]]; do
        # Triple pulse
        for i in {1..3}; do
            afplay "$sound" &
            sleep 0.3
        done
        sleep 2
    done
}

# Escalating ring pattern (increasing frequency)
escalating_ring_pattern() {
    local duration="$1"
    local sound="$2"
    local end_time=$(($(date +%s) + duration))
    local sleep_interval=3
    
    echo "Playing escalating ring pattern for ${duration}s"
    
    while [[ $(date +%s) -lt $end_time ]]; do
        afplay "$sound"
        sleep $sleep_interval
        
        # Decrease interval (increase frequency)
        if [[ $sleep_interval -gt 1 ]]; then
            sleep_interval=$((sleep_interval - 1))
        fi
    done
}

# Morse code SOS pattern
morse_sos_pattern() {
    local duration="$1"
    local sound="$2"
    local end_time=$(($(date +%s) + duration))
    
    echo "Playing Morse SOS pattern for ${duration}s"
    
    while [[ $(date +%s) -lt $end_time ]]; do
        # S (3 short)
        for i in {1..3}; do
            afplay "$sound" &
            sleep 0.2
            sleep 0.3
        done
        sleep 0.5
        
        # O (3 long)
        for i in {1..3}; do
            afplay "$sound" &
            sleep 0.6
            sleep 0.3
        done
        sleep 0.5
        
        # S (3 short)
        for i in {1..3}; do
            afplay "$sound" &
            sleep 0.2
            sleep 0.3
        done
        
        sleep 3
    done
}

# Heartbeat pattern
heartbeat_pattern() {
    local duration="$1"
    local sound="$2"
    local end_time=$(($(date +%s) + duration))
    
    echo "Playing heartbeat pattern for ${duration}s"
    
    while [[ $(date +%s) -lt $end_time ]]; do
        # Double beat
        afplay "$sound" &
        sleep 0.2
        afplay "$sound" &
        sleep 1.5
    done
}

# Usage examples
# intelligent_remote_ring "pulse" 30 "high"
# intelligent_remote_ring "morse_sos" 60 "emergency"

Location-Based Ring Management

#!/bin/bash

# Location-aware remote ring
location_based_ring() {
    local location_context="${1:-office}"
    local time_context="${2:-business_hours}"
    
    echo "=== Location-Based Ring Management ==="
    echo "Location context: $location_context"
    echo "Time context: $time_context"
    echo ""
    
    # Determine appropriate ring settings based on context
    case "$location_context" in
        "office")
            handle_office_environment "$time_context"
            ;;
        "meeting_room")
            handle_meeting_room_environment "$time_context"
            ;;
        "public_space")
            handle_public_space_environment "$time_context"
            ;;
        "home_office")
            handle_home_office_environment "$time_context"
            ;;
        "warehouse")
            handle_warehouse_environment "$time_context"
            ;;
        *)
            echo "Unknown location context, using default settings"
            intelligent_remote_ring "standard" 30 "normal"
            ;;
    esac
}

# Office environment settings
handle_office_environment() {
    local time_context="$1"
    
    echo "Configuring for office environment..."
    
    case "$time_context" in
        "business_hours")
            # Moderate volume, professional sound
            intelligent_remote_ring "standard" 20 "normal"
            ;;
        "after_hours")
            # Higher volume, more attention-getting
            intelligent_remote_ring "escalating" 45 "high"
            ;;
        "lunch_break")
            # Softer approach during break times
            intelligent_remote_ring "pulse" 25 "low"
            ;;
    esac
}

# Meeting room environment settings
handle_meeting_room_environment() {
    local time_context="$1"
    
    echo "Configuring for meeting room environment..."
    
    # Always use discrete settings in meeting areas
    intelligent_remote_ring "heartbeat" 15 "low"
}

# Public space environment settings
handle_public_space_environment() {
    local time_context="$1"
    
    echo "Configuring for public space environment..."
    
    # Discrete but effective
    intelligent_remote_ring "pulse" 30 "normal"
}

# Home office environment settings
handle_home_office_environment() {
    local time_context="$1"
    
    echo "Configuring for home office environment..."
    
    case "$time_context" in
        "business_hours")
            # Can be more assertive at home
            intelligent_remote_ring "escalating" 40 "high"
            ;;
        "evening")
            # Considerate of household
            intelligent_remote_ring "standard" 20 "low"
            ;;
    esac
}

# Warehouse environment settings
handle_warehouse_environment() {
    local time_context="$1"
    
    echo "Configuring for warehouse environment..."
    
    # Loud environment requires maximum volume
    intelligent_remote_ring "morse_sos" 60 "emergency"
}

# Usage
# location_based_ring "office" "business_hours"

Enterprise Remote Ring Management System

#!/bin/bash

# MacFleet Remote Ring and Device Location Management Tool
# Comprehensive device location, audio alerts, and fleet tracking

# Configuration
SCRIPT_VERSION="1.0.0"
LOG_FILE="/var/log/macfleet_remote_ring.log"
REPORT_DIR="/etc/macfleet/reports/location"
CONFIG_DIR="/etc/macfleet/location"
SOUND_DIR="/etc/macfleet/sounds"
POLICY_DIR="/etc/macfleet/policies/location"

# Create directories if they don't exist
mkdir -p "$REPORT_DIR" "$CONFIG_DIR" "$SOUND_DIR" "$POLICY_DIR"

# Ring policies for different scenarios
declare -A RING_POLICIES=(
    ["standard_office"]="volume:70,pattern:standard,duration:30,sound:submarine"
    ["quiet_environment"]="volume:40,pattern:pulse,duration:15,sound:purr"
    ["emergency_locate"]="volume:100,pattern:morse_sos,duration:120,sound:sosumi"
    ["meeting_room"]="volume:30,pattern:heartbeat,duration:10,sound:glass"
    ["warehouse_floor"]="volume:100,pattern:escalating,duration:60,sound:submarine"
    ["public_area"]="volume:60,pattern:pulse,duration:25,sound:ping"
    ["after_hours"]="volume:85,pattern:escalating,duration:45,sound:glass"
    ["healthcare_facility"]="volume:50,pattern:heartbeat,duration:20,sound:purr"
    ["education_campus"]="volume:65,pattern:standard,duration:30,sound:ping"
    ["retail_store"]="volume:75,pattern:pulse,duration:35,sound:submarine"
)

# Location tracking configurations
declare -A LOCATION_CONFIGS=(
    ["high_security"]="gps_tracking,wifi_triangulation,bluetooth_beacons,audit_logging"
    ["standard_office"]="wifi_tracking,bluetooth_detection,basic_logging"
    ["public_access"]="limited_tracking,privacy_compliant,minimal_logging"
    ["healthcare"]="hipaa_compliant,secure_tracking,encrypted_logs,audit_trail"
    ["education"]="ferpa_compliant,student_privacy,controlled_tracking,parent_notification"
    ["retail"]="customer_privacy,basic_tracking,loss_prevention,inventory_integration"
)

# Emergency response levels
declare -A EMERGENCY_LEVELS=(
    ["green"]="normal_operation,standard_ring,basic_logging"
    ["yellow"]="elevated_response,enhanced_ring,increased_logging"
    ["orange"]="urgent_response,emergency_ring,comprehensive_logging"
    ["red"]="critical_response,maximum_ring,full_audit_trail"
)

# Logging function
log_action() {
    local message="$1"
    local severity="${2:-INFO}"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo "[$timestamp] [$severity] $message" | tee -a "$LOG_FILE"
}

# Enterprise remote ring with full management
enterprise_remote_ring() {
    local device_id="${1:-$(hostname)}"
    local ring_policy="${2:-standard_office}"
    local location_context="${3:-office}"
    local emergency_level="${4:-green}"
    local initiated_by="${5:-$(whoami)}"
    
    log_action "Starting enterprise remote ring" "INFO"
    log_action "Device: $device_id, Policy: $ring_policy, Context: $location_context" "INFO"
    
    echo "=== Enterprise Remote Ring Management ==="
    echo "Device ID: $device_id"
    echo "Ring Policy: $ring_policy"
    echo "Location Context: $location_context"
    echo "Emergency Level: $emergency_level"
    echo "Initiated By: $initiated_by"
    echo "Ring ID: $(uuidgen)"
    echo ""
    
    # Parse ring policy
    local policy_settings="${RING_POLICIES[$ring_policy]}"
    if [[ -z "$policy_settings" ]]; then
        log_action "Unknown ring policy: $ring_policy, using standard_office" "WARNING"
        policy_settings="${RING_POLICIES[standard_office]}"
    fi
    
    # Extract policy parameters
    local volume=$(echo "$policy_settings" | grep -o 'volume:[0-9]*' | cut -d: -f2)
    local pattern=$(echo "$policy_settings" | grep -o 'pattern:[^,]*' | cut -d: -f2)
    local duration=$(echo "$policy_settings" | grep -o 'duration:[0-9]*' | cut -d: -f2)
    local sound=$(echo "$policy_settings" | grep -o 'sound:[^,]*' | cut -d: -f2)
    
    echo "--- Policy Configuration ---"
    echo "Volume: $volume%"
    echo "Pattern: $pattern"
    echo "Duration: ${duration}s"
    echo "Sound: $sound"
    
    # Apply emergency level modifications
    apply_emergency_modifications "$emergency_level" volume pattern duration
    
    # Execute pre-ring checks
    if ! pre_ring_validation "$device_id" "$location_context"; then
        log_action "Pre-ring validation failed" "ERROR"
        return 1
    fi
    
    # Record ring initiation
    record_ring_event "$device_id" "$ring_policy" "$location_context" "$initiated_by" "started"
    
    # Execute ring based on policy
    execute_policy_ring "$volume" "$pattern" "$duration" "$sound"
    
    # Record ring completion
    record_ring_event "$device_id" "$ring_policy" "$location_context" "$initiated_by" "completed"
    
    # Generate location report
    generate_location_report "$device_id" "$ring_policy" "$location_context"
    
    log_action "remote ring completed for device: $device_id" "INFO"
}

# Apply emergency level modifications
apply_emergency_modifications() {
    local emergency_level="$1"
    local -n vol_ref=$2
    local -n pat_ref=$3
    local -n dur_ref=$4
    
    echo "--- Emergency Level: $emergency_level ---"
    
    case "$emergency_level" in
        "yellow")
            vol_ref=$((vol_ref + 15))
            dur_ref=$((dur_ref + 10))
            echo "Enhanced response: Volume +15%, Duration +10s"
            ;;
        "orange")
            vol_ref=$((vol_ref + 25))
            dur_ref=$((dur_ref + 20))
            pat_ref="escalating"
            echo "Urgent response: Volume +25%, Duration +20s, Escalating pattern"
            ;;
        "red")
            vol_ref=100
            dur_ref=$((dur_ref * 2))
            pat_ref="morse_sos"
            echo "Critical response: Maximum volume, Double duration, SOS pattern"
            ;;
    esac
    
    # Cap volume at 100%
    if [[ $vol_ref -gt 100 ]]; then
        vol_ref=100
    fi
}

# Pre-ring validation
pre_ring_validation() {
    local device_id="$1"
    local location_context="$2"
    
    echo "--- Pre-Ring Validation ---"
    
    # Check audio system availability
    if ! command -v afplay >/dev/null 2>&1; then
        echo "✗ Audio system not available"
        log_action "Audio system check failed" "ERROR"
        return 1
    fi
    
    # Check if device is in do-not-disturb mode
    local dnd_status=$(defaults read ~/Library/Preferences/ByHost/com.apple.notificationcenterui.* doNotDisturb 2>/dev/null || echo "0")
    if [[ "$dnd_status" == "1" ]]; then
        echo "⚠️ Device is in Do Not Disturb mode"
        log_action "Device in DND mode - ring may be muted" "WARNING"
    fi
    
    # Check system volume
    local current_volume=$(osascript -e "output volume of (get volume settings)" 2>/dev/null || echo "50")
    echo "Current system volume: $current_volume%"
    
    # Check if muted
    local mute_status=$(osascript -e "output muted of (get volume settings)" 2>/dev/null || echo "false")
    if [[ "$mute_status" == "true" ]]; then
        echo "⚠️ System is currently muted"
        log_action "System muted - will override for ring" "WARNING"
    fi
    
    # Location-specific validations
    case "$location_context" in
        "meeting_room")
            echo "Meeting room context - using discrete settings"
            ;;
        "healthcare_facility")
            echo "Healthcare context - ensuring HIPAA compliance"
            ;;
        "education_campus")
            echo "Education context - ensuring appropriate volume levels"
            ;;
    esac
    
    echo "✓ Pre-ring validation completed"
    return 0
}

# Execute ring based on policy
execute_policy_ring() {
    local volume="$1"
    local pattern="$2"
    local duration="$3"
    local sound="$4"
    
    echo "--- Executing Ring ---"
    
    # Map sound name to file path
    local sound_file="/System/Library/Sounds/Submarine.aiff"  # Default
    case "$sound" in
        "submarine") sound_file="/System/Library/Sounds/Submarine.aiff" ;;
        "glass") sound_file="/System/Library/Sounds/Glass.aiff" ;;
        "ping") sound_file="/System/Library/Sounds/Ping.aiff" ;;
        "sosumi") sound_file="/System/Library/Sounds/Sosumi.aiff" ;;
        "purr") sound_file="/System/Library/Sounds/Purr.aiff" ;;
    esac
    
    # Store current audio settings
    local original_volume=$(osascript -e "output volume of (get volume settings)" 2>/dev/null || echo "50")
    local original_mute=$(osascript -e "output muted of (get volume settings)" 2>/dev/null || echo "false")
    
    # Set ring volume and unmute
    osascript -e "set volume without output muted" 2>/dev/null
    osascript -e "set volume output volume $volume" 2>/dev/null
    
    echo "Ring settings: Volume $volume%, Pattern $pattern, Duration ${duration}s"
    echo "Start time: $(date '+%H:%M:%S')"
    
    # Execute ring pattern
    case "$pattern" in
        "standard")
            standard_ring_pattern "$duration" "$sound_file"
            ;;
        "pulse")
            pulse_ring_pattern "$duration" "$sound_file"
            ;;
        "escalating")
            escalating_ring_pattern "$duration" "$sound_file"
            ;;
        "morse_sos")
            morse_sos_pattern "$duration" "$sound_file"
            ;;
        "heartbeat")
            heartbeat_pattern "$duration" "$sound_file"
            ;;
    esac
    
    echo "End time: $(date '+%H:%M:%S')"
    
    # Restore original audio settings
    osascript -e "set volume output volume $original_volume" 2>/dev/null
    if [[ "$original_mute" == "true" ]]; then
        osascript -e "set volume with output muted" 2>/dev/null
    fi
    
    echo "✓ Original audio settings restored"
}

# Record ring events for audit trail
record_ring_event() {
    local device_id="$1"
    local ring_policy="$2"
    local location_context="$3"
    local initiated_by="$4"
    local event_type="$5"
    
    local timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
    local event_file="$CONFIG_DIR/ring_events.log"
    
    echo "$timestamp,$device_id,$ring_policy,$location_context,$initiated_by,$event_type" >> "$event_file"
    
    log_action "Ring event recorded: $event_type for device $device_id" "INFO"
}

# Generate comprehensive location report
generate_location_report() {
    local device_id="$1"
    local ring_policy="$2"
    local location_context="$3"
    
    local report_file="$REPORT_DIR/location_report_${device_id}_$(date +%Y%m%d_%H%M%S).json"
    
    # Get system location information (if available)
    local wifi_network=$(networksetup -getairportnetwork en0 2>/dev/null | cut -d: -f2 | sed 's/^ *//' || echo "Unknown")
    local ip_address=$(ifconfig en0 | grep "inet " | awk '{print $2}' || echo "Unknown")
    
    cat > "$report_file" << EOF
{
    "location_report": {
        "report_metadata": {
            "report_id": "$(uuidgen)",
            "generated_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
            "device_id": "$device_id",
            "hostname": "$(hostname)",
            "script_version": "$SCRIPT_VERSION"
        },
        "ring_details": {
            "ring_policy": "$ring_policy",
            "location_context": "$location_context",
            "execution_timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
        },
        "location_information": {
            "wifi_network": "$wifi_network",
            "ip_address": "$ip_address",
            "system_timezone": "$(date +%Z)",
            "estimated_location": "$location_context"
        },
        "system_information": {
            "os_version": "$(sw_vers -productVersion)",
            "hardware_model": "$(system_profiler SPHardwareDataType | grep 'Model Identifier' | awk '{print $3}')",
            "audio_devices": "$(system_profiler SPAudioDataType | grep -A1 'Audio Devices:' | tail -1 | sed 's/^[ ]*//')"
        }
    }
}
EOF
    
    echo "Location report generated: $report_file"
    log_action "Location report generated: $report_file" "INFO"
}

# Fleet ring management
fleet_ring_management() {
    local operation="$1"
    local device_list="$2"
    local ring_policy="${3:-standard_office}"
    local emergency_level="${4:-green}"
    
    echo "=== Fleet Ring Management ==="
    echo "Operation: $operation"
    echo "Ring Policy: $ring_policy"
    echo "Emergency Level: $emergency_level"
    echo ""
    
    case "$operation" in
        "mass_ring")
            echo "Executing mass ring operation..."
            IFS=',' read -ra DEVICES <<< "$device_list"
            for device in "${DEVICES[@]}"; do
                echo "Ringing device: $device"
                enterprise_remote_ring "$device" "$ring_policy" "office" "$emergency_level"
                sleep 2  # Delay between devices
            done
            ;;
        "emergency_locate")
            echo "Emergency location protocol activated..."
            enterprise_remote_ring "$(hostname)" "emergency_locate" "unknown" "red"
            ;;
        "zone_ring")
            echo "Zone-based ring operation..."
            # Implementation for zone-based ringing
            ;;
        *)
            echo "Unknown operation: $operation"
            return 1
            ;;
    esac
}

# Main execution function
main() {
    local action="${1:-help}"
    local param1="${2:-}"
    local param2="${3:-}"
    local param3="${4:-}"
    local param4="${5:-}"
    local param5="${6:-}"
    
    log_action "=== MacFleet Remote Ring Management Started ===" "INFO"
    log_action "Action: $action" "INFO"
    
    case "$action" in
        "ring")
            if [[ -z "$param1" ]]; then
                param1="$(hostname)"
            fi
            enterprise_remote_ring "$param1" "$param2" "$param3" "$param4" "$param5"
            ;;
        "emergency")
            echo "Emergency ring activated for current device"
            enterprise_remote_ring "$(hostname)" "emergency_locate" "unknown" "red" "$(whoami)"
            ;;
        "test")
            echo "Testing audio system..."
            test_sound_file "/System/Library/Sounds/Ping.aiff"
            ;;
        "volume")
            if [[ -z "$param1" ]]; then
                manage_system_volume "get"
            else
                manage_system_volume "$param1" "$param2"
            fi
            ;;
        "sounds")
            list_system_sounds
            ;;
        "fleet")
            if [[ -z "$param1" ]]; then
                echo "Usage: $0 fleet <operation> [device_list] [policy] [emergency_level]"
                echo "Operations: mass_ring, emergency_locate, zone_ring"
                exit 1
            fi
            fleet_ring_management "$param1" "$param2" "$param3" "$param4"
            ;;
        "help")
            echo "Usage: $0 [action] [options...]"
            echo "Actions:"
            echo "  ring [device_id] [policy] [location] [emergency_level] [initiated_by] - Execute remote ring"
            echo "  emergency - Emergency ring for current device"
            echo "  test - Test audio system"
            echo "  volume [action] [level] - Manage system volume"
            echo "  sounds - List available system sounds"
            echo "  fleet <operation> [device_list] [policy] [emergency_level] - Fleet operations"
            echo "  help - Show this help"
            echo ""
            echo "Ring Policies: ${!RING_POLICIES[*]}"
            echo "Emergency Levels: ${!EMERGENCY_LEVELS[*]}"
            ;;
        *)
            log_action "ERROR: Unknown action: $action" "ERROR"
            echo "Use '$0 help' for usage information"
            exit 1
            ;;
    esac
    
    log_action "=== Remote ring management completed ===" "INFO"
}

# Execute main function
main "$@"

Important Considerations

Audio System Requirements

  • afplay Command - macOS built-in audio player for sound file playback
  • System Sounds - Located in /System/Library/Sounds/ directory
  • Volume Control - Uses AppleScript for system volume management
  • Audio Permissions - Some features may require audio input/output permissions

Enterprise Deployment Notes

  • Network Latency - Remote ring commands may have network delays
  • Device States - Devices may be sleeping, muted, or in do-not-disturb mode
  • Privacy Compliance - Location tracking must comply with privacy regulations
  • Emergency Protocols - Emergency rings should override normal volume restrictions
  • Fleet Coordination - Mass ring operations should be staggered to avoid conflicts

Security Considerations

  • Access Control - Ring functionality should be restricted to authorized administrators
  • Audit Logging - All ring operations should be logged for security and compliance
  • Location Privacy - Device location information must be handled according to privacy policies
  • Emergency Override - Emergency situations may require bypassing normal restrictions

Tutorial

Nuevas actualizaciones y mejoras para Macfleet.

Configurando un Runner de GitHub Actions en un Mac Mini (Apple Silicon)

Runner de GitHub Actions

GitHub Actions es una plataforma poderosa de CI/CD que te permite automatizar tus flujos de trabajo de desarrollo de software. Aunque GitHub ofrece runners hospedados, los runners auto-hospedados proporcionan mayor control y personalización para tu configuración de CI/CD. Este tutorial te guía a través de la configuración y conexión de un runner auto-hospedado en un Mac mini para ejecutar pipelines de macOS.

Prerrequisitos

Antes de comenzar, asegúrate de tener:

  • Un Mac mini (regístrate en Macfleet)
  • Un repositorio de GitHub con derechos de administrador
  • Un gestor de paquetes instalado (preferiblemente Homebrew)
  • Git instalado en tu sistema

Paso 1: Crear una Cuenta de Usuario Dedicada

Primero, crea una cuenta de usuario dedicada para el runner de GitHub Actions:

# Crear la cuenta de usuario 'gh-runner'
sudo dscl . -create /Users/gh-runner
sudo dscl . -create /Users/gh-runner UserShell /bin/bash
sudo dscl . -create /Users/gh-runner RealName "GitHub runner"
sudo dscl . -create /Users/gh-runner UniqueID "1001"
sudo dscl . -create /Users/gh-runner PrimaryGroupID 20
sudo dscl . -create /Users/gh-runner NFSHomeDirectory /Users/gh-runner

# Establecer la contraseña para el usuario
sudo dscl . -passwd /Users/gh-runner tu_contraseña

# Agregar 'gh-runner' al grupo 'admin'
sudo dscl . -append /Groups/admin GroupMembership gh-runner

Cambia a la nueva cuenta de usuario:

su gh-runner

Paso 2: Instalar Software Requerido

Instala Git y Rosetta 2 (si usas Apple Silicon):

# Instalar Git si no está ya instalado
brew install git

# Instalar Rosetta 2 para Macs Apple Silicon
softwareupdate --install-rosetta

Paso 3: Configurar el Runner de GitHub Actions

  1. Ve a tu repositorio de GitHub
  2. Navega a Configuración > Actions > Runners

Runner de GitHub Actions

  1. Haz clic en "New self-hosted runner" (https://github.com/<username>/<repository>/settings/actions/runners/new)
  2. Selecciona macOS como imagen del runner y ARM64 como arquitectura
  3. Sigue los comandos proporcionados para descargar y configurar el runner

Runner de GitHub Actions

Crea un archivo .env en el directorio _work del runner:

# archivo _work/.env
ImageOS=macos15
XCODE_15_DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
  1. Ejecuta el script run.sh en tu directorio del runner para completar la configuración.
  2. Verifica que el runner esté activo y escuchando trabajos en la terminal y revisa la configuración del repositorio de GitHub para la asociación del runner y el estado Idle.

Runner de GitHub Actions

Paso 4: Configurar Sudoers (Opcional)

Si tus acciones requieren privilegios de root, configura el archivo sudoers:

sudo visudo

Agrega la siguiente línea:

gh-runner ALL=(ALL) NOPASSWD: ALL

Paso 5: Usar el Runner en Flujos de Trabajo

Configura tu flujo de trabajo de GitHub Actions para usar el runner auto-hospedado:

name: Flujo de trabajo de muestra

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: [self-hosted, macOS, ARM64]
    steps:
      - name: Instalar NodeJS
        run: brew install node

El runner está autenticado en tu repositorio y etiquetado con self-hosted, macOS, y ARM64. Úsalo en tus flujos de trabajo especificando estas etiquetas en el campo runs-on:

runs-on: [self-hosted, macOS, ARM64]

Mejores Prácticas

  • Mantén tu software del runner actualizado
  • Monitorea regularmente los logs del runner para problemas
  • Usa etiquetas específicas para diferentes tipos de runners
  • Implementa medidas de seguridad apropiadas
  • Considera usar múltiples runners para balanceo de carga

Solución de Problemas

Problemas comunes y soluciones:

  1. Runner no conectando:

    • Verifica conectividad de red
    • Verifica validez del token de GitHub
    • Asegúrate de permisos apropiados
  2. Fallas de construcción:

    • Verifica instalación de Xcode
    • Verifica dependencias requeridas
    • Revisa logs del flujo de trabajo
  3. Problemas de permisos:

    • Verifica permisos de usuario
    • Verifica configuración de sudoers
    • Revisa permisos del sistema de archivos

Conclusión

Ahora tienes un runner auto-hospedado de GitHub Actions configurado en tu Mac mini. Esta configuración te proporciona más control sobre tu entorno de CI/CD y te permite ejecutar flujos de trabajo específicos de macOS de manera eficiente.

Recuerda mantener regularmente tu runner y mantenerlo actualizado con los últimos parches de seguridad y versiones de software.

Aplicación Nativa

Aplicación nativa de Macfleet

Guía de Instalación de Macfleet

Macfleet es una solución poderosa de gestión de flota diseñada específicamente para entornos de Mac Mini alojados en la nube. Como proveedor de hosting en la nube de Mac Mini, puedes usar Macfleet para monitorear, gestionar y optimizar toda tu flota de instancias Mac virtualizadas.

Esta guía de instalación te llevará a través de la configuración del monitoreo de Macfleet en sistemas macOS, Windows y Linux para asegurar una supervisión integral de tu infraestructura en la nube.

🍎 macOS

  • Descarga el archivo .dmg para Mac aquí
  • Haz doble clic en el archivo .dmg descargado
  • Arrastra la aplicación Macfleet a la carpeta Aplicaciones
  • Expulsa el archivo .dmg
  • Abre Preferencias del Sistema > Seguridad y Privacidad
    • Pestaña Privacidad > Accesibilidad
    • Marca Macfleet para permitir el monitoreo
  • Inicia Macfleet desde Aplicaciones
  • El seguimiento comienza automáticamente

🪟 Windows

  • Descarga el archivo .exe para Windows aquí
  • Haz clic derecho en el archivo .exe > "Ejecutar como administrador"
  • Sigue el asistente de instalación
  • Acepta los términos y condiciones
  • Permite en Windows Defender si se solicita
  • Concede permisos de monitoreo de aplicaciones
  • Inicia Macfleet desde el Menú Inicio
  • La aplicación comienza el seguimiento automáticamente

🐧 Linux

  • Descarga el paquete .deb (Ubuntu/Debian) o .rpm (CentOS/RHEL) aquí
  • Instala usando tu gestor de paquetes
    • Ubuntu/Debian: sudo dpkg -i Macfleet-linux.deb
    • CentOS/RHEL: sudo rpm -ivh Macfleet-linux.rpm
  • Permite permisos de acceso X11 si se solicita
  • Agrega el usuario a los grupos apropiados si es necesario
  • Inicia Macfleet desde el menú de Aplicaciones
  • La aplicación comienza el seguimiento automáticamente

Nota: Después de la instalación en todos los sistemas, inicia sesión con tus credenciales de Macfleet para sincronizar datos con tu panel de control.