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.

Battery Charging Limit Management on macOS

Manage battery charging limits across your MacFleet devices to optimize battery health and implement enterprise power management policies. This tutorial covers installation of battery management tools, charging limit configuration, persistence settings, and comprehensive fleet-wide battery health monitoring.

Understanding Battery Charging Limits

Battery charging limits help preserve battery health by preventing overcharging, especially beneficial for devices that remain plugged in continuously:

Why Set Charging Limits?

  • Battery Longevity - Prevents degradation from constant 100% charge
  • Heat Reduction - Lower charge levels generate less heat during operation
  • Enterprise Cost Savings - Extended battery life reduces replacement costs
  • Power Management - Optimized charging for stationary workstations
  • Environmental Benefits - Longer battery life reduces electronic waste

Battery Management Tools

  • bclm - Battery Charge Limit Max (primary tool)
  • SMC - System Management Controller (hardware interface)
  • Homebrew - Package manager for macOS tools
  • Power Management - Built-in macOS power controls

Prerequisites and Installation

Install Homebrew Package Manager

#!/bin/bash

# Install Homebrew package manager
echo "🍺 Installing Homebrew package manager..."

# Check if Homebrew is already installed
if command -v brew >/dev/null 2>&1; then
    echo "ℹ️ Homebrew is already installed"
    echo "Homebrew version: $(brew --version | head -1)"
else
    echo "Installing Homebrew..."
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    
    if [[ $? -eq 0 ]]; then
        echo "✅ Homebrew installed successfully"
    else
        echo "❌ Homebrew installation failed"
        exit 1
    fi
fi

# Verify installation and add to PATH if needed
if [[ -f /opt/homebrew/bin/brew ]]; then
    echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
    eval "$(/opt/homebrew/bin/brew shellenv)"
elif [[ -f /usr/local/bin/brew ]]; then
    echo 'eval "$(/usr/local/bin/brew shellenv)"' >> ~/.zprofile
    eval "$(/usr/local/bin/brew shellenv)"
fi

echo "Homebrew location: $(which brew)"

Install BCLM (Battery Charge Limit Max)

#!/bin/bash

# Install bclm (Battery Charge Limit Max)
echo "🔋 Installing bclm (Battery Charge Limit Max)..."

# Ensure Homebrew is available
if ! command -v brew >/dev/null 2>&1; then
    echo "❌ Homebrew not found. Please install Homebrew first."
    exit 1
fi

# Install bclm
echo "Adding zackelia/formulae tap..."
if brew tap zackelia/formulae; then
    echo "✅ Tap added successfully"
else
    echo "❌ Failed to add tap"
    exit 1
fi

echo "Installing bclm..."
if brew install bclm; then
    echo "✅ bclm installed successfully"
else
    echo "❌ bclm installation failed"
    exit 1
fi

# Verify installation
if command -v bclm >/dev/null 2>&1; then
    echo "bclm location: $(which bclm)"
    echo "Testing bclm access..."
    
    # Test read access (doesn't require sudo)
    if bclm read >/dev/null 2>&1; then
        echo "✅ bclm is working correctly"
        echo "Current charging limit: $(bclm read)%"
    else
        echo "⚠️ bclm installed but may require additional permissions"
    fi
else
    echo "❌ bclm not found in PATH"
    exit 1
fi

Basic Charging Limit Management

Set Charging Limit

#!/bin/bash

# Set battery charging limit
LIMIT="$1"

if [[ -z "$LIMIT" ]]; then
    echo "❌ Usage: $0 <percentage>"
    echo "Example: $0 80"
    echo "Valid range: 50-100"
    exit 1
fi

# Validate limit range
if [[ "$LIMIT" -lt 50 || "$LIMIT" -gt 100 ]]; then
    echo "❌ Invalid limit: $LIMIT"
    echo "Charging limit must be between 50% and 100%"
    exit 1
fi

echo "🔋 Setting battery charging limit to $LIMIT%..."

