2026年5月16日土曜日

ラズパイでNAS +α

 手持ちのラズパイ3B+をNASにし、DLNAサーバーとしても運用したい。

手持ちの5インチディスプレイを使用し、監視システム+α(時計とか天気とか)の表示をさせたい。chatGPTに相談しながら作成してみる。

1.サーバー監視

・ストレージ使用率(総容量、使用量、空き、〇%超で色変化)

・ディスク状態(温度、SMART異常の有無)

・ネットワーク状況(リアルタイム転送速度、接続クライアント数)

・CPU/メモリ使用率(RPi3の負荷監視)

・稼働時間(再起動忘れ防止)

2.+α

・現在時間、カレンダー

・天気情報

・接続中ユーザー表示

・最近のファイル更新ログ

・バックアップ状態

・フォトフレーム(NAS内の写真を表示)

・音楽再生情報(再生中の曲名)

・ニュースヘッドライン

3.状態異常の強調表示

・温度〇度以上の時、ストレージ使用率〇%以上、ネットワーク切断 など


構想:
まず、1のサーバー監視を作成し、順次+αのうちいずれかを表示できるように考えたい。
→python+FlaskでシンプルWeb表示


環境構築:

OS:Debialn13 (コードネームtrixie)
ラズベリーパイ3B+
KUMAN 5インチディスプレイ(800×480)

sambaとminidlnaの導入

①HDDの接続確認

$ lsblk
出力例)
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda            8:0    0  3.6T  0 disk
┗sda1        8:1    0  3.6T  0 part /media/pi

②HDDのファイル形式確認

$ sudo blkid
出力例)
/dev/sda1: LABEL="HD-ADU3" BLOCK_SIZE="512" UUID="XXXXXXXXX" TYPE="ntfs"
※UUIDは後で使います。ntfsでフォーマットされています。

③必要なソフトのインストール、まとめて実行

$ sudo apt update
$ sudo apt install samba minidlna ntfs-3g exfat-fuse -y

最新バージョン(2026.5.10時点)
samba is already the newest version (2:4.22.8+dfsg-0+deb13u1).
minidlna is already the newest version (1.3.3+dfsg-1.1+b1).
ntfs-3g is already the newest version (1:2022.10.3-5+deb13u1).
exfat-fuse is already the newest version (1.4.0-3+b2).

④HDDのマウント先を作る

$ sukdo mkdir -p /mnt/hdd

⑤HDDを手動でマウント

$ sudo mount -t ntfs-3g /dev/sda1 /mnt/hdd

下記のエラーが出る場合

Mount is denied because the NTFS volume is already exclusively opened.
The volume may be already mounted, or another software may use it which
could be identified for example by the help of the 'fuser' command.

すでに /dev/sda1がどこかに接続されているためにおこるエラー。接続先を調べるには
$ mount | grep sda1
表示例)
/dev/sda1 on /media/pi/HD-ADU3 type ntfs3 
→/media/piに接続されているから /mnt/hddには接続できないので、一旦外す。

※/media/pi は一時的な接続先となる。USBメモリの接続など。そのため、毎回必ず「/media/pi/HD-ADU3」となるとは限らない。サーバー用途などでは、「/mnt/hdd」だけではなく「/srv/storage」なども良い。

$ sudo umount /media/pi/HD-ADU3
表示例)
sda           8:0    0  3.6T  0 disk
┗sda1        8:1    0  3.6T  0 part
①の表示例、(┗sda1        8:1    0  3.6T  0 part /media/pi)と比べるとマウントポイントが消えていることが分かる。
再度手動でマウントする。
$ sudo mount -t ntfs-3g /dev/sda1 /mnt/hdd

⑥成功確認

$  ls /mnt/hdd
HDDの中のファイル一覧が見えれば成功

⑦自動マウント設定

UUIDを確認
$ sudo blkid
表示例)
/dev/sda1: UUID="340815D408159648"

fstab編集
$ sudo nano /etc/fstab

一番下に下記の一文を追加
UUID=上記のUUID /mnt/hdd ntfs-3g defaults,uid=1000,gid=1000,umask=000 0 0

上記のUUID:このHDDを使う
/mnt/hdd:ここにHDDを接続する
ntfs-3g:NTFSを読み書きできるドライバを使う
defaults:Linux標準設定。(読み書き可能、自動マウント、実行許可、デバイス許可など)
uid=1000:ユーザー番号1000の所有物にする。ラズパイではpiがUID1000。
gid=1000:グループ番号。通常piのグループ。
umask=000:全員フルアクセスOK。セキュリティ的には自宅内限定。
0:dumpという古いバックアップ機能、現代ではほぼ使わない。
0:fsckという起動チェック設定。LinuxではNTFSは完全修復できないので0でOK。

