用旧苹果手机当nas监控副屏(一)

• 20 分钟阅读 • nas · deepseek · linux

现在玩nas的人越来越多,nas一般没有屏幕,无法随时监控运行状态,于是就有了图灵智显,这是一个硬件(屏幕+有线连接)+软件的实现方法。这里使用远古时代的iphone5s当屏幕,配合软件实现监控nas状态。

iphone5s的浏览器已经不能解析复杂的js文件,本文使用shell脚本采集系统状态数据,再用简单的html文件定时刷新来显示状态信息。

状态数据采集脚本

/usr/local/bin/status.sh:

#!/bin/bash
# nas_status_final.sh - 最终简化版

INTERFACE="enp4s0"
JSON_FILE="/var/www/html/status.json"
NET_FILE="/tmp/net_cache.txt"
# 指定要监控的磁盘挂载点(可以根据需要修改)
MOUNT_POINT="/vol1/docker/overlay2/bfe25ec30f56cc56436cad793bedce52eaf4b0ce409409a65c64a4742e98bdb5/merged"  # 默认监控根目录,可以改为 "/home"、"/data" 等

# 格式化速度(KB/s和MB/s)
format_speed_simple() {
    local bytes_per_sec=$1
    
    # 小于1KB/s显示为0
    if [ -z "$bytes_per_sec" ] || [ $bytes_per_sec -lt 1024 ]; then
        echo "0 KB/s"
        return
    fi
    
    # 转换为KB/s(整数部分)
    local kb_sec=$((bytes_per_sec / 1024))
    
    # 如果大于1024KB/s,转换为MB/s
    if [ $kb_sec -ge 1024 ]; then
        local mb_sec=$((bytes_per_sec / 1048576))
        local remainder=$(( (bytes_per_sec % 1048576) * 100 / 1048576 ))
        echo "${mb_sec}.${remainder} MB/s"
    else
        local remainder=$(( (bytes_per_sec % 1024) * 100 / 1024 ))
        echo "${kb_sec}.${remainder} KB/s"
    fi
}

# 将uptime转换为中文
convert_uptime_to_chinese() {
    local uptime_str=$(uptime -p | sed 's/up //')
    
    # 替换英文单位为中文
    echo "$uptime_str" | sed \
        -e 's/ days/天/g' \
        -e 's/ hours/小时/g' \
        -e 's/ minutes/分/g' \
        -e 's/ weeks/周/g' 
}

# 计算网络
get_network_stats() {
    # 当前值
    read rx_now tx_now <<< $(grep "$INTERFACE:" /proc/net/dev 2>/dev/null | awk '{print $2, $10}' || echo "0 0")
    now=$(date +%s)
    
    # 上次值
    if [ -f "$NET_FILE" ]; then
        read rx_last tx_last time_last < "$NET_FILE"
    else
        rx_last=$rx_now
        tx_last=$tx_now
        time_last=$now
    fi
    
    # 保存
    echo "$rx_now $tx_now $now" > "$NET_FILE"
    
    # 时间差
    time_diff=$((now - time_last))
    [ $time_diff -eq 0 ] && time_diff=1
    
    # 计算速度
    rx_speed=$(( (rx_now - rx_last) / time_diff ))
    tx_speed=$(( (tx_now - tx_last) / time_diff ))
    [ $rx_speed -lt 0 ] && rx_speed=0
    [ $tx_speed -lt 0 ] && tx_speed=0
    
    # 格式化
    download=$(format_speed_simple $rx_speed)
    upload=$(format_speed_simple $tx_speed)
    
    # 总流量(GB,保留2位小数)
    total_down=$(printf "%.2f" $(echo "$rx_now / 1073741824" | bc -l 2>/dev/null || echo "0"))
    total_up=$(printf "%.2f" $(echo "$tx_now / 1073741824" | bc -l 2>/dev/null || echo "0"))
    
    # 返回
    echo "$download"
    echo "$upload"
    echo "$total_down"
    echo "$total_up"
}