# Get current limit for comparison
CURRENT_LIMIT=$(bclm read 2>/dev/null)
if [[ -n "$CURRENT_LIMIT" ]]; then
    echo "Current limit: $CURRENT_LIMIT%"
fi

# Set new charging limit
if sudo bclm write "$LIMIT"; then
    echo "✅ Charging limit set to $LIMIT%"
    
    # Verify the setting
    NEW_LIMIT=$(bclm read 2>/dev/null)
    if [[ "$NEW_LIMIT" == "$LIMIT" ]]; then
        echo "✅ Setting verified: $NEW_LIMIT%"
    else
        echo "⚠️ Warning: Verification shows $NEW_LIMIT% instead of $LIMIT%"
    fi
else
    echo "❌ Failed to set charging limit"
    exit 1
fi

echo "ℹ️ Note: Restart may be required for changes to take effect"

Read Current Charging Limit

#!/bin/bash

# Read current battery charging limit
echo "🔍 Reading current battery charging limit..."

if command -v bclm >/dev/null 2>&1; then
    CURRENT_LIMIT=$(bclm read 2>/dev/null)
    
    if [[ -n "$CURRENT_LIMIT" ]]; then
        echo "Current charging limit: $CURRENT_LIMIT%"
        
        # Provide context about the limit
        if [[ "$CURRENT_LIMIT" -eq 100 ]]; then
            echo "ℹ️ Battery charges to maximum capacity (no limit set)"
        elif [[ "$CURRENT_LIMIT" -ge 80 ]]; then
            echo "ℹ️ Conservative charging limit for battery longevity"
        elif [[ "$CURRENT_LIMIT" -ge 60 ]]; then
            echo "ℹ️ Moderate charging limit for extended battery life"
        else
            echo "ℹ️ Aggressive charging limit for maximum battery preservation"
        fi
    else
        echo "❌ Unable to read charging limit"
        echo "This may indicate bclm is not properly installed or lacks permissions"
        exit 1
    fi
else
    echo "❌ bclm not found. Please install bclm first."
    exit 1
fi

Make Charging Limit Persistent

#!/bin/bash

# Make charging limit persistent across reboots
echo "💾 Making charging limit persistent..."

if ! command -v bclm >/dev/null 2>&1; then
    echo "❌ bclm not found. Please install bclm first."
    exit 1
fi

# Get current limit
CURRENT_LIMIT=$(bclm read 2>/dev/null)
if [[ -z "$CURRENT_LIMIT" ]]; then
    echo "❌ Unable to read current charging limit"
    exit 1
fi

echo "Current charging limit: $CURRENT_LIMIT%"

# Make persistent
if sudo bclm persist; then
    echo "✅ Charging limit ($CURRENT_LIMIT%) is now persistent"
    echo "The limit will be maintained across system reboots"
else
    echo "❌ Failed to make charging limit persistent"
    exit 1
fi

echo "ℹ️ To remove persistence, run: sudo bclm unpersist"

Remove Charging Limit Persistence

#!/bin/bash

# Remove charging limit persistence
echo "🔄 Removing charging limit persistence..."

if ! command -v bclm >/dev/null 2>&1; then
    echo "❌ bclm not found. Please install bclm first."
    exit 1
fi

# Get current limit before removing persistence
CURRENT_LIMIT=$(bclm read 2>/dev/null)
if [[ -n "$CURRENT_LIMIT" ]]; then
    echo "Current charging limit: $CURRENT_LIMIT%"
fi

# Remove persistence
if sudo bclm unpersist; then
    echo "✅ Charging limit persistence removed"
    echo "The limit may reset to 100% after next reboot"
else
    echo "❌ Failed to remove charging limit persistence"
    exit 1
fi

echo "ℹ️ To restore persistence, run: sudo bclm persist"

Advanced Battery Management

Enterprise Battery Health Check

#!/bin/bash

# Comprehensive battery health assessment
echo "🔋 Performing comprehensive battery health check..."