つまり、「UUIDが〇〇のNTFS HDDを、起動時に /mnt/hddへ接続し、piユーザーが自由に読み書きできるようにする。」という意味。

⑧Samba設定(Windows共有)

設定ファイル編集
$ sudo nano /etc/samba/smb.conf

一番下に下記を追加
[HDD]
path = /mnt/hdd
browseable = yes
writeable = yes
create mask = 0777
directory mask = 0777
public = yes
guest ok = yes

⑨Samba再起動

$ sudo systemctl restart smbd
$ sudo systemctl enable smbd

⑩Windowsからアクセス

Windowsから
\\raspberrypi(ホストネーム、IPアドレス)
を開く。

※Windowsの「ネットワークの資格情報」にてはじかれてしまう場合は、
「Raspberry Piに存在するLinuxユーザー」、「Sambaに登録されたユーザー」、「Windowsで入力するユーザー」が一致している必要がある。
RaspberryPi側で $ whoami →例)pi
Sambaユーザー登録
$ sudo smbpasswd -a pi
表示例)
New SMB password:
Retype new password:

ここで設定したパスワードが、Windowsから接続するときに使うパスワードです。

※ネットワークドライブとして割り当てると後々アクセスが楽になる。

⑪MiniDLNA設定

$ sodo nano /etc/minidlna.conf

以下を探して変更
media_dir=/mnt/hdd    メディアフォルダ
friendly_name=RPi3    名前
inotify=yes                        自動監視ON

⑫MiniDLNA再起動

$ sudo systemctl restart minidlna
$ sudo systemctl enable minidlna

⑬データベース再構築(初回)

$ sudo minidlnad -R

⑭動作確認(Windows)

エクスプローラーで\\RPi3 

⑮トラブル時の確認コマンド

