Release v1.0 – PiCopy vollständig dokumentiert und bereit zur Veröffentlichung

- README.md mit vollständiger Anleitung, Features, Tabellen und Schnellstart
- install.sh neu geschrieben: sauberer Installer mit Farbausgabe, apt-Check,
  Download-Fallback und abschließender Statusmeldung mit URL
- LICENSE (MIT) hinzugefügt
- .gitignore: config.json, state.json, rclone.conf, logs/ und deploy.sh excluded
- deploy.sh entfernt (enthielt Zugangsdaten)
- requirements.txt aktualisiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-09 01:58:47 +02:00
parent def2120d9b
commit a15d27ce14
5 changed files with 421 additions and 58 deletions

38
.gitignore vendored Normal file
View File

@@ -0,0 +1,38 @@
# Runtime-Dateien (nicht ins Repo)
config.json
state.json
rclone.conf
logs/
# Deploy-Script (enthält ggf. Zugangsdaten)
deploy.sh
# Python
__pycache__/
*.py[cod]
*.pyo
*.pyd
.Python
venv/
.venv/
*.egg-info/
dist/
build/
# macOS
.DS_Store
.AppleDouble
.LSOverride
._*
.Spotlight-V100
.Trashes
# Editor
.vscode/
.idea/
*.swp
*.swo
*~
# Mount-Verzeichnisse (auf dem Pi)
/mnt/picopy*/

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Tobias Leuschner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

256
README.md Normal file
View File