# 获取指定挂载点的磁盘信息
get_disk_info() {
    local mount_point=$1
    
    # 使用df命令获取指定挂载点的信息
    df_output=$(df -h "$mount_point" 2>/dev/null | tail -1)
    
    if [ -n "$df_output" ]; then
        # 从df输出中提取信息
        usage=$(echo "$df_output" | awk '{print $5}')
        total=$(echo "$df_output" | awk '{print $2}')
        used=$(echo "$df_output" | awk '{print $3}')
        free=$(echo "$df_output" | awk '{print $4}')
        
        # 如果没有可用空间信息(旧版本df),计算它
        if [ -z "$free" ] || [ "$free" = "-" ]; then
            total_bytes=$(df -B1 "$mount_point" 2>/dev/null | tail -1 | awk '{print $2}')
            used_bytes=$(df -B1 "$mount_point" 2>/dev/null | tail -1 | awk '{print $3}')
            free_bytes=$((total_bytes - used_bytes))
            
            # 转换为人类可读格式
            free=$(echo "$free_bytes" | awk '{
                if ($1 >= 1099511627776) printf "%.1fT", $1/1099511627776
                else if ($1 >= 1073741824) printf "%.1fG", $1/1073741824
                else if ($1 >= 1048576) printf "%.1fM", $1/1048576
                else printf "%.1fK", $1/1024
            }')
        fi
    else
        # 如果指定的挂载点不存在,使用根目录
        df_output=$(df -h / | tail -1)
        usage=$(echo "$df_output" | awk '{print $5}')
        total=$(echo "$df_output" | awk '{print $2}')
        used=$(echo "$df_output" | awk '{print $3}')
        free=$(echo "$df_output" | awk '{print $4}')
    fi
    
    echo "$usage"
    echo "$total"
    echo "$used"
    echo "$free"
}

# 主程序
{
    # 获取网络数据
    net_data=$(get_network_stats)
    download_speed=$(echo "$net_data" | head -1)
    upload_speed=$(echo "$net_data" | head -2 | tail -1)
    total_down=$(echo "$net_data" | head -3 | tail -1)
    total_up=$(echo "$net_data" | tail -1)
    
    # 获取CPU使用率
    cpu=$(top -bn1 | grep "Cpu(s)" | awk '{printf "%.1f%%", $2 + $4}')
    
    # 获取内存信息
    read mem_usage mem_used mem_total <<< $(free -m | awk 'NR==2{
        used_mb=$3; total_mb=$2
        printf "%.1f%% %d %d", used_mb*100/total_mb, used_mb, total_mb
    }')
    
    # 获取指定挂载点的磁盘信息
    disk_data=$(get_disk_info "$MOUNT_POINT")
    disk_usage=$(echo "$disk_data" | head -1)
    disk_total=$(echo "$disk_data" | head -2 | tail -1)
    disk_used=$(echo "$disk_data" | head -3 | tail -1)
    disk_free=$(echo "$disk_data" | tail -1)
    
    # 获取中文运行时间
    uptime_chinese=$(convert_uptime_to_chinese)
    
    # 获取系统负载(去掉首尾空格)
    system_load=$(uptime | awk -F'load average:' '{print $2}' | sed 's/^ *//;s/ *$//')
    
    # 在JSON中添加监控的挂载点信息
    cat > "$JSON_FILE" << EOF
{
  "cpu": "$cpu",
  "memory": {
    "usage": "$mem_usage",
    "used": "${mem_used}MB",
    "total": "${mem_total}MB"
  },
  "disk": {
    "mount_point": "$MOUNT_POINT",
    "usage": "$disk_usage",
    "total": "$disk_total",
    "used": "$disk_used",
    "available": "$disk_free"
  },
  "network": {
    "download_speed": "$download_speed",
    "upload_speed": "$upload_speed",
    "total_download": "${total_down} GB",
    "total_upload": "${total_up} GB",
    "interface": "$INTERFACE"
  },
  "system": {
    "uptime": "$uptime_chinese",
    "load": "$system_load",
    "time": "$(date '+%Y-%m-%d %H:%M:%S')"
  }
}
EOF
}

docker cp /var/www/html/status.json php://var/www/html/

INTERFACE:网卡名,用ifconfig获取。
MOUNT_POINT:值是"/“就是整个磁盘,nas有添加的存贮空间,用df -h获取相应路径。
最后一句,nas上的web服务在docker里,这里把状态数据复制到docker里。
chmod +x /usr/local/bin/status.sh
运行脚本得到的json样式:

{
  "cpu": "29.4%",
  "memory": {
    "usage": "57.0%",
    "used": "2179MB",
    "total": "3825MB"
  },
  "disk": {
    "mount_point": "/vol1/docker/overlay2/bfe25ec30f56cc56436cad793bedce52eaf4b0ce409409a65c64a4742e98bdb5/merged",
    "usage": "48%",
    "total": "221G",
    "used": "104G",
    "available": "117G"
  },
  "network": {
    "download_speed": "1.50 KB/s",
    "upload_speed": "1.83 KB/s",
    "total_download": "7.75GB",
    "total_upload": "6.23GB",
    "interface": "enp4s0"
  },
  "system": {
    "uptime": "3天, 11小时, 28分",
    "load": "0.19, 0.23, 0.26",
    "time": "2026-01-28 11:12:41"
  }
}