$ systemctl status smbd  Samba状態
表示例)
pi@RPi3:~ $ systemctl status smbd
● smbd.service - Samba SMB Daemon
     Loaded: loaded (/usr/lib/systemd/system/smbd.se>
     Active: active (running) since Sun 2026-05-10 2>
 Invocation: 8ab259a2c8db44a2a2b87a54ba54d3b6
       Docs: man:smbd(8)
             man:samba(7)
             man:smb.conf(5)
   Main PID: 11111 (smbd)
     Status: "smbd: ready to serve connections..."
      Tasks: 4 (limit: 751)
        CPU: 7.385s
     CGroup: /system.slice/smbd.service
             tq11111 /usr/sbin/smbd --foreground --n>
             tq11114 "smbd: notifyd" .
             tq11115 "smbd: cleanupd "
             mq11583 "smbd: client [240b:13:7e1:7600>

$ systemctl status minidlna   DLNA状態
表示例)
pi@RPi3:~ $ systemctl status minidlna
● minidlna.service - MiniDLNA lightweight DLNA/UPnP->
     Loaded: loaded (/usr/lib/systemd/system/minidln>
     Active: active (running) since Sun 2026-05-10 2>
 Invocation: bea131b5f08645419921f4a3d9b183c8
       Docs: man:minidlnad(1)
             man:minidlna.conf(5)
   Main PID: 11666 (minidlnad)
      Tasks: 2 (limit: 751)
        CPU: 4min 53.080s
     CGroup: /system.slice/minidlna.service
             tq11666 /usr/sbin/minidlnad -f /etc/min>
             mq11673 /usr/sbin/minidlnad -f /etc/min>


Python+Flaskで表示画面作成

1.必要なパッケージをインストールする

$ sudo apt update
$ sudo apt install -y python3-flask python3-psutil smartmontools
$ sudo apt install -y mpd mpc  ※音楽表示をする場合

②作業フォルダ作成

$ mkdir -p ~/nas-monitor/templates
$ mkdir -p ~/nas-monitor/static

フォルダ構成
/home/pi/nas-monitor/
├── app.py
├── templates/
│     └── index.html
└── static/
    └── style.css

③Pythonコード作成(Flask本体)

$ nano ~/nas-monitor/app.py

from flask import Flask, render_template, jsonify
import psutil
import shutil
import subprocess
import time
from datetime import datetime

app = Flask(__name__)

# ===== 設定 =====

# HDD名
DISK = "/dev/sdb"

# 使用しているネットワークIF
# Wi-Fiなら wlan0
# 有線なら eth0
NETWORK_IF = "wlan0"

# マウント先
MOUNT_POINT = "/mnt/hdd"

# ==================

# ネットワーク速度計算用
last_bytes = 0
last_time = time.time()

def get_cpu_temp():

    try:

        temp = subprocess.check_output(
            ["vcgencmd", "measure_temp"]
        ).decode()

        return temp.replace("temp=", "").replace("'C\n", "")

    except:

        return "不明"


def get_disk_temp():

    try:

        output = subprocess.check_output(
            [
                "sudo",
                "smartctl",
                "-A",
                "-d",
                "sat",
                DISK
            ]
        ).decode()

        for line in output.splitlines():

            if "Temperature_Celsius" in line:

                return line.split()[-1] + "°C"

            if "Airflow_Temperature_Cel" in line:

                return line.split()[-1] + "°C"

        return "不明"

    except Exception as e:

        return "取得失敗"


def get_smart_status():

    try:

        output = subprocess.check_output(
            [
                "sudo",
                "smartctl",
                "-H",
                "-d",
                "sat",
                DISK
            ]
        ).decode()

        if "PASSED" in output:

            return "正常"

        else:

            return "異常"

    except:

        return "取得失敗"


def get_now_playing():

    try:

        song = subprocess.check_output(
            ["mpc", "current"]
        ).decode().strip()

        if song == "":

            return "なし"

        return song

    except:

        return "なし"


def get_network_speed():

    global last_bytes
    global last_time

    try:

        counters = psutil.net_io_counters(pernic=True)

        if NETWORK_IF not in counters:

            return 0

        net = counters[NETWORK_IF]

        current_bytes = net.bytes_recv + net.bytes_sent

        current_time = time.time()

        speed = (
            current_bytes - last_bytes
        ) / (
            current_time - last_time
        )

        last_bytes = current_bytes
        last_time = current_time

        # MB/s
        return round(speed / 1024 / 1024, 2)

    except:

        return 0


@app.route("/")
def index():

    return render_template("index.html")


@app.route("/status")
def status():

    # CPU
    cpu = psutil.cpu_percent()

    # RAM
    ram = psutil.virtual_memory().percent

    # ストレージ
    total, used, free = shutil.disk_usage(MOUNT_POINT)

    storage_percent = round(
        (used / total) * 100,
        1
    )

    total_tb = round(
        total / (1024**4),
        1
    )

    # 温度
    cpu_temp = get_cpu_temp()

    disk_temp = get_disk_temp()

    # SMART
    smart = get_smart_status()

    # ネットワーク
    network_speed = get_network_speed()

    # 時刻
    now = datetime.now().strftime("%H:%M:%S")

    # 音楽
    music = get_now_playing()

    return jsonify({

        "cpu": cpu,

        "ram": ram,

        "storage_percent": storage_percent,

        "total_tb": total_tb,

        "cpu_temp": cpu_temp,

        "disk_temp": disk_temp,

        "smart": smart,

        "network_speed": network_speed,

        "time": now,

        "music": music
    })


if __name__ == "__main__":

    app.run(
        host="0.0.0.0",
        port=5000
    )

④HTML作成

$ nano ~/nas-monitor/templates/index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>NAS Monitor</title>
    <link rel="stylesheet" href="/static/style.css">
</head>
<body>
<div class="container">
    <div class="top">
        <div class="left">
            <h2>ストレージ使用率:<span id="storage"></span>%</h2>
            <p>( <span id="total"></span>TB)</p>
        </div>
        <div class="right">
            <p>システム温度:<span id="cpu_temp"></span>°C</p>
            <p>ディスク温度:<span id="disk_temp"></span></p>
            <p>SMART:<span id="smart"></span></p>
        </div>
    </div>
    <div class="middle">
        <div>
            <p>ネットワーク転送速度:<span id="network"></span> MB/s</p>
        </div>
        <div>
            <p>CPU使用率:<span id="cpu"></span>%</p>
            <p>RAM使用率:<span id="ram"></span>%</p>
        </div>
    </div>
    <div class="clock">
        <p>現在時間</p>
        <div id="time">00:00:00</div>
    </div>
    <div class="music">
        <p>現在再生中の音楽:<span id="music"></span></p>
    </div>
</div>
<script>
async function updateStatus() {
    const response = await fetch("/status");
    const data = await response.json();
    document.getElementById("storage").innerText =
        data.storage_percent;
    document.getElementById("total").innerText =
        data.total_gb;
    document.getElementById("cpu_temp").innerText =
        data.cpu_temp;
    document.getElementById("disk_temp").innerText =
        data.disk_temp;
    document.getElementById("smart").innerText =
        data.smart;
    document.getElementById("network").innerText =
        data.network_speed;
    document.getElementById("cpu").innerText =
        data.cpu;
    document.getElementById("ram").innerText =
        data.ram;
    document.getElementById("time").innerText =
        data.time;
    document.getElementById("music").innerText =
        data.music;
}
setInterval(updateStatus, 1000);
updateStatus();
</script>
</body>
</html>

⑤CSS作成

$ nano ~/nas-monitor/static/style.css

body {
    background: #efefef;
    font-family: sans-serif;
    margin: 0;
    padding: 10px;
    width: 800px;
    height: 480px;
    overflow: hidden;
}
.container {
    display: flex;
    flex-direction: column;
    height: 100%;
}
.top {
    display: flex;
    justify-content: space-between;
}
.middle {
    margin-top: 40px;
    display: flex;
    justify-content: space-between;
}
.clock {
    margin-top: 40px;
    text-align: center;
}
#time {
    font-size: 80px;
    letter-spacing: 10px;
}
.music {
    margin-top: 30px;
    font-size: 20px;
}