# Check if battery is present
if ! system_profiler SPPowerDataType | grep -q "Battery Information"; then
    echo "❌ No battery found on this system"
    exit 1
fi

echo "=== Battery Health Assessment ==="

# Get battery information
BATTERY_INFO=$(system_profiler SPPowerDataType)

# Extract key metrics
CYCLE_COUNT=$(echo "$BATTERY_INFO" | grep "Cycle Count" | awk '{print $3}')
CONDITION=$(echo "$BATTERY_INFO" | grep "Condition" | awk '{print $2}')
MAX_CAPACITY=$(echo "$BATTERY_INFO" | grep "Maximum Capacity" | awk '{print $3}' | sed 's/%//')

echo "Battery Condition: $CONDITION"
echo "Cycle Count: $CYCLE_COUNT"
echo "Maximum Capacity: $MAX_CAPACITY%"

# Check charging limit if bclm is available
if command -v bclm >/dev/null 2>&1; then
    CHARGING_LIMIT=$(bclm read 2>/dev/null)
    if [[ -n "$CHARGING_LIMIT" ]]; then
        echo "Charging Limit: $CHARGING_LIMIT%"
    else
        echo "Charging Limit: Not set (100%)"
    fi
fi

# Power adapter information
POWER_ADAPTER=$(echo "$BATTERY_INFO" | grep -A5 "AC Charger Information" | grep "Wattage" | awk '{print $2}')
if [[ -n "$POWER_ADAPTER" ]]; then
    echo "Power Adapter: ${POWER_ADAPTER}W"
fi

# Health assessment
echo -e "\n=== Health Assessment ==="

if [[ "$CONDITION" == "Normal" ]]; then
    echo "✅ Battery condition is normal"
elif [[ "$CONDITION" == "Replace Soon" ]]; then
    echo "⚠️ Battery should be replaced soon"
elif [[ "$CONDITION" == "Replace Now" ]]; then
    echo "❌ Battery needs immediate replacement"
else
    echo "ℹ️ Battery condition: $CONDITION"
fi

if [[ -n "$CYCLE_COUNT" ]]; then
    if [[ "$CYCLE_COUNT" -lt 500 ]]; then
        echo "✅ Cycle count is healthy ($CYCLE_COUNT cycles)"
    elif [[ "$CYCLE_COUNT" -lt 1000 ]]; then
        echo "⚠️ Moderate cycle count ($CYCLE_COUNT cycles)"
    else
        echo "❌ High cycle count ($CYCLE_COUNT cycles)"
    fi
fi

if [[ -n "$MAX_CAPACITY" ]]; then
    if [[ "$MAX_CAPACITY" -ge 90 ]]; then
        echo "✅ Maximum capacity is excellent ($MAX_CAPACITY%)"
    elif [[ "$MAX_CAPACITY" -ge 80 ]]; then
        echo "✅ Maximum capacity is good ($MAX_CAPACITY%)"
    elif [[ "$MAX_CAPACITY" -ge 70 ]]; then
        echo "⚠️ Maximum capacity is declining ($MAX_CAPACITY%)"
    else
        echo "❌ Maximum capacity is poor ($MAX_CAPACITY%)"
    fi
fi

# Recommendations
echo -e "\n=== Recommendations ==="

if [[ -z "$CHARGING_LIMIT" || "$CHARGING_LIMIT" -eq 100 ]]; then
    echo "💡 Consider setting a charging limit (80-90%) for better battery health"
fi

if [[ "$CYCLE_COUNT" -gt 1000 && "$MAX_CAPACITY" -lt 80 ]]; then
    echo "💡 Battery replacement may be needed soon"
fi

Optimized Charging Limit Recommendations

#!/bin/bash

# Provide charging limit recommendations based on usage patterns
echo "🎯 Analyzing optimal charging limit recommendations..."