status.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>NAS状态监控</title>
    <meta http-equiv="refresh" content="10">
    <style>
        body { font-family: sans-serif; margin: 20px; font-size: 16px; }
        .section { 
            border: 1px solid #ccc; 
            margin: 10px 0; 
            padding: 10px;
            border-radius: 5px;
        }
        .title { 
            font-weight: bold; 
            color: #333;
            margin-bottom: 10px;
        }
        .row { 
            display: flex; 
            justify-content: space-between;
            margin: 5px 0;
        }
        .time { 
            text-align: center; 
            color: #666; 
            font-size: 12px;
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <div class="section">
        <div id="cpu">CPU: 加载中...</div>
        <div id="memory">内存: 加载中...</div>
        <div id="disk">磁盘: 加载中...</div>      
        <div id="network">网络: 加载中...</div>
         <div id="system">系统: 加载中...</div>
    </div>
    <div class="time" id="timestamp">最后更新: 加载中...</div>
<script>
// 兼容老iOS的简单请求
function loadStatus() {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'status.json?' + new Date().getTime(), true);
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                try {
                    var data = JSON.parse(xhr.responseText);
                    updateDisplay(data);
                } catch(e) {
                    document.getElementById('cpu').innerHTML = '数据解析错误';
                    console.error('JSON解析错误:', e);
                }
            } else {
                document.getElementById('cpu').innerHTML = '连接失败: ' + xhr.status;
            }
        }
    };
    xhr.send();
}

function updateDisplay(data) {
    // CPU
    document.getElementById('cpu').innerHTML = 
        '<div class="row"><span>CPU使用率:</span><span>' + data.cpu + '</span></div>';
    
    // 内存
    document.getElementById('memory').innerHTML = 
        '<div class="row"><span>内存使用:</span><span>' + data.memory.usage + 
        ' (' + data.memory.used + '/' + data.memory.total + ')</span></div>';
    
    // 磁盘
    document.getElementById('disk').innerHTML = 
        '<div class="row"><span>磁盘使用:</span><span>' + data.disk.usage + 
        ' (' + data.disk.used + '/' + data.disk.total + ')</span></div>' +
        '<div class="row"><span>可用空间:</span><span>' + data.disk.available + '</span></div>';
    
    // 网络 - 这里特别注意解析
    var net = data.network;
    document.getElementById('network').innerHTML = 
        '<div class="row"><span>下载速度:</span><span>' + net.download_speed + '</span></div>' +
        '<div class="row"><span>上传速度:</span><span>' + net.upload_speed + '</span></div>' +
        '<div class="row"><span>总下载:</span><span>' + net.total_download + '</span></div>' +
        '<div class="row"><span>总上传:</span><span>' + net.total_upload + ' </span></div>' +
        '<div class="row"><span>接口:</span><span>' + net.interface + '</span></div>';
    
    // 系统信息
    document.getElementById('system').innerHTML = 
        '<div class="row"><span>运行时间:</span><span>' + data.system.uptime + '</span></div>' +
        '<div class="row"><span>系统负载:</span><span>' + data.system.load + '</span></div>';
    
    // 更新时间
    document.getElementById('timestamp').innerHTML = 
        '最后更新: ' + data.system.time + ' (每10秒自动刷新)';
    
    // 调试信息(可选)
    console.log('网络数据:', data.network);
}

// 页面加载时运行
window.onload = function() {
    loadStatus();
    // 每10秒自动刷新(配合meta标签)
    setInterval(loadStatus, 10000);
};
</script>
</body>
</html>

文件和status.json在同一路径,放在web服务目录下。

定时刷新脚本数据

在crond里添加定时刷新。
crontab -e:在最后添加以下语句

* * * * * /usr/local/bin/status.sh
* * * * * sleep 10; /usr/local/bin/status.sh
* * * * * sleep 20; /usr/local/bin/status.sh
* * * * * sleep 30; /usr/local/bin/status.sh
* * * * * sleep 40; /usr/local/bin/status.sh
* * * * * sleep 50; /usr/local/bin/nas_status.sh

每10秒刷新一次。

效果图


屏幕已经发黄,里面因为拆机换后盖和电池进灰,但作为一个监控副屏,还是能吊打单片机+显示屏做的副屏,充分发挥了一个不锈钢脸盆的价值。

html中的<meta http-equiv="refresh" content="10">会造成页面闪烁,删掉就好了。

网页特效

由于iphone5s上的ios12.5.8不支持网页背景图,不能做成比较炫酷的效果。style语句只包含新增部分。
渐变色效果:

body {
                background: linear-gradient(135deg, #ffffff 0%, #ff1493 100%);
        }
.section {
            background-color: rgba(255, 255, 255, 0.40);
        }

动态渐变色效果:

body {
                background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
                background-size: 400% 400%;
                animation: gradient 15s ease infinite;
        }
        @keyframes gradient {
                0% { background-position: 0% 50%; }
                50% { background-position: 100% 50%; }
                100% { background-position: 0% 50%; }
        }



以上脚本和网页代码均由deepseek生成,加少量人工修改。

文章标签: nas, deepseek, linux

上一篇 : 用旧苹果手机当nas监控副屏(二)
下一篇 : arm飞牛一键解锁应用中心: XXNAS工具箱
留言
阅读进度 0%