⑥Flask起動

$ cd ~/nas-monitor
$ python3 app.py

表示例)
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://192.168.10.131:5000

ラズパイからなら、ブラウザにhttp://127.0.0.1:5000と入力
LAN内のWindows機からはhttp://192.168.10.131:5000と入力すると表示される。

⑦sudoers設定

$ sudo visudo

最後に以下の1文を追記する。

pi ALL=(ALL) NOPASSWD: /usr/sbin/smartctl

⑧自動起動設定

サービスに登録する。

$ sudo nano /etc/systemd/system/nas-monitor.service

[Unit]
Description=NAS Monitor
After=network.target

[Service]
User=pi
WorkingDirectory=/home/pi/nas-monitor
ExecStart=/usr/bin/python3 /home/pi/nas-monitor/app.py
Restart=always

[Install]
WantedBy=multi-user.target

上記自作のサービスを有効にする。

$ sudo systemctl daemon-reload
$ sudo systemctl enable nas-monitor
$ sudo systemctl start nas-monitor

⑨フルスクリーン表示

$ sudo apt install -y chromium
$ mkdir -p ~/.config/lxsession/LXDE
$ nano ~/.config/lxsession/LXDE/autostart

@xset s off
@xset -dpms
@xset s noblank

@unclutter -idle 0

@chromium
--kiosk
--app=http://localhost:5000
--no-first-run
--disable-infobars
--disable-session-crashed-bubble
--disable-features=TranslateUI
--disable-gpu
--incognito
--noerrdialogs


表示されない場合、LXDEが起動していない可能性もある。
必要なGUIを追加する。
$ sudo apt update
$ sudo apt install -y lxde-core lightdm xserver-xorg xinit openbox
$ sudo nano /etc/lightdm/lightdm.conf

[Seat:*]の下に以下を追加。
autologin-user=pi
autologin-user-timeout=0
user-session=LXDE
#autologin-session=rpd-labwc

でもTrixie は:labwc(Wayland)が標準採用なんだよね。。。

2025年8月26日火曜日

VScodeでラズパイに接続

LM Studio -0.3.23とopenai/gpt-oss-20bを使用して、ウィンドウズ機からラズベリーパイ上でPythonファイルを操作する方法を聞いてみた。

Q:windows11のパソコンから、VScodeを使用して、ラズベリーパイ上のPythonファイルを操作したいので、環境構築方法を教えてください。

A:

概要

Windows 11 の PC から Visual Studio Code (VS Code) を使い、Raspberry Pi 上の Python ファイルを開いて編集・実行するだけでなく、デバッグやパッケージ管理も同じエディタ内で完結できるようにします。
以下は「Remote‑SSH」拡張機能を中心にした手順です。

目的手順
1. VS Code をインストール公式サイトからインストーラをダウンロード → インストール
2. Remote‑SSH 拡張機能を追加VS Code の拡張機能ビューで「Remote - SSH」を検索してインストール
3. Raspberry Pi に SSH 接続設定キーペア生成、authorized_keys 設定
4. Python 環境の準備必要なパッケージを pip install で入れる
5. VS Code からリモート接続Remote‑SSH で Pi に接続し、Python ファイルを開く

1. Windows 11 への VS Code インストール

  1. 公式サイト
    https://code.visualstudio.com/download → 「Windows」→「64-bit .zip」をダウンロード(または MSI を選択)。

  2. ZIP を展開し、Code.exe を起動。

  3. 初回起動時に言語設定・拡張機能の推奨を聞かれますので任意で設定。


2. Remote‑SSH 拡張機能を追加

  1. VS Code 左側バーから Extensions (四角いアイコン) をクリック。
  2. 検索ボックスに Remote - SSH と入力 → Microsoft が配布している拡張機能を選択。
  3. Install ボタンでインストール。
  4. インストール完了後、左下の青いアイコン(>)をクリックし、「Remote-SSH: Connect to Host...」を選びます。