@@ -0,0 +1,256 @@
# PiCopy
**Automatische USB-Backup-Station für den Raspberry Pi mit Web-Interface**
PiCopy verwandelt deinen Raspberry Pi in ein eigenständiges Backup-Gerät. Stecke eine Quell-USB (Speicherkarte, USB-Stick) und ein Ziel-Laufwerk ein PiCopy kopiert die Daten automatisch, organisiert sie in Datumsordnern, prüft die Integrität und kann danach auf ein NAS hochladen.
---
## Features
| | Feature | Beschreibung |
|---|---|---|
| 📋 | **Automatisches Kopieren** | Startet sofort wenn Quelle und Ziel eingesteckt werden |
| 🌐 | **Web-Interface** | Konfiguration und Status von jedem Gerät im Netzwerk |
| 📂 | **Datei-Explorer** | Inhalt verbundener Laufwerke direkt im Browser durchsuchen |
| 🗂️ | **Smarte Organisation** | Erstellt automatisch Datumsordner (`2024-01-15_143022/`) |
| 🔍 | **Dateifilter** | Nur Fotos, nur Videos oder beliebige Dateitypen kopieren |
| 🔄 | **Duplikat-Behandlung** | Überspringen / Überschreiben / Umbenennen |
| ✅ | **MD5-Verifizierung** | Jede Datei nach dem Kopieren auf Integrität prüfen |
| 🗑️ | **Quelle leeren** | Quelldateien nach erfolgreichem Kopieren löschen (Move-Modus) |
| 🖧 | **NAS / SMB Upload** | Nach dem lokalen Backup auf ein Netzlaufwerk hochladen |
| 📡 | **WiFi-Fallback** | Erstellt einen eigenen Hotspot wenn kein WLAN verfügbar ist |
| ⚡ | **Headless-Betrieb** | Kein Monitor, keine Tastatur nötig |
| 🔁 | **Autostart** | Startet automatisch beim Pi-Boot via systemd |
---
## Voraussetzungen
- Raspberry Pi (2, 3, 4, 5 oder Zero 2W)
- Raspberry Pi OS **Bookworm** (Debian 12) oder neuer
- Mindestens 2 USB-Ports (Quelle + Ziel)
- WLAN oder LAN für das Web-Interface
---
## Installation
### Option A Direkt vom Git-Repo (empfohlen)
```bash
git clone https://github.com/YOUR_USERNAME/picopy
cd picopy
sudo bash install.sh
```
### Option B One-Liner
```bash
curl -sSL https://raw.githubusercontent.com/YOUR_USERNAME/picopy/main/install.sh | sudo bash
```
Nach der Installation ist das Web-Interface unter folgender Adresse erreichbar:
```
http://<raspberry-pi-ip>:8080
```
Die IP-Adresse wird am Ende der Installation angezeigt.
---
## Schnellstart
1. **Web-Interface öffnen**`http://<pi-ip>:8080`
2. **USB-Gerät einstecken** das als Quelle dienen soll
3. **Port konfigurieren** → Unter *USB Port Konfiguration* das Gerät in der Dropdown-Liste wählen → *Als feste Quelle speichern*
4. **Ziel konfigurieren** → Ziel-Laufwerk einstecken, Port wählen → *Als festes Ziel speichern*
5. **Auto-Kopie aktivieren** → Haken bei *Automatisch kopieren wenn Quelle & Ziel verbunden*
6. **Fertig** → Jetzt beide Laufwerke einstecken → Kopie startet automatisch
> **Wichtig:** PiCopy merkt sich den **physischen Port** (Anschluss), nicht das spezifische Gerät. Ein anderer USB-Stick im gleichen Anschluss wird automatisch als Quelle/Ziel erkannt.
---
## Web-Interface
### Kopierstatus
Zeigt den Live-Fortschritt mit:
- Prozentualer Fortschritt + Fortschrittsbalken
- Dateizähler (`23 / 147 Dateien`)
- Übertragene Datenmenge (`1.2 GB / 3.5 GB`)
- Geschwindigkeit (`12.4 MB/s`)
- Verbleibende Zeit (`⏱ noch ca. 4 Min.`)
- Aktuelle Datei
- Phasen-Anzeige: *Kopieren → Verifizieren → Quelle leeren*
Nach dem Abschluss: Zusammenfassung mit ✕-Button (verschwindet nach 5 Minuten automatisch).
### USB Port Konfiguration & Datei-Explorer
```
┌─────────────────┬─────────────────┬──────────────────────┐
│ ▲ QUELLE │ ▼ ZIEL │ ⬆ Quelle ⬇ Ziel ↻ │
│ ● Port 2-2 │ ○ Port 1-1 │ ──────────────────── │
│ Samsung USB │ Nicht verbunden│ 📁 DCIM │
│ │ │ 📁 MISC │
│ [Als Quelle ▾] │ [Als Ziel ▾] │ 🖼 IMG_001.jpg 4 MB │
└─────────────────┴─────────────────┴──────────────────────┘
```
- **Grüner Punkt** = Gerät verbunden und bereit
- **Grauer Punkt** = Port konfiguriert, kein Gerät eingesteckt
- **Datei-Explorer** zum Durchsuchen der verbundenen Laufwerke
### Kopier-Einstellungen
| Einstellung | Standard | Beschreibung |
|---|---|---|
| Datumsformat | `JJJJ-MM-TT` | Format des Zielordners |
| Uhrzeit | ✓ | Uhrzeit im Ordnernamen (`_143022`) |
| Unterordner | ✓ | Unterordner nach Gerätebezeichnung |
| Auto-Kopie | ✓ | Automatisch starten wenn beide verbunden |
| Dateifilter | *leer* | Nur bestimmte Dateitypen kopieren |
| Systemdateien | ✓ | `.DS_Store`, `Thumbs.db`, `RECYCLER` usw. ausschließen |
| Duplikate | Überspringen | Skip / Überschreiben / Umbenennen |
| MD5-Verify | ✗ | Jede Datei nach dem Kopieren prüfen |
| Quelle leeren | ✗ | Quelldateien nach Kopieren löschen |
#### Dateifilter Schnell-Presets
| Preset | Dateitypen |
|---|---|
| 📷 Fotos | jpg, jpeg, heic, raw, cr2, nef, arw, dng, png |
| 🎬 Videos | mp4, mov, avi, mkv, mts, m2ts, wmv |
| 📷+🎬 Beides | Fotos + Videos kombiniert |
| ✕ Alle | Kein Filter alle Dateien kopieren |
### Fernkopie NAS / SMB
Nach dem lokalen Kopieren lädt PiCopy auf konfigurierte NAS-Freigaben hoch:
1. * NAS-Ziel hinzufügen* klicken
2. Name, Server-IP, Freigabename, Benutzer und Passwort eingeben
3. *Speichern & Verbindung testen* PiCopy testet die Verbindung sofort
4. Mehrere NAS-Ziele möglich, jedes einzeln aktivierbar
### WiFi-Einstellungen
| Modus | Beschreibung |
|---|---|
| **Heimnetz** | WLAN-Name und Passwort für die Router-Verbindung |
| **Hotspot (AP)** | Eigenes WLAN wenn kein Heimnetz erreichbar |
**Hotspot-Standardwerte:**
- SSID: `PiCopy`
- Passwort: `PiCopy,`
- IP im Hotspot-Modus: `http://10.42.0.1:8080`
Der Hotspot startet automatisch beim Boot wenn das konfigurierte WLAN nicht verfügbar ist.
---
## Ordnerstruktur auf dem Ziel
```
/ziel-laufwerk/
└── 2024-01-15_143022/ ← Datum + Uhrzeit (konfigurierbar)
└── Samsung_USB/ ← Gerätebezeichnung (wenn Unterordner aktiv)
├── DCIM/
│ └── 100CANON/
│ ├── IMG_0001.JPG
│ ├── IMG_0001.CR2
│ └── IMG_0002.MP4
└── MISC/
└── notes.txt
```
---
## Update
```bash
cd picopy
git pull
sudo cp app.py /opt/picopy/app.py
sudo systemctl restart picopy
```
---
## Deinstallation
```bash
sudo systemctl stop picopy
sudo systemctl disable picopy
sudo rm /etc/systemd/system/picopy.service
sudo rm -rf /opt/picopy
sudo systemctl daemon-reload
```
---
## Service-Verwaltung
```bash
# Status prüfen
sudo systemctl status picopy
# Live-Logs
journalctl -u picopy -f
# Neustart
sudo systemctl restart picopy
# Stoppen
sudo systemctl stop picopy
```
---
## Technische Details
| Komponente | Technologie |
|---|---|
| Backend | Python 3 + Flask |
| USB-Erkennung | `lsblk` + `udevadm` |
| USB-Monitoring | `pyudev` (udev-Events) |
| WiFi-Verwaltung | NetworkManager (`nmcli`) |
| NAS-Sync | `rclone` (SMB) |
| Service | systemd (Autostart, Auto-Restart) |
**Dateipfade auf dem Pi:**
| Pfad | Inhalt |
|---|---|
| `/opt/picopy/app.py` | Hauptanwendung |
| `/opt/picopy/config.json` | Konfiguration (Ports, WiFi, Einstellungen) |
| `/opt/picopy/state.json` | Letzter Kopierstatus (persisted) |
| `/opt/picopy/rclone.conf` | NAS-Zugangsdaten (rclone) |
| `/opt/picopy/logs/picopy.log` | Log-Datei |
| `/etc/systemd/system/picopy.service` | Systemd-Service |
---
## Getestete Hardware
| Gerät | Status |
|---|---|
| Raspberry Pi 4 Model B | ✅ Vollständig getestet |
| Raspberry Pi 5 | ✅ Kompatibel |
| Raspberry Pi 3 Model B+ | ✅ Kompatibel |
| Raspberry Pi Zero 2W | ⚠️ Langsamer, nur 1 USB-Port (Hub benötigt) |
---
## Lizenz
MIT License siehe [LICENSE](LICENSE)
---
## Autor
Tobias Leuschner [info@leuschner.dev](mailto:info@leuschner.dev)