# Get device model and usage information
DEVICE_MODEL=$(system_profiler SPHardwareDataType | grep "Model Name" | awk -F': ' '{print $2}')
UPTIME=$(uptime | awk '{print $3}' | sed 's/,//')

echo "Device: $DEVICE_MODEL"
echo "Current uptime: $UPTIME"

# Check if device is primarily plugged in
AC_POWER_COUNT=$(pmset -g log | grep -c "Using AC" 2>/dev/null || echo "0")
BATTERY_POWER_COUNT=$(pmset -g log | grep -c "Using Batt" 2>/dev/null || echo "0")

echo -e "\n=== Usage Pattern Analysis ==="

if [[ "$AC_POWER_COUNT" -gt "$BATTERY_POWER_COUNT" ]]; then
    USAGE_TYPE="Desktop/Stationary"
    RECOMMENDED_LIMIT=80
    echo "Usage pattern: Primarily AC powered"
    echo "Recommendation: Set charging limit to $RECOMMENDED_LIMIT%"
else
    USAGE_TYPE="Mobile/Portable"
    RECOMMENDED_LIMIT=90
    echo "Usage pattern: Frequently on battery"
    echo "Recommendation: Set charging limit to $RECOMMENDED_LIMIT%"
fi

# Get current battery health
BATTERY_CONDITION=$(system_profiler SPPowerDataType | grep "Condition" | awk '{print $2}')
MAX_CAPACITY=$(system_profiler SPPowerDataType | grep "Maximum Capacity" | awk '{print $3}' | sed 's/%//')

if [[ -n "$MAX_CAPACITY" && "$MAX_CAPACITY" -lt 85 ]]; then
    RECOMMENDED_LIMIT=75
    echo "⚠️ Battery health is declining, recommended limit: $RECOMMENDED_LIMIT%"
fi

# Check current setting
if command -v bclm >/dev/null 2>&1; then
    CURRENT_LIMIT=$(bclm read 2>/dev/null)
    
    if [[ -n "$CURRENT_LIMIT" ]]; then
        echo "Current limit: $CURRENT_LIMIT%"
        
        if [[ "$CURRENT_LIMIT" -eq "$RECOMMENDED_LIMIT" ]]; then
            echo "✅ Current setting is optimal"
        else
            echo "💡 Consider adjusting to $RECOMMENDED_LIMIT% for optimal battery health"
        fi
    else
        echo "Current limit: Not set (100%)"
        echo "💡 Recommended action: Set charging limit to $RECOMMENDED_LIMIT%"
    fi
fi

echo -e "\n=== Implementation Command ==="
echo "To set recommended limit: sudo bclm write $RECOMMENDED_LIMIT"
echo "To make persistent: sudo bclm persist"

Enterprise Battery Management Script

#!/bin/bash

# MacFleet Battery Management Tool
# Comprehensive battery charging limit management for enterprise environments

# Configuration
LOG_FILE="/var/log/macfleet_battery.log"
BACKUP_DIR="/var/backups/macfleet/battery"
REPORT_DIR="/var/reports/macfleet/battery"
CONFIG_FILE="/etc/macfleet/battery_policy.conf"

# Battery policy settings
DEFAULT_CHARGING_LIMIT=80
MOBILE_DEVICE_LIMIT=90
STATIONARY_DEVICE_LIMIT=75
ENFORCE_BATTERY_POLICY=false
HEALTH_CHECK_ENABLED=true
ALERT_CAPACITY_THRESHOLD=80
ALERT_CYCLE_THRESHOLD=1000

# Logging function
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Setup directories
setup_directories() {
    for dir in "$BACKUP_DIR" "$REPORT_DIR" "$(dirname "$CONFIG_FILE")"; do
        if [[ ! -d "$dir" ]]; then
            sudo mkdir -p "$dir"
            log_action "Created directory: $dir"
        fi
    done
}

# Check if device has a battery
check_battery_presence() {
    if system_profiler SPPowerDataType | grep -q "Battery Information"; then
        return 0
    else
        echo "❌ No battery found on this system"
        log_action "No battery detected on device"
        return 1
    fi
}