3. Raspberry Pi に SSH 接続設定

(a) Pi の IP アドレス確認

# ターミナルで実行
hostname -I   # 例: 192.168.1.55

(b) Windows から SSH キー生成(PowerShell)

ssh-keygen -t ed25519 -C "your_email@example.com"
# デフォルトの保存場所 (~\.ssh\id_ed25519) をそのまま OK
  • id_ed25519.pub が公開鍵。

(c) 公開鍵を Pi にコピー

scp ~/.ssh/id_ed25519.pub pi@192.168.1.55:~
# ここでパスワードを入力(Pi のユーザー名は通常 `pi`、デフォルトのパスワードは `raspberry`)

(d) Pi 側で公開鍵を登録

ssh pi@192.168.1.55   # パスワード認証でログイン

mkdir -p ~/.ssh
chmod 700 ~/.ssh
cat ~/id_ed25519.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
rm id_ed25519.pub

(e) VS Code の SSH 構成ファイルにホスト追加

VS Code を起動し、左下の青いアイコン > Remote-SSH: Open Configuration File...config を選択。

Host raspberrypi
    HostName 192.168.1.55      # 実際の IP アドレスに置き換えてください
    User pi                    # Pi のユーザー名
    IdentityFile ~/.ssh/id_ed25519   # Windows の秘密鍵パス

Tip: Host は好きな名前で OK。
もし Wi‑Fi が頻繁に変わる場合は HostName を DHCP 固定 IP に設定しておくと便利。


4. Raspberry Pi 上の Python 環境準備

(a) 基本的なパッケージをインストール

sudo apt update
sudo apt install python3 python3-pip python3-venv -y

(b) 仮想環境(オプション)

プロジェクトごとに隔離したい場合は仮想環境を作成します。

# プロジェクトディレクトリへ移動または作成
mkdir ~/myproject && cd ~/myproject

python3 -m venv .venv
source .venv/bin/activate   # activate するとプロンプトが変わる
pip install --upgrade pip setuptools wheel

(c) 必要なパッケージをインストール

# 例: Flask, pandas など
pip install flask pandas

Tip: requirements.txt を使うと再現性が高くなります。

pip freeze > requirements.txt

5. VS Code から Raspberry Pi に接続

  1. 左下の青いアイコン(>)をクリック → Remote-SSH: Connect to Host... → raspberrypi を選択。
  2. 接続確認ダイアログが出たら OK。
  3. 接続後、VS Code のステータスバーに「SSH: raspberrypi」と表示されます。

ファイル操作

  • Explorer で Pi 上のファイルシステムをブラウズできます。
  • 任意の Python ファイル (*.py) をダブルクリックして開くと、ローカルエディタとして扱われます。

ターミナル

  • VS Code の Terminal → New Terminal で リモートターミナル が起動します。
  • ここでは Pi 上のシェルが実行されるので、Python スクリプトを直接走らせたり、仮想環境をアクティベートできます。
source .venv/bin/activate   # 仮想環境を有効化
python script.py

デバッグ

  1. Run → Add Configuration... を選び、Python のデバッグ設定を作成。
  2. 変数やブレークポイントを VS Code 内で管理しつつ、Pi 上で実行されるようになります。

よくあるトラブルと対策

問題原因解決策
SSH 接続がタイムアウトPi がネットワークに接続できていないWi‑Fi のSSID・パスワードを確認。Pi の ifconfig で IP を再確認。
パーミッションエラー (Permission denied (publickey))秘密鍵が正しく設定されていない、または権限不足chmod 600 ~/.ssh/authorized_keys と chmod 700 ~/.ssh を実行。
Python が見つからないPATH が通っていない/usr/bin/python3 のフルパスを指定するか、仮想環境のアクティベーションを忘れずに。
VS Code が Pi 上でファイルを書き換えられないauthorized_keys に書き込み権限がないchmod 600 ~/.ssh/authorized_keys を再確認。

まとめ

  1. VS Code と Remote‑SSH 拡張機能を Windows 11 にインストール
  2. Pi の SSH キー認証を設定
  3. VS Code の config ファイルでホスト情報を登録
  4. Raspberry Pi 上に Python + 必要パッケージ(仮想環境可)を用意
  5. VS Code からリモート接続し、エディタ・ターミナル・デバッグを同じ UI で操作

これで Windows 11 の PC から Raspberry Pi 上の Python 開発がシームレスに行えるようになります。

Happy coding! 🚀