今天主打「做得到」:
- 家用伺服器三合一(AdGuard Home + Jellyfin + 檔案分享)
- 「看到人就通知」的相機 + 小型 AI
- 休閒娛樂:Kiosk 看板 / 復古遊戲
內文皆為 可直接複製貼上 的純文字,搭配 ASCII 小圖表。
[家用網路] → [Pi 5]
├─ AdGuard Home:全家擋廣告 / 追蹤
├─ Jellyfin:影片影音伺服器
├─ 檔案分享:家中 NAS 小小版
└─ 相機 + AI:偵測到人 → LINE 通知
準備:建議先把系統碟換成 NVMe(官方 M.2 HAT)或至少用 A2 等級 microSD;資料放到
/srv
。
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# 重新登入以套用 docker 群組
sudo apt install -y docker-compose-plugin
compose.yml
sudo mkdir -p /srv/{adguard, jellyfin, media}
sudo chown -R $USER:$USER /srv
cd /srv
tee compose.yml >/dev/null <<'YML'
services:
adguard:
image: adguard/adguardhome:latest
container_name: adguard
restart: unless-stopped
ports:
- "53:53/tcp" # DNS
- "53:53/udp"
- "3000:3000/tcp" # 初次設定精靈
- "80:80/tcp" # 網頁管理(之後可改)
volumes:
- ./adguard/work:/opt/adguardhome/work
- ./adguard/conf:/opt/adguardhome/conf
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
network_mode: host # 播放更穩定
volumes:
- ./jellyfin/config:/config
- ./jellyfin/cache:/cache
- ./media:/media # 你的影片/音樂
YML
啟動:
docker compose up -d
http://<Pi的IP>:3000
進精靈 → 設好你的 Pi 為家中 DNS。http://<Pi的IP>:8096
→ 指向 /srv/media
。迷你 NAS(Samba):最簡單照用戶權限做共享。
sudo apt install -y samba
sudo tee -a /etc/samba/smb.conf >/dev/null <<'CONF'
[public]
path = /srv/media
browseable = yes
writeable = yes
create mask = 0644
directory mask = 0755
guest ok = yes
CONF
sudo systemctl restart smbd
小圖表:家用伺服器資料流
[手機/電腦/TV] ──DNS查詢──> [AdGuard]
│
├─影音串流──> [Jellyfin] ──讀取──> [/srv/media]
│
└─檔案上傳/下載──> [Samba 共享]
加分:把 :80
留給日後的反向代理(Nginx/Caddy),可做 HTTPS 與網域名稱;或把 AdGuard 管理介面改成 :8080
以免衝突。
成本低、成就感高。偵測有人靠近門口 → 立刻傳訊。
sudo apt install -y python3-picamera2 libcamera-apps
pipx install tflite-runtime requests pillow
# 準備一個 TFLite 物件偵測模型(檔名假設為 detect.tflite)
# (可選:下載 COCO 小模型;放到腳本同資料夾即可)
# save as watch_door.py
from picamera2 import Picamera2
from time import sleep, time
import tflite_runtime.interpreter as tflite
import numpy as np
import requests
from PIL import Image
LINE_TOKEN = "填入你的LINE Notify Token"
def line_notify(msg, image_path=None):
headers = {"Authorization": f"Bearer {LINE_TOKEN}"}
data = {"message": msg}
files = {"imageFile": open(image_path, "rb")} if image_path else None
requests.post("https://notify-api.line.me/api/notify",
headers=headers, data=data, files=files)
# 載入 TFLite 模型
interpreter = tflite.Interpreter(model_path="detect.tflite")
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
picam = Picamera2()
picam.configure(picam.create_preview_configuration(main={"size": (640, 480)}))
picam.start(); sleep(1)
last_sent = 0
COOLDOWN = 15 # 同一波動作 15 秒內不重複通知
def preprocess(arr):
h, w = input_details[0]['shape'][1:3]
img = Image.fromarray(arr).resize((w, h))
x = np.expand_dims(np.asarray(img, dtype=np.uint8), 0)
return x
while True:
frame = picam.capture_array()
x = preprocess(frame)
interpreter.set_tensor(input_details[0]['index'], x)
interpreter.invoke()
# 取出結果(不同模型輸出結構略有差異;這裡示意 COCO SSD)
boxes = interpreter.get_tensor(output_details[0]['index'])[0]
classes = interpreter.get_tensor(output_details[1]['index'])[0]
scores = interpreter.get_tensor(output_details[2]['index'])[0]
person_detected = any((c == 0 and s > 0.6) for c, s in zip(classes, scores)) # COCO: class 0=person
now = time()
if person_detected and now - last_sent > COOLDOWN:
path = "snapshot.jpg"
Image.fromarray(frame).save(path)
line_notify("門口有人~(Pi 5 報告)", image_path=path)
last_sent = now
sleep(0.3)
mkdir -p ~/apps/doorwatch && mv watch_door.py ~/apps/doorwatch/
tee ~/.config/systemd/user/doorwatch.service >/dev/null <<'UNIT'
[Unit]
Description=Pi5 Door Watch (TFLite + Picamera2)
[Service]
ExecStart=/usr/bin/python3 /home/%u/apps/doorwatch/watch_door.py
Restart=always
Environment=PYTHONUNBUFFERED=1
WorkingDirectory=/home/%u/apps/doorwatch
[Install]
WantedBy=default.target
UNIT
systemctl --user daemon-reload
systemctl --user enable --now doorwatch
資料流小圖
[Camera] → [TFLite 推論] → (有人?) → [拍照] → [LINE Notify]
小挑戰:把
person
換成「辨識貓咪就丟訊息」;或限制時間:只有晚上 11 點到早上 6 點通知。
sudo raspi-config # 設定開機進桌面 & 自動登入(如果還沒設)
mkdir -p ~/.config/systemd/user
tee ~/.config/systemd/user/kiosk-browser.service >/dev/null <<'UNIT'
[Unit]
Description=Kiosk Browser (Chromium)
[Service]
ExecStart=/usr/bin/chromium-browser --kiosk --noerrdialogs --disable-infobars \
--check-for-update-interval=31536000 --app=https://calendar.google.com/
Restart=always
[Install]
WantedBy=default.target
UNIT
systemctl --user daemon-reload
systemctl --user enable --now kiosk-browser
--app=URL
換成你要的公司儀表板 / 家庭行事曆 / Home Assistant 等網址。Pi 5 支援雙 4K,左邊放看板、右邊看 Jellyfin,超實用。
安裝 RetroPie → 配置手把 → 加入 ROMs → 開玩
/srv/media/roms
,方便日後備份;手把用藍牙連比 USB 省線。即時觀察
htop # 美美的互動版 top
vcgencmd measure_temp # 溫度
watch -n 2 "df -h | head -n 2; free -h"
健康檢查(建議每週執行一次)
CPU 溫度: < 70°C(長期) ✔ 良好
系統負載: 1min 負載 < 3 ✔ 正常
儲存空間: 使用率 < 80% ✔ 安心
網路封包損失:< 1% ✔ 穩定
AdGuard 開不起來?
:53
被占用。關掉系統自帶的 systemd-resolved
或把容器的 DNS 端口改到 :5353
,再把路由器指到該埠。
Jellyfin 撥放卡卡?
改用 network_mode: host
(已在 compose 範例),或把媒體檔放在 NVMe;Wi-Fi 太擁塞請改用有線。
LINE 圖片收不到?
Token 是否有 notify
權限?files
參數拼對了嗎?圖片檔案大小 < 10MB。
開機未自動跑 AI 程式?
檢查 systemctl --user status doorwatch
;必要時 journalctl --user -u doorwatch -e
查看錯誤。
/srv
資料目錄並可從電腦存取htop
/ watch
觀察系統健康