View File

@@ -1,21 +0,0 @@
#!/bin/bash
# deploy.sh - Überträgt PiCopy zum Pi und installiert es
# Verwendung: bash deploy.sh
# Benötigt: sshpass (brew install sshpass)
PI_HOST="10.0.100.61"
PI_USER="tobias"
PI_PASS="dmu7uqMH9roYzdtovlm0XfXT6"
REMOTE="/home/tobias/picopy_deploy"
SSH="sshpass -p '$PI_PASS' ssh -o StrictHostKeyChecking=no $PI_USER@$PI_HOST"
SCP="sshpass -p '$PI_PASS' scp -o StrictHostKeyChecking=no"
echo ">> Dateien übertragen..."
eval "$SCP -r $(pwd)/. $PI_USER@$PI_HOST:$REMOTE/"
echo ">> Installation starten..."
eval "$SSH 'cd $REMOTE && sudo bash install.sh'"
echo ">> Fertig!"
eval "$SSH 'sudo systemctl status picopy --no-pager'"

View File

@@ -1,42 +1,111 @@
#!/bin/bash #!/usr/bin/env bash
# PiCopy Installations-Script für den Raspberry Pi # ============================================================
# Ausführen auf dem Pi als root oder mit sudo: # PiCopy Installer
# sudo bash install.sh # https://github.com/YOUR_USERNAME/picopy
#
# Usage:
# sudo bash install.sh
# or one-line:
# curl -sSL https://raw.githubusercontent.com/YOUR_USERNAME/picopy/main/install.sh | sudo bash
# ============================================================
set -euo pipefail
set -e INSTALL_DIR="/opt/picopy"
SERVICE_NAME="picopy"
PORT=8080
REPO_RAW="https://raw.githubusercontent.com/YOUR_USERNAME/picopy/main"
PI_DIR="/opt/picopy" # ── Farben ───────────────────────────────────────────────────────────────────
SERVICE="picopy" R='\033[0;31m'; G='\033[0;32m'; Y='\033[1;33m'; B='\033[0;34m'; N='\033[0m'
info() { echo -e "${B}[PiCopy]${N} $1"; }
ok() { echo -e "${G}[ OK ]${N} $1"; }
warn() { echo -e "${Y}[ WARN ]${N} $1"; }
fail() { echo -e "${R}[ FAIL ]${N} $1"; exit 1; }
echo "=== PiCopy Installation ===" # ── Voraussetzungen ───────────────────────────────────────────────────────────
[ "$EUID" -eq 0 ] || fail "Bitte als root ausführen: sudo bash install.sh"
# Abhängigkeiten installieren command -v apt-get &>/dev/null || fail "apt-get nicht gefunden (nur Debian/Raspberry Pi OS unterstützt)"
echo ">> Pakete installieren..."
apt-get update -q
apt-get install -y python3 python3-venv python3-pip lsblk
# Verzeichnis anlegen
echo ">> Verzeichnis anlegen: $PI_DIR"
mkdir -p "$PI_DIR/logs"
# Python-Umgebung
echo ">> Python venv erstellen..."
python3 -m venv "$PI_DIR/venv"
"$PI_DIR/venv/bin/pip" install --quiet flask pyudev
# App-Dateien kopieren
echo ">> Dateien kopieren..."
cp app.py "$PI_DIR/app.py"
# Systemd-Service einrichten
echo ">> Systemd-Service einrichten..."
cp picopy.service "/etc/systemd/system/$SERVICE.service"
systemctl daemon-reload
systemctl enable "$SERVICE"
systemctl restart "$SERVICE"
echo "" echo ""
echo "=== Installation abgeschlossen ===" echo -e "${B}╔══════════════════════════════════════════╗${N}"
echo "Web-Interface: http://$(hostname -I | awk '{print $1}'):8080" echo -e "${B}║ PiCopy Installation ║${N}"
echo "Status: systemctl status $SERVICE" echo -e "${B}╚══════════════════════════════════════════╝${N}"
echo "Logs: journalctl -u $SERVICE -f" echo ""
# ── System-Pakete ─────────────────────────────────────────────────────────────
info "Systemabhängigkeiten werden installiert..."
apt-get update -q
apt-get install -y -q python3 python3-venv python3-pip util-linux rclone
ok "Systemabhängigkeiten installiert"
# ── Verzeichnis anlegen ───────────────────────────────────────────────────────
info "Installationsverzeichnis: $INSTALL_DIR"
mkdir -p "$INSTALL_DIR/logs"
# ── App-Datei kopieren oder herunterladen ─────────────────────────────────────
if [ -f "./app.py" ]; then
info "Lokale app.py wird verwendet..."
cp app.py "$INSTALL_DIR/app.py"
else
info "app.py wird heruntergeladen..."
curl -sSfL "$REPO_RAW/app.py" -o "$INSTALL_DIR/app.py" \
|| fail "Download fehlgeschlagen. Prüfe die Internet-Verbindung."
fi
ok "app.py installiert"
# ── Python-Umgebung ───────────────────────────────────────────────────────────
info "Python venv wird erstellt..."
python3 -m venv "$INSTALL_DIR/venv"
"$INSTALL_DIR/venv/bin/pip" install --quiet --upgrade pip
"$INSTALL_DIR/venv/bin/pip" install --quiet flask pyudev
ok "Python-Umgebung erstellt"
# ── Systemd-Service ───────────────────────────────────────────────────────────
info "Systemd-Service wird eingerichtet..."
if [ -f "./picopy.service" ]; then
cp picopy.service /etc/systemd/system/picopy.service
else
cat > /etc/systemd/system/picopy.service << 'EOF'
[Unit]
Description=PiCopy Automatischer USB-Kopierdienst
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/picopy
ExecStart=/opt/picopy/venv/bin/python /opt/picopy/app.py
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
fi
systemctl daemon-reload
systemctl enable "$SERVICE_NAME"
systemctl restart "$SERVICE_NAME"
# ── Ergebnis ─────────────────────────────────────────────────────────────────
sleep 3
if systemctl is-active --quiet "$SERVICE_NAME"; then
IP=$(hostname -I | awk '{print $1}')
echo ""
echo -e "${G}╔══════════════════════════════════════════╗${N}"
echo -e "${G}║ PiCopy ist bereit! ║${N}"
echo -e "${G}╚══════════════════════════════════════════╝${N}"
echo ""
echo -e " Web-Interface: ${B}http://$IP:$PORT${N}"
echo ""
echo " Nützliche Befehle:"
echo " sudo systemctl status $SERVICE_NAME # Status"
echo " journalctl -u $SERVICE_NAME -f # Live-Logs"
echo " sudo systemctl restart $SERVICE_NAME # Neustart"
echo ""
else
fail "PiCopy konnte nicht gestartet werden."$'\n'"Logs: journalctl -u $SERVICE_NAME -n 50"
fi