# Install battery management tools
install_battery_tools() {
    echo "🔧 Installing battery management tools..."
    log_action "Battery tools installation started"
    
    # Check and install Homebrew
    if ! command -v brew >/dev/null 2>&1; then
        echo "Installing Homebrew..."
        /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
        
        # Add to PATH
        if [[ -f /opt/homebrew/bin/brew ]]; then
            eval "$(/opt/homebrew/bin/brew shellenv)"
        elif [[ -f /usr/local/bin/brew ]]; then
            eval "$(/usr/local/bin/brew shellenv)"
        fi
    fi
    
    # Install bclm
    if ! command -v bclm >/dev/null 2>&1; then
        echo "Installing bclm..."
        brew tap zackelia/formulae && brew install bclm
        
        if command -v bclm >/dev/null 2>&1; then
            echo "✅ bclm installed successfully"
            log_action "bclm installed successfully"
        else
            echo "❌ bclm installation failed"
            log_action "bclm installation failed"
            return 1
        fi
    else
        echo "✅ bclm already installed"
    fi
    
    return 0
}

# Generate comprehensive battery report
generate_battery_report() {
    local report_file="$REPORT_DIR/battery_report_$(date +%Y%m%d_%H%M%S).txt"
    
    echo "📊 Generating comprehensive battery report..."
    
    {
        echo "MacFleet Battery Management Report"
        echo "Generated: $(date)"
        echo "Device: $(hostname)"
        echo "================================="
        echo ""
        
        # System information
        echo "=== System Information ==="
        system_profiler SPHardwareDataType | grep -E "Model Name|Model Identifier|Processor|Memory"
        echo ""
        
        # Battery hardware information
        echo "=== Battery Hardware Information ==="
        local battery_info=$(system_profiler SPPowerDataType)
        echo "$battery_info" | grep -E "Condition|Cycle Count|Maximum Capacity|Manufacturer|Device Name|Pack Lot Code|PCB Lot Code|Firmware Version|Hardware Revision"
        echo ""
        
        # Current charging limit
        echo "=== Charging Limit Configuration ==="
        if command -v bclm >/dev/null 2>&1; then
            local current_limit=$(bclm read 2>/dev/null)
            if [[ -n "$current_limit" ]]; then
                echo "Current charging limit: $current_limit%"
                
                # Check if persistent
                local smc_value=$(sudo bclm read 2>/dev/null)
                if [[ "$smc_value" == "$current_limit" ]]; then
                    echo "Persistence status: Enabled"
                else
                    echo "Persistence status: Disabled"
                fi
            else
                echo "Current charging limit: Not set (100%)"
                echo "Persistence status: N/A"
            fi
        else
            echo "bclm status: Not installed"
        fi
        echo ""
        
        # Power usage analysis
        echo "=== Power Usage Analysis ==="
        echo "Power adapter connected: $(system_profiler SPPowerDataType | grep -q "AC Charger Information" && echo "Yes" || echo "No")"
        
        # Get power adapter info if available
        local adapter_info=$(system_profiler SPPowerDataType | grep -A3 "AC Charger Information" | grep "Wattage")
        if [[ -n "$adapter_info" ]]; then
            echo "Power adapter: $(echo "$adapter_info" | awk '{print $2}')W"
        fi
        
        # Battery temperature and voltage
        echo "Battery temperature: $(ioreg -l | grep Temperature | awk '{print $3/100}' | head -1)°C"
        echo "Battery voltage: $(ioreg -l | grep Voltage | awk '{print $3/1000}' | head -1)V"
        echo ""
        
        # Health assessment
        echo "=== Battery Health Assessment ==="
        local condition=$(echo "$battery_info" | grep "Condition" | awk '{print $2}')
        local cycle_count=$(echo "$battery_info" | grep "Cycle Count" | awk '{print $3}')
        local max_capacity=$(echo "$battery_info" | grep "Maximum Capacity" | awk '{print $3}' | sed 's/%//')
        
        echo "Overall condition: $condition"
        echo "Cycle count: $cycle_count"
        echo "Maximum capacity: $max_capacity%"
        
        # Health scoring
        local health_score=100
        
        if [[ "$condition" != "Normal" ]]; then
            health_score=$((health_score - 20))
        fi
        
        if [[ -n "$cycle_count" ]]; then
            if [[ "$cycle_count" -gt 1000 ]]; then
                health_score=$((health_score - 20))
            elif [[ "$cycle_count" -gt 500 ]]; then
                health_score=$((health_score - 10))
            fi
        fi
        
        if [[ -n "$max_capacity" ]]; then
            if [[ "$max_capacity" -lt 70 ]]; then
                health_score=$((health_score - 30))
            elif [[ "$max_capacity" -lt 80 ]]; then
                health_score=$((health_score - 20))
            elif [[ "$max_capacity" -lt 90 ]]; then
                health_score=$((health_score - 10))
            fi
        fi
        
        echo "Health score: $health_score/100"
        
        # Recommendations
        echo ""
        echo "=== Recommendations ==="
        
        if [[ "$health_score" -ge 80 ]]; then
            echo "✅ Battery health is good"
            echo "💡 Consider setting charging limit to 80% for optimal longevity"
        elif [[ "$health_score" -ge 60 ]]; then
            echo "⚠️ Battery health is declining"
            echo "💡 Set charging limit to 75% and monitor closely"
        else
            echo "❌ Battery health is poor"
            echo "💡 Consider battery replacement and immediate charging limit to 70%"
        fi
        
        # Policy compliance check
        if [[ "$ENFORCE_BATTERY_POLICY" == "true" ]]; then
            echo ""
            echo "=== Policy Compliance ==="
            echo "Battery policy enforcement: ENABLED"
            echo "Default charging limit: $DEFAULT_CHARGING_LIMIT%"
            
            if [[ -n "$current_limit" ]]; then
                if [[ "$current_limit" -eq "$DEFAULT_CHARGING_LIMIT" ]]; then
                    echo "Compliance status: ✅ COMPLIANT"
                else
                    echo "Compliance status: ❌ NON-COMPLIANT"
                    echo "Current: $current_limit%, Required: $DEFAULT_CHARGING_LIMIT%"
                fi
            else
                echo "Compliance status: ❌ NON-COMPLIANT (no limit set)"
            fi
        fi
        
    } > "$report_file"
    
    echo "📊 Report saved to: $report_file"
    log_action "Battery report generated: $report_file"
}

# Set optimal charging limit based on usage pattern
set_optimal_charging_limit() {
    local force_limit="$1"
    
    echo "🎯 Determining optimal charging limit..."
    
    if ! check_battery_presence; then
        return 1
    fi
    
    # Install tools if needed
    if ! command -v bclm >/dev/null 2>&1; then
        if ! install_battery_tools; then
            echo "❌ Failed to install required tools"
            return 1
        fi
    fi
    
    local recommended_limit="$DEFAULT_CHARGING_LIMIT"
    
    # Override with forced limit if provided
    if [[ -n "$force_limit" ]]; then
        recommended_limit="$force_limit"
        echo "Using forced limit: $recommended_limit%"
    else
        # Analyze usage pattern
        echo "Analyzing device usage pattern..."
        
        # Check if device is primarily stationary (simplified detection)
        local model=$(system_profiler SPHardwareDataType | grep "Model Name" | awk -F': ' '{print $2}')
        if echo "$model" | grep -qi "mac studio\|mac pro\|imac"; then
            recommended_limit="$STATIONARY_DEVICE_LIMIT"
            echo "Detected stationary device, recommended limit: $recommended_limit%"
        else
            recommended_limit="$MOBILE_DEVICE_LIMIT"
            echo "Detected mobile device, recommended limit: $recommended_limit%"
        fi
        
        # Adjust based on battery health
        local max_capacity=$(system_profiler SPPowerDataType | grep "Maximum Capacity" | awk '{print $3}' | sed 's/%//')
        if [[ -n "$max_capacity" && "$max_capacity" -lt 85 ]]; then
            recommended_limit=75
            echo "Adjusted for battery health: $recommended_limit%"
        fi
    fi
    
    # Set the charging limit
    echo "Setting charging limit to $recommended_limit%..."
    
    if sudo bclm write "$recommended_limit"; then
        echo "✅ Charging limit set to $recommended_limit%"
        
        # Make persistent
        if sudo bclm persist; then
            echo "✅ Charging limit made persistent"
            log_action "Charging limit set to $recommended_limit% and made persistent"
        else
            echo "⚠️ Failed to make charging limit persistent"
            log_action "Charging limit set to $recommended_limit% but persistence failed"
        fi
        
        # Verify setting
        local verify_limit=$(bclm read 2>/dev/null)
        if [[ "$verify_limit" == "$recommended_limit" ]]; then
            echo "✅ Setting verified: $verify_limit%"
        else
            echo "⚠️ Verification failed: expected $recommended_limit%, got $verify_limit%"
        fi
    else
        echo "❌ Failed to set charging limit"
        log_action "Failed to set charging limit to $recommended_limit%"
        return 1
    fi
}

# Monitor battery health and alert on issues
monitor_battery_health() {
    echo "🔍 Monitoring battery health..."
    
    if ! check_battery_presence; then
        return 1
    fi
    
    local battery_info=$(system_profiler SPPowerDataType)
    local condition=$(echo "$battery_info" | grep "Condition" | awk '{print $2}')
    local cycle_count=$(echo "$battery_info" | grep "Cycle Count" | awk '{print $3}')
    local max_capacity=$(echo "$battery_info" | grep "Maximum Capacity" | awk '{print $3}' | sed 's/%//')
    
    local alerts_triggered=0
    
    # Check condition
    if [[ "$condition" != "Normal" ]]; then
        echo "🚨 ALERT: Battery condition is $condition"
        log_action "ALERT: Battery condition is $condition"
        ((alerts_triggered++))
    fi
    
    # Check cycle count
    if [[ -n "$cycle_count" && "$cycle_count" -gt "$ALERT_CYCLE_THRESHOLD" ]]; then
        echo "🚨 ALERT: High cycle count - $cycle_count cycles"
        log_action "ALERT: High cycle count - $cycle_count cycles"
        ((alerts_triggered++))
    fi
    
    # Check capacity
    if [[ -n "$max_capacity" && "$max_capacity" -lt "$ALERT_CAPACITY_THRESHOLD" ]]; then
        echo "🚨 ALERT: Low maximum capacity - $max_capacity%"
        log_action "ALERT: Low maximum capacity - $max_capacity%"
        ((alerts_triggered++))
    fi
    
    if [[ "$alerts_triggered" -eq 0 ]]; then
        echo "✅ No battery health alerts"
        log_action "Battery health monitoring: No alerts"
    else
        echo "⚠️ $alerts_triggered battery health alert(s) triggered"
        log_action "Battery health monitoring: $alerts_triggered alerts triggered"
    fi
    
    return $alerts_triggered
}

# Main execution function
main() {
    local action="${1:-help}"
    local target="${2:-}"
    
    log_action "=== MacFleet Battery Management Started ==="
    
    setup_directories
    
    case "$action" in
        "install"|"setup")
            install_battery_tools
            ;;
        "report"|"status")
            generate_battery_report
            ;;
        "set")
            if [[ -n "$target" ]]; then
                set_optimal_charging_limit "$target"
            else
                set_optimal_charging_limit
            fi
            ;;
        "read"|"current")
            if command -v bclm >/dev/null 2>&1; then
                local current=$(bclm read 2>/dev/null)
                if [[ -n "$current" ]]; then
                    echo "Current charging limit: $current%"
                else
                    echo "No charging limit set (100%)"
                fi
            else
                echo "❌ bclm not installed"
            fi
            ;;
        "persist")
            if command -v bclm >/dev/null 2>&1; then
                if sudo bclm persist; then
                    echo "✅ Charging limit made persistent"
                else
                    echo "❌ Failed to make charging limit persistent"
                fi
            else
                echo "❌ bclm not installed"
            fi
            ;;
        "unpersist")
            if command -v bclm >/dev/null 2>&1; then
                if sudo bclm unpersist; then
                    echo "✅ Charging limit persistence removed"
                else
                    echo "❌ Failed to remove charging limit persistence"
                fi
            else
                echo "❌ bclm not installed"
            fi
            ;;
        "monitor")
            monitor_battery_health
            ;;
        "health")
            if check_battery_presence; then
                local battery_info=$(system_profiler SPPowerDataType)
                echo "=== Battery Health Summary ==="
                echo "$battery_info" | grep -E "Condition|Cycle Count|Maximum Capacity"
                
                if command -v bclm >/dev/null 2>&1; then
                    local limit=$(bclm read 2>/dev/null)
                    echo "Charging Limit: ${limit:-100}%"
                fi
            fi
            ;;
        "help"|*)
            echo "MacFleet Battery Management Tool"
            echo "Usage: $0 [action] [options]"
            echo ""
            echo "Actions:"
            echo "  install               - Install battery management tools (Homebrew, bclm)"
            echo "  report                - Generate comprehensive battery report"
            echo "  set [limit]           - Set optimal charging limit (or specify percentage)"
            echo "  read                  - Read current charging limit"
            echo "  persist               - Make charging limit persistent"
            echo "  unpersist             - Remove charging limit persistence"
            echo "  monitor               - Monitor battery health and trigger alerts"
            echo "  health                - Show battery health summary"
            echo "  help                  - Show this help message"
            echo ""
            echo "Examples:"
            echo "  $0 install             # Install required tools"
            echo "  $0 set 80              # Set 80% charging limit"
            echo "  $0 set                 # Set optimal limit based on device type"
            echo "  $0 report              # Generate detailed report"
            echo ""
            echo "Charging Limit Guidelines:"
            echo "  50-100%     - Valid range"
            echo "  80%         - Recommended for most devices"
            echo "  75%         - For stationary/desktop Macs"
            echo "  90%         - For mobile/laptop Macs"
            ;;
    esac
    
    log_action "=== MacFleet Battery Management Completed ==="
}

# Execute main function
main "$@"

Battery Health Monitoring

Automated Health Checks

# Schedule daily battery health monitoring
create_health_monitoring_schedule() {
    local plist_file="$HOME/Library/LaunchAgents/com.macfleet.battery-monitor.plist"
    
    cat > "$plist_file" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.macfleet.battery-monitor</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>$(realpath "$0")</string>
        <string>monitor</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>9</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
    <key>RunAtLoad</key>
    <false/>
</dict>
</plist>
EOF
    
    launchctl load "$plist_file" 2>/dev/null
    echo "✅ Daily battery monitoring scheduled"
}

Charging Limit Recommendations

Device TypeRecommended LimitReasoning
Desktop Macs75-80%Always plugged in, prioritize longevity
Laptop Macs (Stationary)80%Mostly plugged in usage
Laptop Macs (Mobile)90%Need higher capacity for portability
Degraded Battery70-75%Extend remaining battery life

Important Notes

  • Supported Devices - Only works on Mac devices with batteries
  • Administrative Privileges - Requires sudo access for SMC modifications
  • System Compatibility - Compatible with modern macOS versions
  • Restart Requirements - Some changes may require system restart
  • Fleet Deployment - Test on individual devices before bulk deployment
  • Battery Health - Monitor battery condition regularly for optimal results

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.