🌦️☀️ Automatisiere deine Markise mit Home Assistant und örtlichen Wetterdaten! ☁️🌬️

Viele Smart-Home-Systeme greifen auf allgemeine Wetterdaten zurück. Diese sind allerdings häufig ungenau oder zu weit vom eigenen Standort entfernt. Ich zeige dir, wie du die Daten einer örtlichen Wetterstation von einer Webseite ausliest und für deine Automatisierungen nutzen kannst – ganz einfach mit Home Assistant!

🔧 Voraussetzungen

Um das Ganze umzusetzen, benötigst du:

  • Eine installierte und eingerichtete Instanz von Home Assistant
  • Zugriff auf eine Webseite mit Wetterdaten einer lokalen Wetterstation
  • Grundkenntnisse in Automatisierungen und Template-Sensoren in Home Assistant

🧩 Wetterdaten abrufen – So funktioniert’s

Wir nutzen die Integration von Wetterdaten über RESTful Sensoren, um Informationen wie:

  • Regenstatus
  • Windgeschwindigkeit
  • Wetterlage (z.B. sonnig, bewölkt)
  • Temperatur

auszulesen. Diese Daten werden anschließend in eigene Sensoren überführt, die Home Assistant versteht und in Automatisierungen verwendet.

Zunächst müssen wir uns auf die Seite von Weather Underground begeben. Dort lasst euch den Quelltext anzeigen und kopiert diesen in einen Editor Tool ( z.B. von Windows).

Um den API Eintrag zu finden, sucht nach der Zeichenkette

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
https://api.weather.com/v2/pws/observations/current
https://api.weather.com/v2/pws/observations/current
https://api.weather.com/v2/pws/observations/current

Kopiert euch die gesamte Zeichenkette inklusive apiKey und stationId und passt den Inhalt wie folgt an.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
https://api.weather.com/v2/pws/observations/current?apiKey=**deinAPI-KEY**&stationId=**deineStationID**&numericPrecision=decimal&format=json&units=m
https://api.weather.com/v2/pws/observations/current?apiKey=**deinAPI-KEY**&stationId=**deineStationID**&numericPrecision=decimal&format=json&units=m
https://api.weather.com/v2/pws/observations/current?apiKey=**deinAPI-KEY**&stationId=**deineStationID**&numericPrecision=decimal&format=json&units=m

die „**“ sind nur zur eindeutigen Identifizierung zu verstehen und nicht dem Key und der StationID hinzuzufügen!

Als nächstes geht mit dem Editor eurer Wahl ( z.B. File Editor oder Studio Code Server ) in eurer Home Assistant Instanz und fügt in der configuration.yaml einen neuen Rest Sensor ein.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
rest:
- resource: https://api.weather.com/v2/pws/observations/current?apiKey=**deinAPI-KEY**&stationId=**deineStationID**&numericPrecision=decimal&format=json&units=m
scan_interval: 600
sensor:
- name: Wetterstation Lahr
unique_id: 82413cbe-2261-4d41-a7f4-c271cba75645 #hier musst du eine eigene eindeutige ID erstellen !
value_template: >
{{ value_json.observations[0].metric.temp }}
json_attributes:
- observations
rest: - resource: https://api.weather.com/v2/pws/observations/current?apiKey=**deinAPI-KEY**&stationId=**deineStationID**&numericPrecision=decimal&format=json&units=m scan_interval: 600 sensor: - name: Wetterstation Lahr unique_id: 82413cbe-2261-4d41-a7f4-c271cba75645 #hier musst du eine eigene eindeutige ID erstellen ! value_template: > {{ value_json.observations[0].metric.temp }} json_attributes: - observations
rest:
  - resource: https://api.weather.com/v2/pws/observations/current?apiKey=**deinAPI-KEY**&stationId=**deineStationID**&numericPrecision=decimal&format=json&units=m
    scan_interval: 600 
    sensor:
      - name: Wetterstation Lahr
        unique_id: 82413cbe-2261-4d41-a7f4-c271cba75645 #hier musst du eine eigene eindeutige ID erstellen !
        value_template: >
          {{ value_json.observations[0].metric.temp }}
        json_attributes:
          - observations

Hinweis: Bitte geht nicht unter 600 Sekunden beim Scan Interval. In der Regel sehen es die Betreiber einer Website nicht gerne , wenn zu viele Abfragen von einer IP – Adresse kommen. Mit den 600 Sekunden solltet ihr auf der sicheren Seite sein.

⚙️ Automatisierung der Markise

Die Logik ist einfach:

  • Wenn es regnet oder starker Wind herrscht, fährt die Markise automatisch ein.
  • Bei Sonne und angenehmen Bedingungen fährt sie aus.

Die Automatisierung lässt sich natürlich noch weiter verfeinern – zum Beispiel durch Tageszeiten oder Anwesenheit.

Template Helfer Sensoren erstellen

Der nächste wichtige Schritt ist aus den Daten, die nun im Sensor Wetterstation Lahr (obervations) stehen alle relevanten Daten für eine Automatisierung auszulesen.

Dazu legt euch 4 Helfer an vom Typ Template Sensor

Hinweis: Bei mir habe ich die Wetterstation „’sensor.wetterstation_lahr“ genannt. Hier müsst ihr in allen Code Zeilen den von euch vergebenen Namen verwenden!

Wetterstation Lahr Windgeschwindigkeit

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{{ state_attr('sensor.wetterstation_Lahr', 'observations')[0]['metric']['windSpeed'] }}
{{ state_attr('sensor.wetterstation_Lahr', 'observations')[0]['metric']['windSpeed'] }}
{{ state_attr('sensor.wetterstation_Lahr', 'observations')[0]['metric']['windSpeed'] }}

Einheit : km/h

Wetterstation Lahr Wetterlage

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{% set obs = state_attr('sensor.wetterstation_Lahr', 'observations')[0] %}
{% set radiation = obs['solarRadiation'] %}
{% set uv = obs['uv'] %}
{% set precip = obs['metric']['precipRate'] %}
{% if precip > 0 %}
regen
{% elif radiation < 100 or uv <= 1 %}
bewölkt
{% elif radiation < 500 or uv < 3 %}
leicht bewölkt
{% else %}
sonnig
{% endif %}
{% set obs = state_attr('sensor.wetterstation_Lahr', 'observations')[0] %} {% set radiation = obs['solarRadiation'] %} {% set uv = obs['uv'] %} {% set precip = obs['metric']['precipRate'] %} {% if precip > 0 %} regen {% elif radiation < 100 or uv <= 1 %} bewölkt {% elif radiation < 500 or uv < 3 %} leicht bewölkt {% else %} sonnig {% endif %}
{% set obs = state_attr('sensor.wetterstation_Lahr', 'observations')[0] %}
{% set radiation = obs['solarRadiation'] %}
{% set uv = obs['uv'] %}
{% set precip = obs['metric']['precipRate'] %}
{% if precip > 0 %}
   regen
{% elif radiation < 100 or uv <= 1 %}
   bewölkt
{% elif radiation < 500 or uv < 3 %}
   leicht bewölkt
{% else %}
   sonnig
{% endif %}

Einheit: keine

Wetterstation Lahr Temperatur

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{{ state_attr('sensor.wetterstation_Lahr', 'observations')[0]['metric']['temp'] }}
{{ state_attr('sensor.wetterstation_Lahr', 'observations')[0]['metric']['temp'] }}
{{ state_attr('sensor.wetterstation_Lahr', 'observations')[0]['metric']['temp'] }}

Einheit: °C

Wetterstation Lahr Regen

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{{ state_attr('sensor.wetterstation_Lahr', 'observations')[0]['metric']['precipRate'] > 0 }}
{{ state_attr('sensor.wetterstation_Lahr', 'observations')[0]['metric']['precipRate'] > 0 }}
{{ state_attr('sensor.wetterstation_Lahr', 'observations')[0]['metric']['precipRate'] > 0 }}

Einheit: keine

Automatisierung Markise steuern

Sobald

Und wenn

Dann

Gesamter Yaml Code

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
alias: Markise steuern
description: Steuert die Markise basierend auf den Wetterbedingungen
triggers:
- entity_id: sensor.wetterstation_lahr_temperatur
above: 18
id: Temperatur hoch
trigger: numeric_state
- entity_id: sensor.wetterstation_lahr_temperatur
below: 18.1
id: Temperatur niedrig
trigger: numeric_state
- entity_id: sensor.wetterstation_lahr_wetterlage
to: regen
id: Regen
trigger: state
- entity_id: sensor.wetterstation_lahr_wetterlage
to: sonnig
id: Sonnig
trigger: state
- entity_id: sensor.wetterstation_lahr_wetterlage
to: leicht bewölkt
id: Leicht bewölkt
trigger: state
- entity_id: sensor.wetterstation_lahr_wetterlage
to: bewölkt
id: Bewölkt
trigger: state
- entity_id: sensor.wetterstation_lahr_windgeschwindigkeit
above: 22
id: Windgeschwindigkeit hoch
trigger: numeric_state
- entity_id: sensor.wetterstation_lahr_windgeschwindigkeit
below: 22.1
id: Windgeschwindigkeit niedrig
trigger: numeric_state
conditions:
- condition: time
after: "10:00:00"
before: "19:00:00"
actions:
- choose:
- conditions:
- condition: or
conditions:
- condition: state
entity_id: sensor.wetterstation_lahr_wetterlage
state: regen
- condition: numeric_state
entity_id: sensor.wetterstation_lahr_windgeschwindigkeit
above: 22
- condition: numeric_state
entity_id: sensor.wetterstation_lahr_temperatur
below: 18.1
sequence:
- entity_id: switch.markise_markise2
action: switch.turn_on
alias: Markise einfahren
alias: Schlechte Wetterlage -> Markise einfahren
- conditions:
- condition: and
conditions:
- condition: numeric_state
entity_id: sensor.wetterstation_lahr_temperatur
above: 18
- condition: numeric_state
entity_id: sensor.wetterstation_lahr_windgeschwindigkeit
below: 22.1
- condition: or
conditions:
- condition: state
entity_id: sensor.wetterstation_lahr_wetterlage
state: sonnig
- condition: state
entity_id: sensor.wetterstation_lahr_wetterlage
state: leicht bewölkt
- condition: state
entity_id: sensor.wetterstation_lahr_wetterlage
state: bewölkt
alias: Gute Wetterlage -> Markise ausfahren
sequence:
- entity_id: switch.markise
action: switch.turn_on
alias: Markise ausfahren
mode: single
alias: Markise steuern description: Steuert die Markise basierend auf den Wetterbedingungen triggers: - entity_id: sensor.wetterstation_lahr_temperatur above: 18 id: Temperatur hoch trigger: numeric_state - entity_id: sensor.wetterstation_lahr_temperatur below: 18.1 id: Temperatur niedrig trigger: numeric_state - entity_id: sensor.wetterstation_lahr_wetterlage to: regen id: Regen trigger: state - entity_id: sensor.wetterstation_lahr_wetterlage to: sonnig id: Sonnig trigger: state - entity_id: sensor.wetterstation_lahr_wetterlage to: leicht bewölkt id: Leicht bewölkt trigger: state - entity_id: sensor.wetterstation_lahr_wetterlage to: bewölkt id: Bewölkt trigger: state - entity_id: sensor.wetterstation_lahr_windgeschwindigkeit above: 22 id: Windgeschwindigkeit hoch trigger: numeric_state - entity_id: sensor.wetterstation_lahr_windgeschwindigkeit below: 22.1 id: Windgeschwindigkeit niedrig trigger: numeric_state conditions: - condition: time after: "10:00:00" before: "19:00:00" actions: - choose: - conditions: - condition: or conditions: - condition: state entity_id: sensor.wetterstation_lahr_wetterlage state: regen - condition: numeric_state entity_id: sensor.wetterstation_lahr_windgeschwindigkeit above: 22 - condition: numeric_state entity_id: sensor.wetterstation_lahr_temperatur below: 18.1 sequence: - entity_id: switch.markise_markise2 action: switch.turn_on alias: Markise einfahren alias: Schlechte Wetterlage -> Markise einfahren - conditions: - condition: and conditions: - condition: numeric_state entity_id: sensor.wetterstation_lahr_temperatur above: 18 - condition: numeric_state entity_id: sensor.wetterstation_lahr_windgeschwindigkeit below: 22.1 - condition: or conditions: - condition: state entity_id: sensor.wetterstation_lahr_wetterlage state: sonnig - condition: state entity_id: sensor.wetterstation_lahr_wetterlage state: leicht bewölkt - condition: state entity_id: sensor.wetterstation_lahr_wetterlage state: bewölkt alias: Gute Wetterlage -> Markise ausfahren sequence: - entity_id: switch.markise action: switch.turn_on alias: Markise ausfahren mode: single
alias: Markise steuern
description: Steuert die Markise basierend auf den Wetterbedingungen
triggers:
  - entity_id: sensor.wetterstation_lahr_temperatur
    above: 18
    id: Temperatur hoch
    trigger: numeric_state
  - entity_id: sensor.wetterstation_lahr_temperatur
    below: 18.1
    id: Temperatur niedrig
    trigger: numeric_state
  - entity_id: sensor.wetterstation_lahr_wetterlage
    to: regen
    id: Regen
    trigger: state
  - entity_id: sensor.wetterstation_lahr_wetterlage
    to: sonnig
    id: Sonnig
    trigger: state
  - entity_id: sensor.wetterstation_lahr_wetterlage
    to: leicht bewölkt
    id: Leicht bewölkt
    trigger: state
  - entity_id: sensor.wetterstation_lahr_wetterlage
    to: bewölkt
    id: Bewölkt
    trigger: state
  - entity_id: sensor.wetterstation_lahr_windgeschwindigkeit
    above: 22
    id: Windgeschwindigkeit hoch
    trigger: numeric_state
  - entity_id: sensor.wetterstation_lahr_windgeschwindigkeit
    below: 22.1
    id: Windgeschwindigkeit niedrig
    trigger: numeric_state
conditions:
  - condition: time
    after: "10:00:00"
    before: "19:00:00"
actions:
  - choose:
      - conditions:
          - condition: or
            conditions:
              - condition: state
                entity_id: sensor.wetterstation_lahr_wetterlage
                state: regen
              - condition: numeric_state
                entity_id: sensor.wetterstation_lahr_windgeschwindigkeit
                above: 22
              - condition: numeric_state
                entity_id: sensor.wetterstation_lahr_temperatur
                below: 18.1
        sequence:
          - entity_id: switch.markise_markise2
            action: switch.turn_on
            alias: Markise einfahren
        alias: Schlechte Wetterlage -> Markise einfahren
      - conditions:
          - condition: and
            conditions:
              - condition: numeric_state
                entity_id: sensor.wetterstation_lahr_temperatur
                above: 18
              - condition: numeric_state
                entity_id: sensor.wetterstation_lahr_windgeschwindigkeit
                below: 22.1
              - condition: or
                conditions:
                  - condition: state
                    entity_id: sensor.wetterstation_lahr_wetterlage
                    state: sonnig
                  - condition: state
                    entity_id: sensor.wetterstation_lahr_wetterlage
                    state: leicht bewölkt
                  - condition: state
                    entity_id: sensor.wetterstation_lahr_wetterlage
                    state: bewölkt
            alias: Gute Wetterlage -> Markise ausfahren
        sequence:
          - entity_id: switch.markise
            action: switch.turn_on
            alias: Markise ausfahren
mode: single

Um die Markise um 19:00 Uhr generell wieder einzufahren habe ich eine separate Automatisierung erstellt. Es wäre auch möglich in jedem „Optionsblock“ die Bedingung zwischen 10:00 Uhr – 19:00 Uhr vorzuschalten, ich fand die Variante mit einer separaten Automatisierung in diesem Fall allerdings sinnvoller.

Automatisierung Markise um 19:00 Uhr einfahren

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
alias: Markise einfahren
description: ""
triggers:
- trigger: time
at: "19:00:00"
conditions: []
actions:
- action: switch.turn_on
metadata: {}
data: {}
target:
entity_id: switch.markise_markise2
mode: single
alias: Markise einfahren description: "" triggers: - trigger: time at: "19:00:00" conditions: [] actions: - action: switch.turn_on metadata: {} data: {} target: entity_id: switch.markise_markise2 mode: single
alias: Markise einfahren
description: ""
triggers:
  - trigger: time
    at: "19:00:00"
conditions: []
actions:
  - action: switch.turn_on
    metadata: {}
    data: {}
    target:
      entity_id: switch.markise_markise2
mode: single

Hinweis: Wie schon im Video erwähnt, ist der Code nicht ausgiebig getestet. Gerne dürft ihr mir in den Youtube Kommentaren erweiterte Varianten oder angepassten Lösungen vorstellen, ich würde diese dann auf meiner Blog Seite veröffentlichen.

🔒 Cyber Security im Smart Home – Wie sicher ist dein Netzwerk wirklich?

In diesem Video dreht sich alles um die Sicherheit im Smart Home! Ich spreche mit meinem Gast, einem YouTube-Kollegen, der sich intensiv mit der Unifi-Welt auseinandersetzt. Gemeinsam gehen wir auf typische Sicherheitsrisiken ein, teilen praktische Tipps und analysieren echte Angriffsbeispiele.

In der heutigen Zeit haben viele von uns unzählige Geräte im Heimnetzwerk. Doch wie gut sind diese eigentlich geschützt? Welche Maßnahmen kann man ergreifen, um das eigene Smart Home sicherer zu machen? Das Video gibt Antworten auf diese Fragen und bietet wertvolle Einblicke in den Bereich der Smart Home-Sicherheit.

💡 Themen im Video:

  • Sicherheitslücken in typischen Smart Home Setups
  • Tipps zur Absicherung deines Netzwerks
  • UniFi Firewalls & Best Practices
  • Erfahrungen aus der Praxis und ein Blick auf meine eigenen Firewall-Settings

Ob du gerade erst mit Smart Home beginnst oder bereits ein Fortgeschrittener bist – hier ist garantiert etwas für dich dabei!

Schau dir das Video an und lass uns in den Kommentaren wissen, wie du dein Netzwerk absicherst oder ob du noch Fragen hast. Ich freue mich auf den Austausch!

Ein besonderer Dank geht an Jan, der sich sofort bereit erklärt hat, mich mit seiner Expertise in diesem Video zu unterstützen. Schaut gerne mal bei ihm vorbei und abonniert seinen Kanal!

👉 Seinen Kanal findet ihr hier: @JanPoertner

Eine komplette Playlist aller seiner UniFi Videos findet ihr auch hier:
https://youtube.com/playlist?list=PLcKKIJBFoNTEtFXlUC9Sg12RA7v_8JHpg&si=XWu0-KVeMMTSSpxG

Anbei noch ein paar Gateways, die ich für den Einsatz als Firewall empfehlen kann*:

Das Cloud Gateway Ultra ist ein günstiger Einstieg, der aus meiner Sicht alle Netzwerkfunktionen, die man im normalen Hausgebrauch benötigt abdeckt. Ich habe diese Variante selber auch als Backup für meine UDM Pro im Einsatz und bin sehr zufrieden mit der Leistung. Ein Backup der UDM Pro lässt sich ohne Probleme in wenigen Minuten auf das Cloud Gateway Ultra aufspielen.

Sale
Ubiquiti Cloud Gateway Ultra – UCG-Ultra
  • Läuft UniFi-Netzwerk für Full-Stack-Netzwerkverwaltung
  • Verwaltet über 30 UniFi-Netzwerkgeräte und über 300 Clients
  • 1 Gbit/s Routing mit IDS/IPS
  • Multi-WAN-Lastausgleich
  • 2,4 cm LCM-Statusanzeige

Wenn man etwas mehr Leistung benötigt, gibt es den größeren Bruder des UCG Ultra, das Cloud Gateway Max. Mehr IPS Durchsatz, Protect etc.. ist damit umsetzbar.

Sale
Ubiquiti UniFi Cloud Gateway Max
  • NETZWERKLEISTUNG: Hochleistungs-Router mit fortschrittlicher UniFi-Technologie für professionelles Netzwerkmanagement
  • CLOUD-VERWALTUNG: Einfache Konfiguration und Überwachung über die UniFi Cloud-Plattform mit Echtzeitanalysen
  • SICHERHEITSFUNKTIONEN: Integrierte Firewall und erweiterte Sicherheitsprotokolle zum Schutz des Netzwerks
  • ANSCHLUSSVIELFALT: Mehrere Gigabit-Ethernet-Ports für flexible Netzwerkanbindung und Erweiterungsmöglichkeiten
  • ENTERPRISE-FUNKTIONEN: Unterstützung für VLANs, fortgeschrittenes Routing und QoS-Management für optimale Netzwerkleistung

In der folgenden Tabelle habe ich euch noch ein paar Unifi Produkte aufgelistet, die ich gerne einsetze und wo ich sehr zufrieden mit bin.

📂 Paperless NGX: Dokumente synchronisieren mit OneDrive, Nextcloud, WebDAV & mehr! 🔄☁️

In diesem Video zeige ich dir, wie du gescannte Dokumente direkt in die Cloud schicken und mit Paperless NGX automatisch verarbeiten lassen kannst. Dafür stelle ich ein Tool für Linux vor, mit dem du die Synchronisation mit OneDrive, Nextcloud, WebDAV & viele andere Dienste einrichtest. 🖨️➡️📂 🔹 Themen im Video:

✔️ Installation und Einrichtung des Synchronisationstools unter Linux 🐧

✔️ Automatisches „Herunterladen“ gescannter Dokumente 📤

✔️ Effiziente Dokumentenverwaltung mit Paperless NGX 📑

Das Video zur Installation von paperless ngx: https://youtu.be/WRyBPMH9zf0

Blogbeitrag zum Video: https://blog.smarthomeundmore.de/paperless-ngx-komplett-einrichten-mit-rest-api-home-assistant-sensor/

Das Tool kannst du aber auch unter Linux für viele weitere Aufgaben verwenden.

Im Video habe ich ein paar Befehle verwendet. Damit ihr die Syntax nicht „kompliziert“ aus dem Video ablesen müsst, habe ich euch die wichtigsten Kommandos in diesem Blog Beitrag zusammengefasst.

Installation von rclone unter Linux ( getestet mit Ubuntu 24.10)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
sudo apt-get install rclone
sudo apt-get install rclone
sudo apt-get install rclone

Die wichtigsten rclone Befehle kurz zusammengefasst. Im Video habe ich für „remote:“ den Namen onedrive verwendet.

Grundlegende Befehle

  • rclone config – Konfiguration von Remotes (z. B. OneDrive,Google Drive, Dropbox).
  • rclone listremotes – Zeigt alle konfigurierten Remotes.
  • rclone lsd remote: – Listet die Verzeichnisse im Root des Remotes auf.
  • rclone ls remote: – Zeigt alle Dateien und Verzeichnisse im Remote an.
  • rclone copy Quelle Ziel – Kopiert Dateien/Ordner von einer Quelle zu einem Ziel.
  • rclone sync Quelle Ziel – Synchronisiert Quelle mit Ziel (Achtung: Ziel wird überschrieben!).
  • rclone move Quelle Ziel – Verschiebt Dateien von Quelle nach Ziel.
  • rclone delete remote:Ordner – Löscht alle Dateien in einem Remote-Ordner.
  • rclone rmdir remote:Ordner – Löscht einen leeren Remote-Ordner.

Erweiterte Befehle

  • rclone check Quelle Ziel – Vergleicht Dateien zwischen Quelle und Ziel.
  • rclone mount remote: /lokaler/pfad – Mountet ein Remote-Laufwerk als lokales Verzeichnis.
  • rclone dedupe remote: – Findet und entfernt doppelte Dateien.
  • rclone about remote: – Zeigt Speicherinformationen des Remotes an.
  • rclone size remote: – Zeigt die Größe aller Dateien im Remote an.

Hinweis: rclone mount wird in einem unpriviligierten Container nicht funktionieren. Wenn ihr ein smb/cifs Laufwerk mounten möchtet, so empfehle ich euch eine „echte“ virtuelle Maschine zu verwenden. Alle „grundlegenden Befehle“ können hingegen ohne Einschränkungen verwendet werden.

Um einen Scheduler ( Zeitplan ) für einen „Kopiervorgang“ zu definieren müsst ihr zunächst einen „crontab“ Eintrag erstellen.

Ein Crontab (kurz für Cron Table) ist eine Datei, die geplante Aufgaben (Cron-Jobs) für das cron-Daemon unter Linux und Unix-basierten Systemen speichert. Diese Jobs werden zu festgelegten Zeiten oder in bestimmten Intervallen automatisch ausgeführt.

Wichtige Befehle für Crontab

  • crontab -e – Bearbeitet die Crontab-Datei des aktuellen Benutzers.
  • crontab -l – Listet alle aktuell gesetzten Cron-Jobs auf.
  • crontab -r – Löscht alle Cron-Jobs des aktuellen Benutzers.

Crontab-Syntax

Eine Crontab-Zeile besteht aus fünf Zeitfeldern und dem auszuführenden Befehl:

* * * * * /pfad/zum/befehl.sh
- - - - -
| | | | |
| | | | +---- Wochentag (0 - Sonntag, 6 - Samstag)
| | | +------ Monat (1-12)
| | +-------- Tag des Monats (1-31)
| +---------- Stunde (0-23)
+------------ Minute (0-59)

Wir öffnen also den „Crontab Editor“ mit

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
crontab -e
crontab -e
crontab -e

und wählen „nano“ als Editor aus.

Dann fügen wir folgende Zeile im Crontab Editor ein.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
*/5 * * * * /usr/bin/rclone move onedrive:scans /data/paperless/consume --progress
*/5 * * * * /usr/bin/rclone move onedrive:scans /data/paperless/consume --progress
*/5 * * * * /usr/bin/rclone move onedrive:scans /data/paperless/consume --progress

Mit Strg++X speichern wir diesen Vorgang. Denkt daran den Namen eures Remote Laufwerks anzupassen.

Jetzt wird alle 5 Minuten auf dem Cloud Laufwerk geschaut, ob sich Daten im Verzeichnis „scans“ befinden. Ist das der Fall, werden diese Daten in den „consume“ Ordner von paperless verschoben.

📢 Home Assistant Notifications – So wird’s einfacher! 📢

In diesem Video zeige ich dir, wie du Benachrichtigungen in Home Assistant deutlich einfacher verwalten kannst! 🚀 Normalerweise muss man in jeder Automatisierung festlegen, wer welche Nachricht bekommt – sei es die Frau, die Kids oder man selbst. Dazu kommen noch kritische Benachrichtigungen, die extra Aufmerksamkeit erfordern. Ich habe eine Lösung entwickelt, mit der du das Ganze zentral steuern kannst. Selbst wenn sich Geräte ändern, musst du nicht stundenlang deine Automatisierungen anpassen. 🔄

Um das Skript einzufügen, begib dich zu Home Assistant Skripte , lege eine neues Skript an und wähle über die drei Punkte in der rechten oberen Ecke die YAML Bearbeitung aus. Dort kannst du das unten aufgeführte Skript dann einfügen. Wichtig ! Die Dienstnamen für die Benachrichtigungen der Alexa-Media Player Devices oder auch Mobile Geräte müssen in der Variable „targets“ angepasst werden.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
sequence:
- variables:
push_data: |-
{% if critical %} {
"push": {
"sound": {
"name": "default",
"critical": 1,
"volume": 1.0
}
}
} {% else %} {} {% endif %}
alias: push_data Variable, um den Channel "Critical" beim Iphone zu abonnieren
- variables:
targets: |-
{% set t = [] %}
{% if group_admins %}
{% set t = t + ["notify.mobile_app_iphone_tobias"] %}
{% endif %}
{% if group_family %}
{% set t = t + ["notify.mobile_app_iphone_tobias", "notify.mobile_app_slerch","notify.alexa_media_bad_oben"] %}
{% endif %}
{% if alexa %}
{% set t = t + ["notify.alexa_media_keller"] %}
{% endif %}
{{ t | unique | list }}
alias: targets für alle gewünschten "notify" Dienste
- variables:
alexa_devices: "{{ targets | select('search', 'notify.alexa_media') | list }}"
alias: "alexa_devices : Filter um nur die alexa Devices für den Dienst zu filtern"
- variables:
media_players: >
{% set media_players = alexa_devices | map('replace',
'notify.alexa_media_', 'media_player.') | list %} {{ media_players }}
alias: >-
media_players: Aus dem Dienst werden automatisch alle Media_Player
Entitätsnamen abgeleitet.
- variables:
volume_level: |
{% if critical %}
0.8
{% else %}
0.2
{% endif %}
alias: >-
volume_level: Wenn critical aktiviert ist, wir eine andere Lautstärke
gewählt , anonsten default für die Ausgabe
- repeat:
for_each: "{{ media_players }}"
sequence:
- action: media_player.volume_set
metadata: {}
data:
volume_level: "{{ volume_level }}"
target:
entity_id: "{{ repeat.item }}"
enabled: true
- repeat:
sequence:
- action: "{{ repeat.item }}"
data:
title: "{{ title }}"
message: "{{ message }}"
data: "{{ push_data }}"
for_each: "{{ targets }}"
enabled: true
- delay:
hours: 0
minutes: 0
seconds: 5
milliseconds: 0
- repeat:
for_each: "{{ media_players }}"
sequence:
- action: media_player.volume_set
metadata: {}
data:
volume_level: 0.1
target:
entity_id: "{{ repeat.item }}"
enabled: true
- action: persistent_notification.create
metadata: {}
data:
message: "{{ targets }}"
alias: Notify All V2
description: ""
fields:
message:
selector:
text:
multiline: true
name: message
title:
selector:
text: null
name: title
group_admins:
selector:
boolean: {}
name: group_admins
required: true
group_family:
selector:
boolean: {}
name: group_family
required: true
critical:
selector:
boolean: {}
name: critical
required: true
alexa:
selector:
boolean: {}
name: alexa
required: true
sequence: - variables: push_data: |- {% if critical %} { "push": { "sound": { "name": "default", "critical": 1, "volume": 1.0 } } } {% else %} {} {% endif %} alias: push_data Variable, um den Channel "Critical" beim Iphone zu abonnieren - variables: targets: |- {% set t = [] %} {% if group_admins %} {% set t = t + ["notify.mobile_app_iphone_tobias"] %} {% endif %} {% if group_family %} {% set t = t + ["notify.mobile_app_iphone_tobias", "notify.mobile_app_slerch","notify.alexa_media_bad_oben"] %} {% endif %} {% if alexa %} {% set t = t + ["notify.alexa_media_keller"] %} {% endif %} {{ t | unique | list }} alias: targets für alle gewünschten "notify" Dienste - variables: alexa_devices: "{{ targets | select('search', 'notify.alexa_media') | list }}" alias: "alexa_devices : Filter um nur die alexa Devices für den Dienst zu filtern" - variables: media_players: > {% set media_players = alexa_devices | map('replace', 'notify.alexa_media_', 'media_player.') | list %} {{ media_players }} alias: >- media_players: Aus dem Dienst werden automatisch alle Media_Player Entitätsnamen abgeleitet. - variables: volume_level: | {% if critical %} 0.8 {% else %} 0.2 {% endif %} alias: >- volume_level: Wenn critical aktiviert ist, wir eine andere Lautstärke gewählt , anonsten default für die Ausgabe - repeat: for_each: "{{ media_players }}" sequence: - action: media_player.volume_set metadata: {} data: volume_level: "{{ volume_level }}" target: entity_id: "{{ repeat.item }}" enabled: true - repeat: sequence: - action: "{{ repeat.item }}" data: title: "{{ title }}" message: "{{ message }}" data: "{{ push_data }}" for_each: "{{ targets }}" enabled: true - delay: hours: 0 minutes: 0 seconds: 5 milliseconds: 0 - repeat: for_each: "{{ media_players }}" sequence: - action: media_player.volume_set metadata: {} data: volume_level: 0.1 target: entity_id: "{{ repeat.item }}" enabled: true - action: persistent_notification.create metadata: {} data: message: "{{ targets }}" alias: Notify All V2 description: "" fields: message: selector: text: multiline: true name: message title: selector: text: null name: title group_admins: selector: boolean: {} name: group_admins required: true group_family: selector: boolean: {} name: group_family required: true critical: selector: boolean: {} name: critical required: true alexa: selector: boolean: {} name: alexa required: true
sequence:
  - variables:
      push_data: |-
        {% if critical %} {
          "push": {
            "sound": {
             "name": "default",
             "critical": 1,
              "volume": 1.0
             }
          }
        } {% else %} {} {% endif %}
    alias: push_data Variable, um den Channel "Critical" beim Iphone zu abonnieren
  - variables:
      targets: |-
        {% set t = [] %} 
        {% if group_admins %}
          {% set t = t + ["notify.mobile_app_iphone_tobias"] %}
        {% endif %} 
        {% if group_family %}
          {% set t = t + ["notify.mobile_app_iphone_tobias", "notify.mobile_app_slerch","notify.alexa_media_bad_oben"] %}
        {% endif %} 
        {% if alexa %}
          {% set t = t + ["notify.alexa_media_keller"] %}
        {% endif %} 
        {{ t | unique | list }}
    alias: targets für alle gewünschten "notify" Dienste
  - variables:
      alexa_devices: "{{ targets | select('search', 'notify.alexa_media') | list }}"
    alias: "alexa_devices : Filter um nur die alexa Devices für den Dienst zu filtern"
  - variables:
      media_players: >
        {% set media_players = alexa_devices | map('replace',
        'notify.alexa_media_', 'media_player.') | list %} {{ media_players }}
    alias: >-
      media_players: Aus dem Dienst werden automatisch alle Media_Player
      Entitätsnamen abgeleitet.
  - variables:
      volume_level: |
        {% if critical %}
          0.8
        {% else %}
          0.2
        {% endif %}
    alias: >-
      volume_level: Wenn critical aktiviert ist, wir eine andere Lautstärke
      gewählt , anonsten default für die Ausgabe
  - repeat:
      for_each: "{{ media_players }}"
      sequence:
        - action: media_player.volume_set
          metadata: {}
          data:
            volume_level: "{{ volume_level }}"
          target:
            entity_id: "{{ repeat.item }}"
    enabled: true
  - repeat:
      sequence:
        - action: "{{ repeat.item }}"
          data:
            title: "{{ title }}"
            message: "{{ message }}"
            data: "{{ push_data }}"
      for_each: "{{ targets }}"
    enabled: true
  - delay:
      hours: 0
      minutes: 0
      seconds: 5
      milliseconds: 0
  - repeat:
      for_each: "{{ media_players }}"
      sequence:
        - action: media_player.volume_set
          metadata: {}
          data:
            volume_level: 0.1
          target:
            entity_id: "{{ repeat.item }}"
    enabled: true
  - action: persistent_notification.create
    metadata: {}
    data:
      message: "{{ targets }}"
alias: Notify All V2
description: ""
fields:
  message:
    selector:
      text:
        multiline: true
    name: message
  title:
    selector:
      text: null
    name: title
  group_admins:
    selector:
      boolean: {}
    name: group_admins
    required: true
  group_family:
    selector:
      boolean: {}
    name: group_family
    required: true
  critical:
    selector:
      boolean: {}
    name: critical
    required: true
  alexa:
    selector:
      boolean: {}
    name: alexa
    required: true

Folgende Videos kann ich dir als Grundlagenvideos zum Thema Notifications noch empfehlen.

YouTube player

YouTube player

YouTube player

💬 So schützt ihr euer Zuhause mit Home Assistant vor der eigenen Vergesslichkeit

🔒 Mehr Sicherheit im eigenen Zuhause – ohne Alarmanlage! Vergesslichkeit kann schnell zu einem Problem werden: Offene Fenster, offene Türen oder ein laufendes Gerät können im Alltag leicht übersehen werden. Genau hier kann Home Assistant helfen! 🏡✨ In diesem Video zeige ich euch zwei einfache Möglichkeiten, um euer Zuhause sicherer zu machen – nicht durch eine klassische Alarmanlage, sondern durch intelligente Automatisierungen, die eure Vergesslichkeit ausgleichen.

🔹 **Variante 1:** Eine schnelle und einfache Lösung – leicht umzusetzen und sofort nutzbar.

🔹 **Variante 2:** Eine elegantere, flexiblere Methode für alle, die es noch smarter möchten.

Mit Home Assistant könnt ihr alltägliche Risiken minimieren und euer Smart Home noch nützlicher gestalten. Seid gespannt! 🚀

Diesen Sensor verwende ich sehr gerne für meine Türen und Fenster *:

Die beiden Automatisierungsbeispiele aus dem Video:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
alias: Warnung vor einer offenen Tür
description: ""
triggers:
- trigger: state
entity_id:
- input_boolean.notify_night
to: "on"
- trigger: numeric_state
entity_id:
- zone.home
below: 1
conditions:
- condition: state
entity_id: binary_sensor.gruppe_aller_turen
state: "on"
actions:
- action: notify.mobile_app_iphone_tobias
metadata: {}
data:
title: Hausinformation
message: Es ist noch eine Türe geöffnet
mode: single
alias: Warnung vor einer offenen Tür description: "" triggers: - trigger: state entity_id: - input_boolean.notify_night to: "on" - trigger: numeric_state entity_id: - zone.home below: 1 conditions: - condition: state entity_id: binary_sensor.gruppe_aller_turen state: "on" actions: - action: notify.mobile_app_iphone_tobias metadata: {} data: title: Hausinformation message: Es ist noch eine Türe geöffnet mode: single
alias: Warnung vor einer offenen Tür
description: ""
triggers:
  - trigger: state
    entity_id:
      - input_boolean.notify_night
    to: "on"
  - trigger: numeric_state
    entity_id:
      - zone.home
    below: 1
conditions:
  - condition: state
    entity_id: binary_sensor.gruppe_aller_turen
    state: "on"
actions:
  - action: notify.mobile_app_iphone_tobias
    metadata: {}
    data:
      title: Hausinformation
      message: Es ist noch eine Türe geöffnet
mode: single

Automatisierung 2

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
alias: Warnung vor einer offenen Tür 2
description: ""
triggers:
- trigger: state
entity_id:
- input_boolean.notify_night
to: "on"
- trigger: numeric_state
entity_id:
- zone.home
below: 1
conditions:
- condition: template
value_template: |-
{{ expand(states.binary_sensor)
| selectattr('state', 'eq', 'on')
| selectattr('attributes.device_class', 'eq', 'door')
|rejectattr('entity_id', 'in' , ['binary_sensor.geschirrspuler_door'])
| map(attribute='name')
| list | count > 0
}}
actions:
- action: notify.mobile_app_iphone_tobias
metadata: {}
data:
title: Hausinformation
message: >-
Es ist noch geöffnet: {{ expand(states.binary_sensor) |
selectattr('state', 'eq', 'on') |
selectattr('attributes.device_class', 'eq', 'door')
|rejectattr('entity_id', 'in' , ['binary_sensor.geschirrspuler_door'])
| map(attribute='name') | list | join('\n') }}
mode: single
alias: Warnung vor einer offenen Tür 2 description: "" triggers: - trigger: state entity_id: - input_boolean.notify_night to: "on" - trigger: numeric_state entity_id: - zone.home below: 1 conditions: - condition: template value_template: |- {{ expand(states.binary_sensor) | selectattr('state', 'eq', 'on') | selectattr('attributes.device_class', 'eq', 'door') |rejectattr('entity_id', 'in' , ['binary_sensor.geschirrspuler_door']) | map(attribute='name') | list | count > 0 }} actions: - action: notify.mobile_app_iphone_tobias metadata: {} data: title: Hausinformation message: >- Es ist noch geöffnet: {{ expand(states.binary_sensor) | selectattr('state', 'eq', 'on') | selectattr('attributes.device_class', 'eq', 'door') |rejectattr('entity_id', 'in' , ['binary_sensor.geschirrspuler_door']) | map(attribute='name') | list | join('\n') }} mode: single
alias: Warnung vor einer offenen Tür 2
description: ""
triggers:
  - trigger: state
    entity_id:
      - input_boolean.notify_night
    to: "on"
  - trigger: numeric_state
    entity_id:
      - zone.home
    below: 1
conditions:
  - condition: template
    value_template: |-
      {{ expand(states.binary_sensor)
        | selectattr('state', 'eq', 'on')
        | selectattr('attributes.device_class', 'eq', 'door')
        |rejectattr('entity_id', 'in' , ['binary_sensor.geschirrspuler_door'])
        | map(attribute='name')
        | list | count > 0
      }}
actions:
  - action: notify.mobile_app_iphone_tobias
    metadata: {}
    data:
      title: Hausinformation
      message: >-
        Es ist noch geöffnet: {{ expand(states.binary_sensor)   |
        selectattr('state', 'eq', 'on')   |
        selectattr('attributes.device_class', 'eq', 'door')  
        |rejectattr('entity_id', 'in' , ['binary_sensor.geschirrspuler_door'])  
        | map(attribute='name')   | list | join('\n') }}
mode: single

Weitere Videos, die zur Umsetzung hilfreich sein könnten und im Video erwähnt wurden:

YouTube player

YouTube player

YouTube player

🚗⚡ Tesla & evcc : So nutzt du die Fleet API & myteslamate mit evcc 2025🔋💡

In diesem Video erfahrt ihr, wie ihr euren Tesla mit EVCC verbinden könnt. Ich habe euch versprochen, darauf nochmal einzugehen, wenn Interesse besteht – und genau dieses Versprechen löse ich mit diesem Video sehr gerne ein! Seit Februar 2025 hat sich einiges geändert, und der bisherige Weg funktioniert nicht mehr. Aber keine Sorge: Ich habe mich mit der neuen Lösung beschäftigt und zeige euch, wie ihr euren Tesla weiterhin mit evcc nutzen könnt.

Wollt ihr wissen, was EVCC ist und wie es sich installieren lässt, dann empfehle ich euch dieses Video zur Vorbereitung

YouTube player

Was hat sich geändert?

Bislang war die Integration von Tesla in evcc recht einfach, doch Tesla hat einige Anpassungen vorgenommen, die eine neue Vorgehensweise erfordern. Statt der bisherigen Methode nutzen wir nun die Fleet API in Kombination mit myteslamate, um die Verbindung herzustellen. Ich erkläre euch genau, was das bedeutet und wie ihr euren Tesla damit einbinden könnt.

Ist die neue Methode besser oder schlechter?

Natürlich stellt sich die Frage: Ist die neue Lösung eine Verbesserung oder eher eine Hürde? In meinem Video teile ich meine persönliche Einschätzung . Wie sieht eure Meinung dazu aus ? Teilt es mir gerne in den Kommentaren zum Video.

🔧🚀 Immich – Komplette Installationsanleitung! So richtest du deine eigene Foto-Cloud ein 📸💾

YouTube player

Heute möchte ich euch eine Software vorstellen, dir mir im Alltag viel Zeit einspart. Heutzutage haben wir tausende Bilder und Videos zu verwalten. Man dokumentiert den Wachstum der Kinder , will besondere Momente festhalten, oder nimmt einfach nur gerne Fotos von der Natur auf. Fotos und Videos gehören einfach zum heutigen Alltag. Lange Zeit habe ich mit Cloud Diensten gearbeitet. Ich will hier gar keine Namen nennen, aber die machen alle, mehr oder weniger gut, was ihre Aufgabe ist, nämlich Bilder verwalten. Irgendwie hat es mir nur nie gefallen, meine Bilder in die Cloud zu stellen. Deshalb möchte ich heute eine Software vorstellen, die mir aus meiner Sicht mindestens den gleichen Komfort bietet, aber lokal betrieben werden kann.

Um euch die Arbeit zu erleichtern, habe ich ein Installationsskript erstellt, welches euch den Einstieg in diese Software hoffentlich vereinfacht. Es kann als LXC Container unter Proxmox, VM oder direkt auf einer Hardware installiert werden.

Seht es mir nach, dass ich nicht alle Varianten durchtesten konnte. Voraussetzung ist ein 64 Bit basiertes Linux Betriebssystem ( mit Ubuntu getestet) . Auch solltet ihr ein wenig RAM mitbringen, da auch KI basierte Verfahren zum Einsatz kommen. Mehr dazu findet ihr im Video.

Immich ist kostenlos, bietet aber in der Software die Möglichkeit eine Lizenz zu erwerben. Damit erweitert ihr nicht den Funktionsumfang, aber ihr unterstützt damit die Entwickler. Die Pflege und Entwicklung einer Software ist immer mit sehr viel Aufwand verbunden. Wenn euch die Software also gefällt, lege ich es jeden ans Herz , hier ggf. auch tätig zu werden 🙂

Home | Immich

Um das Skript zu installieren, führt folgenden Befehl aus:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
wget https://blog.smarthomeundmore.de/wp-content/uploads/install_immich.sh
wget https://blog.smarthomeundmore.de/wp-content/uploads/install_immich.sh
wget https://blog.smarthomeundmore.de/wp-content/uploads/install_immich.sh

danach muss das Skript noch ausführbar gemacht werden.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
chmod +x install_immich.sh
chmod +x install_immich.sh
chmod +x install_immich.sh

Um jetzt die Installation auszuführen, müsst ihr nur noch das Skript aufrufen.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
./install_immich.sh
./install_immich.sh
./install_immich.sh

Jetzt könnt ihr die bei der Installation angezeigte Adresse im Browser eingeben und loslegen.

Falls ihr euch das Skript manuell anlegen wollt, hier noch die Inhalte des Skriptes

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/bin/bash
set -e # Beende das Skript bei Fehlern
# Variablen definieren
INSTALL_DIR="/opt/immich-app"
IMMICH_USER="immich"
DOCKER_COMPOSE_YML_URL="https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml"
ENV_FILE_URL="https://github.com/immich-app/immich/releases/latest/download/example.env"
# Passwort f r den Immich-Benutzer abfragen
echo "Bitte ein Passwort f r den Benutzer '$IMMICH_USER' eingeben:"
read -s IMMICH_PASSWORD
echo "Bitte das Passwort erneut eingeben:"
read -s IMMICH_PASSWORD_CONFIRM
if [ "$IMMICH_PASSWORD" != "$IMMICH_PASSWORD_CONFIRM" ]; then
echo "Passw rter stimmen nicht berein. Abbruch."
exit 1
fi
# System aktualisieren
sudo apt update && sudo apt upgrade -y
# Notwendige Pakete installieren
sudo apt install -y curl wget apt-transport-https ca-certificates gnupg lsb-release pwgen
# Docker-Repository hinzuf gen und Docker installieren
if ! command -v docker &> /dev/null; then
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io
sudo usermod -aG docker $USER
newgrp docker << END
echo "Docker wurde installiert und ist sofort ohne Abmeldung nutzbar."
END
fi
# Docker Compose installieren
if ! command -v docker compose &> /dev/null; then
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
fi
# Benutzer f r Immich erstellen
if ! id "$IMMICH_USER" &>/dev/null; then
sudo useradd -m -s /bin/bash "$IMMICH_USER"
echo "$IMMICH_USER:$IMMICH_PASSWORD" | sudo chpasswd
echo "Benutzer $IMMICH_USER wurde erstellt."
fi
# Benutzer zur Docker-Gruppe hinzuf gen
sudo usermod -aG docker "$IMMICH_USER"
# Docker-Socket-Berechtigungen setzen
sudo chmod 666 /var/run/docker.sock
# Installationsverzeichnis erstellen und Berechtigungen setzen
sudo mkdir -p "$INSTALL_DIR"
sudo chown -R "$IMMICH_USER:$IMMICH_USER" "$INSTALL_DIR"
cd "$INSTALL_DIR"
# docker-compose.yml und .env herunterladen
sudo -u "$IMMICH_USER" wget -O docker-compose.yml "$DOCKER_COMPOSE_YML_URL"
sudo -u "$IMMICH_USER" wget -O .env "$ENV_FILE_URL"
# Standardwerte in der .env Datei setzen
sudo -u "$IMMICH_USER" sed -i "s|UPLOAD_LOCATION=./library|UPLOAD_LOCATION=$INSTALL_DIR/library|g" .env
sudo -u "$IMMICH_USER" sed -i "s|DB_DATA_LOCATION=./postgres|DB_DATA_LOCATION=$INSTALL_DIR/postgres|g" .env
sudo -u "$IMMICH_USER" sed -i "s|DB_PASSWORD=postgres|DB_PASSWORD=$IMMICH_PASSWORD|g" .env
# Container starten mit neuem Benutzer
sudo su - "$IMMICH_USER" -c "cd $INSTALL_DIR && docker compose up -d"
# IP-Adresse und Port ausgeben
IP_ADDRESS=$(hostname -I | awk '{print $1}')
PORT=$(sudo grep -oP 'IMMICH_SERVER_PORT=\K\d+' .env || echo "2283")
# Abschlussmeldung
echo "Installation abgeschlossen! Immich l uft nun im Hintergrund unter dem Benutzer $IMMICH_USER."
echo "Installationsverzeichnis: $INSTALL_DIR"
echo "Datenbank-Passwort: $IMMICH_PASSWORD"
echo "Immich kann unter folgender Adresse erreicht werden: http://$IP_ADDRESS:$PORT"
#!/bin/bash set -e # Beende das Skript bei Fehlern # Variablen definieren INSTALL_DIR="/opt/immich-app" IMMICH_USER="immich" DOCKER_COMPOSE_YML_URL="https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml" ENV_FILE_URL="https://github.com/immich-app/immich/releases/latest/download/example.env" # Passwort f r den Immich-Benutzer abfragen echo "Bitte ein Passwort f r den Benutzer '$IMMICH_USER' eingeben:" read -s IMMICH_PASSWORD echo "Bitte das Passwort erneut eingeben:" read -s IMMICH_PASSWORD_CONFIRM if [ "$IMMICH_PASSWORD" != "$IMMICH_PASSWORD_CONFIRM" ]; then echo "Passw rter stimmen nicht berein. Abbruch." exit 1 fi # System aktualisieren sudo apt update && sudo apt upgrade -y # Notwendige Pakete installieren sudo apt install -y curl wget apt-transport-https ca-certificates gnupg lsb-release pwgen # Docker-Repository hinzuf gen und Docker installieren if ! command -v docker &> /dev/null; then curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io sudo usermod -aG docker $USER newgrp docker << END echo "Docker wurde installiert und ist sofort ohne Abmeldung nutzbar." END fi # Docker Compose installieren if ! command -v docker compose &> /dev/null; then sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose fi # Benutzer f r Immich erstellen if ! id "$IMMICH_USER" &>/dev/null; then sudo useradd -m -s /bin/bash "$IMMICH_USER" echo "$IMMICH_USER:$IMMICH_PASSWORD" | sudo chpasswd echo "Benutzer $IMMICH_USER wurde erstellt." fi # Benutzer zur Docker-Gruppe hinzuf gen sudo usermod -aG docker "$IMMICH_USER" # Docker-Socket-Berechtigungen setzen sudo chmod 666 /var/run/docker.sock # Installationsverzeichnis erstellen und Berechtigungen setzen sudo mkdir -p "$INSTALL_DIR" sudo chown -R "$IMMICH_USER:$IMMICH_USER" "$INSTALL_DIR" cd "$INSTALL_DIR" # docker-compose.yml und .env herunterladen sudo -u "$IMMICH_USER" wget -O docker-compose.yml "$DOCKER_COMPOSE_YML_URL" sudo -u "$IMMICH_USER" wget -O .env "$ENV_FILE_URL" # Standardwerte in der .env Datei setzen sudo -u "$IMMICH_USER" sed -i "s|UPLOAD_LOCATION=./library|UPLOAD_LOCATION=$INSTALL_DIR/library|g" .env sudo -u "$IMMICH_USER" sed -i "s|DB_DATA_LOCATION=./postgres|DB_DATA_LOCATION=$INSTALL_DIR/postgres|g" .env sudo -u "$IMMICH_USER" sed -i "s|DB_PASSWORD=postgres|DB_PASSWORD=$IMMICH_PASSWORD|g" .env # Container starten mit neuem Benutzer sudo su - "$IMMICH_USER" -c "cd $INSTALL_DIR && docker compose up -d" # IP-Adresse und Port ausgeben IP_ADDRESS=$(hostname -I | awk '{print $1}') PORT=$(sudo grep -oP 'IMMICH_SERVER_PORT=\K\d+' .env || echo "2283") # Abschlussmeldung echo "Installation abgeschlossen! Immich l uft nun im Hintergrund unter dem Benutzer $IMMICH_USER." echo "Installationsverzeichnis: $INSTALL_DIR" echo "Datenbank-Passwort: $IMMICH_PASSWORD" echo "Immich kann unter folgender Adresse erreicht werden: http://$IP_ADDRESS:$PORT"
#!/bin/bash

set -e  # Beende das Skript bei Fehlern

# Variablen definieren
INSTALL_DIR="/opt/immich-app"
IMMICH_USER="immich"
DOCKER_COMPOSE_YML_URL="https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml"
ENV_FILE_URL="https://github.com/immich-app/immich/releases/latest/download/example.env"

# Passwort f  r den Immich-Benutzer abfragen
echo "Bitte ein Passwort f  r den Benutzer '$IMMICH_USER' eingeben:"
read -s IMMICH_PASSWORD
echo "Bitte das Passwort erneut eingeben:"
read -s IMMICH_PASSWORD_CONFIRM

if [ "$IMMICH_PASSWORD" != "$IMMICH_PASSWORD_CONFIRM" ]; then
    echo "Passw  rter stimmen nicht   berein. Abbruch."
    exit 1
fi

# System aktualisieren
sudo apt update && sudo apt upgrade -y

# Notwendige Pakete installieren
sudo apt install -y curl wget apt-transport-https ca-certificates gnupg lsb-release pwgen

# Docker-Repository hinzuf  gen und Docker installieren
if ! command -v docker &> /dev/null; then
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    sudo apt update
    sudo apt install -y docker-ce docker-ce-cli containerd.io
    sudo usermod -aG docker $USER
    newgrp docker << END
    echo "Docker wurde installiert und ist sofort ohne Abmeldung nutzbar."
END
fi

# Docker Compose installieren
if ! command -v docker compose &> /dev/null; then
    sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    sudo chmod +x /usr/local/bin/docker-compose
fi

# Benutzer f  r Immich erstellen
if ! id "$IMMICH_USER" &>/dev/null; then
    sudo useradd -m -s /bin/bash "$IMMICH_USER"
    echo "$IMMICH_USER:$IMMICH_PASSWORD" | sudo chpasswd
    echo "Benutzer $IMMICH_USER wurde erstellt."
fi

# Benutzer zur Docker-Gruppe hinzuf  gen
sudo usermod -aG docker "$IMMICH_USER"

# Docker-Socket-Berechtigungen setzen
sudo chmod 666 /var/run/docker.sock

# Installationsverzeichnis erstellen und Berechtigungen setzen
sudo mkdir -p "$INSTALL_DIR"
sudo chown -R "$IMMICH_USER:$IMMICH_USER" "$INSTALL_DIR"
cd "$INSTALL_DIR"

# docker-compose.yml und .env herunterladen
sudo -u "$IMMICH_USER" wget -O docker-compose.yml "$DOCKER_COMPOSE_YML_URL"
sudo -u "$IMMICH_USER" wget -O .env "$ENV_FILE_URL"

# Standardwerte in der .env Datei setzen
sudo -u "$IMMICH_USER" sed -i "s|UPLOAD_LOCATION=./library|UPLOAD_LOCATION=$INSTALL_DIR/library|g" .env
sudo -u "$IMMICH_USER" sed -i "s|DB_DATA_LOCATION=./postgres|DB_DATA_LOCATION=$INSTALL_DIR/postgres|g" .env
sudo -u "$IMMICH_USER" sed -i "s|DB_PASSWORD=postgres|DB_PASSWORD=$IMMICH_PASSWORD|g" .env

# Container starten mit neuem Benutzer
sudo su - "$IMMICH_USER" -c "cd $INSTALL_DIR && docker compose up -d"

# IP-Adresse und Port ausgeben
IP_ADDRESS=$(hostname -I | awk '{print $1}')
PORT=$(sudo grep -oP 'IMMICH_SERVER_PORT=\K\d+' .env || echo "2283")

# Abschlussmeldung
echo "Installation abgeschlossen! Immich l  uft nun im Hintergrund unter dem Benutzer $IMMICH_USER."
echo "Installationsverzeichnis: $INSTALL_DIR"
echo "Datenbank-Passwort: $IMMICH_PASSWORD"
echo "Immich kann unter folgender Adresse erreicht werden: http://$IP_ADDRESS:$PORT"

💡 Warum ist EVCC 2025 ein Gamechanger?

EVCC ist eine der beliebtesten Lösungen für das intelligente Laden von Elektroautos mit PV-Überschuss. Die neue Version bringt einige tiefgreifende Änderungen mit sich, die sowohl die Basisinstallation als auch die Konfiguration betreffen.

Einige Highlights der neuen Version:

✅ Überarbeitete Konfigurationsstruktur
✅ Verbesserte Integration in Home Assistant
✅ Erweiterte Unterstützung für verschiedene Wechselrichter und Stromtarife
✅ Neue Funktionen für mehrphasiges Laden & Batteriespeicher

Egal, ob du bereits EVCC nutzt oder gerade erst startest – diese Änderungen solltest du kennen!

🛠️ EVCC in Home Assistant 2025 installieren

Die Installation von EVCC unter Home Assistant ist einfacher geworden, erfordert aber einige Anpassungen. Hier sind die wichtigsten Schritte:

Basisinstallation und erste Konfiguration

Nach der Installation sind einige grundlegende Konfigurationsschritte erforderlich:

🔹 MQTT einrichten ( nicht zwingend notwendig )
🔹 Ladepunkt hinzufügen und mit dem EVCC-System verbinden
🔹 PV-Anlage & Batteriespeicher konfigurieren
🔹 Dynamische Stromtarife einbinden

Migration von einer bestehenden Installation

Falls du EVCC bereits nutzt, solltest du einige Punkte beachten:

⚡ Backup der aktuellen Konfiguration
⚡ Überprüfung der YAML-Struktur (einige Parameter haben sich geändert)
⚡ Anpassung an die neuen Konfigurationsmöglichkeiten

In meinem Video zeige ich dir Schritt für Schritt, wie du EVCC installierst und die wichtigsten Änderungen übernimmst.

🚀 Fazit: Lohnt sich das Update?

Definitiv! Die neuen Funktionen machen EVCC noch leistungsfähiger und die Integration in Home Assistant wurde weiter verbessert. Besonders die neuen Einstellungen für Stromtarife, PV-Prognosen und Batteriespeicher bringen das Smart Charging auf das nächste Level.

Wenn du bereits EVCC nutzt, solltest du dich mit den Änderungen vertraut machen – und falls du gerade erst startest, ist jetzt der perfekte Zeitpunkt, um EVCC in dein Smart Home zu integrieren!

🔋 Besuche die EVCC Homepage

EVCC Add-on über HACS in Home Assistant installieren

EVCC kann über das Home Assistant Community Store (HACS) Add-on integriert werden. Die aktuellste Version findest du hier:
👉 EVCC HACS Add-on auf GitHub

Damit bekommst du Zugriff und Steuerungsmöglichkeiten auf EVCC Entitäten in Home Assistant. Beachte dabei meine Installationsanleitung.

YouTube player

Paperless NGX komplett einrichten – mit REST API Home Assistant Sensor

YouTube player

In diesem Video zeige ich euch, wie ihr unter Proxmox ( LXC oder VM), oder einem separaten PC Paperless NGX einrichtet. Da es recht viele Dinge dabei zu berücksichtigen gibt, habe ich euch dafür 3 Skripte erstellt.

  1. Installation
  2. Backup
  3. Restore

Mit diesen Skripten wird euch fast die gesamte Arbeit abgenommen.

Möchtest du Paperless ngx als Home Assistant Addon installieren, findest du hier eine Anleitung dazu:
https://youtu.be/wCiSkHQtYEE

Wichtiger Hinweis ! Bitte unbedingt beachten!

Ich habe die Freigabenamen umbenannt. Im Video bin ich darauf nochmal kurz eingegangen. Die Freigaben heißen nun:

consume

backup

restore

D.h. , wenn unter Windows die Freigaben gemountet werden, müssen diese Freigabenamen verwendet werden !

Skript install_paperless.sh

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/bin/bash
set -euo pipefail
# Funktion zur sicheren Passworteingabe mit Bestätigung
function prompt_for_password() {
local password password_confirm
# Falls PAPERLESS_PASSWORD eingegeben wird, zusätzliche Erklärung ausgeben
if [[ "$1" == "PAPERLESS_PASSWORD" ]]; then
echo -e "\n💡 Hinweis: Dieses Passwort wird für den Linux-Benutzer 'paperless' und den Samba-Server verwendet."
echo -e "Es wird für den Zugriff auf freigegebene Samba-Ordner benötigt.\n"
fi
while true; do
echo -e "\n🔒 Bitte geben Sie das Passwort für **$1** ein:"
read -s password
echo -e "\n🔒 Bitte bestätigen Sie das Passwort:"
read -s password_confirm
if [[ "$password" == "$password_confirm" ]]; then
echo -e "\n✅ Passwort erfolgreich gesetzt für **$1**.\n"
eval "$2='$password'"
break
else
echo -e "\n❌ Die Passwörter stimmen nicht überein. Bitte erneut eingeben.\n"
fi
done
}
# Funktion zur Eingabe des Admin-Benutzernamens mit Standardwert
function prompt_for_admin_user() {
echo -e "\n👤 Bitte geben Sie den **Admin-Benutzernamen** ein (Standard: paperless):"
read admin_user_input
ADMIN_USER="${admin_user_input:-paperless}"
echo -e "\n✅ Admin-Benutzer wurde auf **'$ADMIN_USER'** gesetzt.\n"
}
# Passwörter abfragen
prompt_for_password "PAPERLESS_PASSWORD" PAPERLESS_PASSWORD
prompt_for_admin_user
prompt_for_password "ADMIN_PASSWORD" ADMIN_PASSWORD
# Weitere Konfigurationen
SAMBA_PASSWORD="$PAPERLESS_PASSWORD"
DB_PASSWORD="paperless"
# System aktualisieren und benötigte Pakete installieren
update_and_install_dependencies() {
echo "Aktualisiere Paketliste und installiere benötigte Pakete..."
sudo apt update
sudo apt install -y apt-transport-https curl jq gnupg openssh-server samba samba-common-bin
}
# Docker-Repository hinzufügen
add_docker_repo() {
echo "Füge Docker GPG-Schlüssel und Repository hinzu..."
sudo mkdir -p /etc/apt/keyrings
if [[ ! -f /etc/apt/keyrings/docker.gpg ]]; then
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
fi
. /etc/os-release
DOCKER_REPO="deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $VERSION_CODENAME stable"
echo "$DOCKER_REPO" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
}
# Paperless-Benutzer und Gruppe anlegen
ensure_paperless_user_and_group() {
if ! getent group paperless &>/dev/null; then
echo "Erstelle Gruppe 'paperless' mit GID 1002..."
sudo groupadd -g 1002 paperless
fi
if ! id -u paperless &>/dev/null; then
echo "Erstelle Benutzer 'paperless' mit UID 1002 und GID 1002..."
sudo useradd -m -s /bin/bash -u 1002 -g paperless paperless
echo "paperless:$PAPERLESS_PASSWORD" | sudo chpasswd
fi
}
# Docker installieren
install_docker() {
if ! command -v docker &>/dev/null; then
echo "Docker wird installiert..."
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
fi
if ! groups paperless | grep -q "\bdocker\b"; then
echo "Füge Benutzer 'paperless' zur Docker-Gruppe hinzu..."
sudo usermod -aG docker paperless
fi
}
# Samba Konfiguration
configure_samba() {
# Backup der Original-Samba-Konfiguration
sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.bak
sudo mkdir -p /data/paperless/{backup,restore}
sudo chown -R paperless:paperless /data/paperless/
sudo chmod -R 770 /data/paperless/
# Für den Share [consume] soll nur der Ordner /data/paperless/consume freigegeben werden:
if ! grep -q "^\[consume\]" /etc/samba/smb.conf; then
sudo tee -a /etc/samba/smb.conf > /dev/null <<'EOF'
[consume]
comment = Paperless Daten
path = /data/paperless/consume
browsable = yes
writable = yes
guest ok = no
create mask = 0770
directory mask = 0770
valid users = paperless
EOF
fi
# Share für Backup
if ! grep -q "^\[backup\]" /etc/samba/smb.conf; then
sudo tee -a /etc/samba/smb.conf > /dev/null <<'EOF'
[backup]
comment = Paperless Backup Daten
path = /data/paperless/backup
browsable = yes
writable = yes
guest ok = no
create mask = 0770
directory mask = 0770
valid users = paperless
EOF
fi
# Share für Restore
if ! grep -q "^\[restore\]" /etc/samba/smb.conf; then
sudo tee -a /etc/samba/smb.conf > /dev/null <<'EOF'
[restore]
comment = Paperless Restore Daten
path = /data/paperless/restore
browsable = yes
writable = yes
guest ok = no
create mask = 0770
directory mask = 0770
valid users = paperless
EOF
fi
sudo systemctl restart smbd
echo "Samba Shares [consume], [backup] und [restore] wurden konfiguriert."
(echo "$SAMBA_PASSWORD"; echo "$SAMBA_PASSWORD") | sudo smbpasswd -a paperless -s
sudo systemctl restart smbd
}
# Docker-Compose-Datei erstellen
deploy_containers() {
echo "Erstelle docker-compose.yml im Verzeichnis von 'paperless'..."
sudo mkdir -p /home/paperless
cat <<EOL | sudo tee /home/paperless/docker-compose.yml > /dev/null
services:
broker:
image: redis:7
container_name: broker
restart: unless-stopped
volumes:
- /data/paperless/redis/_data:/data
db:
image: postgres:16
container_name: db
restart: unless-stopped
volumes:
- /data/paperless/postgresql/_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD: $DB_PASSWORD
webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
container_name: webserver
restart: unless-stopped
depends_on:
- db
- broker
- gotenberg
- tika
ports:
- "8001:8000"
volumes:
- /data/paperless/consume:/usr/src/paperless/consume
- /data/paperless/data:/usr/src/paperless/data
- /data/paperless/media:/usr/src/paperless/media
- /data/paperless/export:/usr/src/paperless/export
environment:
PAPERLESS_ADMIN_USER: $ADMIN_USER
PAPERLESS_ADMIN_PASSWORD: $ADMIN_PASSWORD
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_DBHOST: db
PAPERLESS_TIKA_ENABLED: 1
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
PAPERLESS_OCR_LANGUAGE: deu
PAPERLESS_TIME_ZONE: Europe/Berlin
PAPERLESS_CONSUMER_ENABLE_BARCODES: "true"
PAPERLESS_CONSUMER_ENABLE_ASN_BARCODE: "true"
PAPERLESS_CONSUMER_BARCODE_SCANNER: ZXING
PAPERLESS_EMAIL_TASK_CRON: '*/10 * * * *'
USERMAP_UID: "1002"
USERMAP_GID: "1002"
gotenberg:
image: gotenberg/gotenberg:8.8
restart: unless-stopped
command:
- "gotenberg"
- "--chromium-disable-javascript=false"
- "--chromium-allow-list=.*"
tika:
image: ghcr.io/paperless-ngx/tika:latest
container_name: tika
restart: unless-stopped
EOL
cd /home/paperless
sudo docker compose up -d
}
# Hauptprogramm
update_and_install_dependencies
add_docker_repo
ensure_paperless_user_and_group
install_docker
configure_samba
deploy_containers
sleep 60
sudo chown -R paperless:paperless /data/paperless
# Lokale IP-Adresse ermitteln
LOCAL_IP=$(hostname -I | awk '{print $1}')
echo -e "\n🚀 **Paperless ist jetzt bereit!**"
echo -e "🔗 **Zugriff im Browser:** http://$LOCAL_IP:8001\n"
echo -e "🔗 ** Bitte einmal neu booten"
#!/bin/bash set -euo pipefail # Funktion zur sicheren Passworteingabe mit Bestätigung function prompt_for_password() { local password password_confirm # Falls PAPERLESS_PASSWORD eingegeben wird, zusätzliche Erklärung ausgeben if [[ "$1" == "PAPERLESS_PASSWORD" ]]; then echo -e "\n💡 Hinweis: Dieses Passwort wird für den Linux-Benutzer 'paperless' und den Samba-Server verwendet." echo -e "Es wird für den Zugriff auf freigegebene Samba-Ordner benötigt.\n" fi while true; do echo -e "\n🔒 Bitte geben Sie das Passwort für **$1** ein:" read -s password echo -e "\n🔒 Bitte bestätigen Sie das Passwort:" read -s password_confirm if [[ "$password" == "$password_confirm" ]]; then echo -e "\n✅ Passwort erfolgreich gesetzt für **$1**.\n" eval "$2='$password'" break else echo -e "\n❌ Die Passwörter stimmen nicht überein. Bitte erneut eingeben.\n" fi done } # Funktion zur Eingabe des Admin-Benutzernamens mit Standardwert function prompt_for_admin_user() { echo -e "\n👤 Bitte geben Sie den **Admin-Benutzernamen** ein (Standard: paperless):" read admin_user_input ADMIN_USER="${admin_user_input:-paperless}" echo -e "\n✅ Admin-Benutzer wurde auf **'$ADMIN_USER'** gesetzt.\n" } # Passwörter abfragen prompt_for_password "PAPERLESS_PASSWORD" PAPERLESS_PASSWORD prompt_for_admin_user prompt_for_password "ADMIN_PASSWORD" ADMIN_PASSWORD # Weitere Konfigurationen SAMBA_PASSWORD="$PAPERLESS_PASSWORD" DB_PASSWORD="paperless" # System aktualisieren und benötigte Pakete installieren update_and_install_dependencies() { echo "Aktualisiere Paketliste und installiere benötigte Pakete..." sudo apt update sudo apt install -y apt-transport-https curl jq gnupg openssh-server samba samba-common-bin } # Docker-Repository hinzufügen add_docker_repo() { echo "Füge Docker GPG-Schlüssel und Repository hinzu..." sudo mkdir -p /etc/apt/keyrings if [[ ! -f /etc/apt/keyrings/docker.gpg ]]; then curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg fi . /etc/os-release DOCKER_REPO="deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $VERSION_CODENAME stable" echo "$DOCKER_REPO" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt update } # Paperless-Benutzer und Gruppe anlegen ensure_paperless_user_and_group() { if ! getent group paperless &>/dev/null; then echo "Erstelle Gruppe 'paperless' mit GID 1002..." sudo groupadd -g 1002 paperless fi if ! id -u paperless &>/dev/null; then echo "Erstelle Benutzer 'paperless' mit UID 1002 und GID 1002..." sudo useradd -m -s /bin/bash -u 1002 -g paperless paperless echo "paperless:$PAPERLESS_PASSWORD" | sudo chpasswd fi } # Docker installieren install_docker() { if ! command -v docker &>/dev/null; then echo "Docker wird installiert..." sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo systemctl enable --now docker fi if ! groups paperless | grep -q "\bdocker\b"; then echo "Füge Benutzer 'paperless' zur Docker-Gruppe hinzu..." sudo usermod -aG docker paperless fi } # Samba Konfiguration configure_samba() { # Backup der Original-Samba-Konfiguration sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.bak sudo mkdir -p /data/paperless/{backup,restore} sudo chown -R paperless:paperless /data/paperless/ sudo chmod -R 770 /data/paperless/ # Für den Share [consume] soll nur der Ordner /data/paperless/consume freigegeben werden: if ! grep -q "^\[consume\]" /etc/samba/smb.conf; then sudo tee -a /etc/samba/smb.conf > /dev/null <<'EOF' [consume] comment = Paperless Daten path = /data/paperless/consume browsable = yes writable = yes guest ok = no create mask = 0770 directory mask = 0770 valid users = paperless EOF fi # Share für Backup if ! grep -q "^\[backup\]" /etc/samba/smb.conf; then sudo tee -a /etc/samba/smb.conf > /dev/null <<'EOF' [backup] comment = Paperless Backup Daten path = /data/paperless/backup browsable = yes writable = yes guest ok = no create mask = 0770 directory mask = 0770 valid users = paperless EOF fi # Share für Restore if ! grep -q "^\[restore\]" /etc/samba/smb.conf; then sudo tee -a /etc/samba/smb.conf > /dev/null <<'EOF' [restore] comment = Paperless Restore Daten path = /data/paperless/restore browsable = yes writable = yes guest ok = no create mask = 0770 directory mask = 0770 valid users = paperless EOF fi sudo systemctl restart smbd echo "Samba Shares [consume], [backup] und [restore] wurden konfiguriert." (echo "$SAMBA_PASSWORD"; echo "$SAMBA_PASSWORD") | sudo smbpasswd -a paperless -s sudo systemctl restart smbd } # Docker-Compose-Datei erstellen deploy_containers() { echo "Erstelle docker-compose.yml im Verzeichnis von 'paperless'..." sudo mkdir -p /home/paperless cat <<EOL | sudo tee /home/paperless/docker-compose.yml > /dev/null services: broker: image: redis:7 container_name: broker restart: unless-stopped volumes: - /data/paperless/redis/_data:/data db: image: postgres:16 container_name: db restart: unless-stopped volumes: - /data/paperless/postgresql/_data:/var/lib/postgresql/data environment: POSTGRES_DB: paperless POSTGRES_USER: paperless POSTGRES_PASSWORD: $DB_PASSWORD webserver: image: ghcr.io/paperless-ngx/paperless-ngx:latest container_name: webserver restart: unless-stopped depends_on: - db - broker - gotenberg - tika ports: - "8001:8000" volumes: - /data/paperless/consume:/usr/src/paperless/consume - /data/paperless/data:/usr/src/paperless/data - /data/paperless/media:/usr/src/paperless/media - /data/paperless/export:/usr/src/paperless/export environment: PAPERLESS_ADMIN_USER: $ADMIN_USER PAPERLESS_ADMIN_PASSWORD: $ADMIN_PASSWORD PAPERLESS_REDIS: redis://broker:6379 PAPERLESS_DBHOST: db PAPERLESS_TIKA_ENABLED: 1 PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000 PAPERLESS_TIKA_ENDPOINT: http://tika:9998 PAPERLESS_OCR_LANGUAGE: deu PAPERLESS_TIME_ZONE: Europe/Berlin PAPERLESS_CONSUMER_ENABLE_BARCODES: "true" PAPERLESS_CONSUMER_ENABLE_ASN_BARCODE: "true" PAPERLESS_CONSUMER_BARCODE_SCANNER: ZXING PAPERLESS_EMAIL_TASK_CRON: '*/10 * * * *' USERMAP_UID: "1002" USERMAP_GID: "1002" gotenberg: image: gotenberg/gotenberg:8.8 restart: unless-stopped command: - "gotenberg" - "--chromium-disable-javascript=false" - "--chromium-allow-list=.*" tika: image: ghcr.io/paperless-ngx/tika:latest container_name: tika restart: unless-stopped EOL cd /home/paperless sudo docker compose up -d } # Hauptprogramm update_and_install_dependencies add_docker_repo ensure_paperless_user_and_group install_docker configure_samba deploy_containers sleep 60 sudo chown -R paperless:paperless /data/paperless # Lokale IP-Adresse ermitteln LOCAL_IP=$(hostname -I | awk '{print $1}') echo -e "\n🚀 **Paperless ist jetzt bereit!**" echo -e "🔗 **Zugriff im Browser:** http://$LOCAL_IP:8001\n" echo -e "🔗 ** Bitte einmal neu booten"
#!/bin/bash
set -euo pipefail

# Funktion zur sicheren Passworteingabe mit Bestätigung
function prompt_for_password() {
 local password password_confirm

 # Falls PAPERLESS_PASSWORD eingegeben wird, zusätzliche Erklärung ausgeben
 if [[ "$1" == "PAPERLESS_PASSWORD" ]]; then
   echo -e "\n💡 Hinweis: Dieses Passwort wird für den Linux-Benutzer 'paperless' und den Samba-Server verwendet."
   echo -e "Es wird für den Zugriff auf freigegebene Samba-Ordner benötigt.\n"
 fi

 while true; do
   echo -e "\n🔒 Bitte geben Sie das Passwort für **$1** ein:"
   read -s password
   echo -e "\n🔒 Bitte bestätigen Sie das Passwort:"
   read -s password_confirm

   if [[ "$password" == "$password_confirm" ]]; then
     echo -e "\n✅ Passwort erfolgreich gesetzt für **$1**.\n"
     eval "$2='$password'"
     break
   else
     echo -e "\n❌ Die Passwörter stimmen nicht überein. Bitte erneut eingeben.\n"
   fi
 done
}

# Funktion zur Eingabe des Admin-Benutzernamens mit Standardwert
function prompt_for_admin_user() {
 echo -e "\n👤 Bitte geben Sie den **Admin-Benutzernamen** ein (Standard: paperless):"
 read admin_user_input
 ADMIN_USER="${admin_user_input:-paperless}"
 echo -e "\n✅ Admin-Benutzer wurde auf **'$ADMIN_USER'** gesetzt.\n"
}

# Passwörter abfragen
prompt_for_password "PAPERLESS_PASSWORD" PAPERLESS_PASSWORD
prompt_for_admin_user
prompt_for_password "ADMIN_PASSWORD" ADMIN_PASSWORD

# Weitere Konfigurationen
SAMBA_PASSWORD="$PAPERLESS_PASSWORD"
DB_PASSWORD="paperless"

# System aktualisieren und benötigte Pakete installieren
update_and_install_dependencies() {
 echo "Aktualisiere Paketliste und installiere benötigte Pakete..."
 sudo apt update
 sudo apt install -y apt-transport-https curl jq gnupg openssh-server samba samba-common-bin
}

# Docker-Repository hinzufügen
add_docker_repo() {
 echo "Füge Docker GPG-Schlüssel und Repository hinzu..."
 sudo mkdir -p /etc/apt/keyrings
 if [[ ! -f /etc/apt/keyrings/docker.gpg ]]; then
   curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
 fi

 . /etc/os-release
 DOCKER_REPO="deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $VERSION_CODENAME stable"
 echo "$DOCKER_REPO" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
 sudo apt update
}

# Paperless-Benutzer und Gruppe anlegen
ensure_paperless_user_and_group() {
 if ! getent group paperless &>/dev/null; then
   echo "Erstelle Gruppe 'paperless' mit GID 1002..."
   sudo groupadd -g 1002 paperless
 fi

 if ! id -u paperless &>/dev/null; then
   echo "Erstelle Benutzer 'paperless' mit UID 1002 und GID 1002..."
   sudo useradd -m -s /bin/bash -u 1002 -g paperless paperless
   echo "paperless:$PAPERLESS_PASSWORD" | sudo chpasswd
 fi
}

# Docker installieren
install_docker() {
 if ! command -v docker &>/dev/null; then
   echo "Docker wird installiert..."
   sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
   sudo systemctl enable --now docker
 fi

 if ! groups paperless | grep -q "\bdocker\b"; then
   echo "Füge Benutzer 'paperless' zur Docker-Gruppe hinzu..."
   sudo usermod -aG docker paperless
 fi
}
# Samba Konfiguration
configure_samba() {
  # Backup der Original-Samba-Konfiguration
  sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.bak
  sudo mkdir -p /data/paperless/{backup,restore}
  sudo chown -R paperless:paperless /data/paperless/
  sudo chmod -R 770 /data/paperless/

  # Für den Share [consume] soll nur der Ordner /data/paperless/consume freigegeben werden:
  if ! grep -q "^\[consume\]" /etc/samba/smb.conf; then
    sudo tee -a /etc/samba/smb.conf > /dev/null <<'EOF'

[consume]
   comment = Paperless Daten
   path = /data/paperless/consume
   browsable = yes
   writable = yes
   guest ok = no
   create mask = 0770
   directory mask = 0770
   valid users = paperless
EOF
  fi

  # Share für Backup
  if ! grep -q "^\[backup\]" /etc/samba/smb.conf; then
    sudo tee -a /etc/samba/smb.conf > /dev/null <<'EOF'

[backup]
   comment = Paperless Backup Daten
   path = /data/paperless/backup
   browsable = yes
   writable = yes
   guest ok = no
   create mask = 0770
   directory mask = 0770
   valid users = paperless
EOF
  fi

  # Share für Restore
  if ! grep -q "^\[restore\]" /etc/samba/smb.conf; then
    sudo tee -a /etc/samba/smb.conf > /dev/null <<'EOF'

[restore]
   comment = Paperless Restore Daten
   path = /data/paperless/restore
   browsable = yes
   writable = yes
   guest ok = no
   create mask = 0770
   directory mask = 0770
   valid users = paperless
EOF
  fi

  sudo systemctl restart smbd
  echo "Samba Shares [consume], [backup] und [restore] wurden konfiguriert."

 (echo "$SAMBA_PASSWORD"; echo "$SAMBA_PASSWORD") | sudo smbpasswd -a paperless -s
 sudo systemctl restart smbd
}


# Docker-Compose-Datei erstellen
deploy_containers() {
 echo "Erstelle docker-compose.yml im Verzeichnis von 'paperless'..."
 sudo mkdir -p /home/paperless

 cat <<EOL | sudo tee /home/paperless/docker-compose.yml > /dev/null
services:
 broker:
   image: redis:7
   container_name: broker
   restart: unless-stopped
   volumes:
     - /data/paperless/redis/_data:/data

 db:
   image: postgres:16
   container_name: db
   restart: unless-stopped
   volumes:
     - /data/paperless/postgresql/_data:/var/lib/postgresql/data
   environment:
     POSTGRES_DB: paperless
     POSTGRES_USER: paperless
     POSTGRES_PASSWORD: $DB_PASSWORD

 webserver:
   image: ghcr.io/paperless-ngx/paperless-ngx:latest
   container_name: webserver
   restart: unless-stopped
   depends_on:
     - db
     - broker
     - gotenberg
     - tika
   ports:
     - "8001:8000"
   volumes:
     - /data/paperless/consume:/usr/src/paperless/consume
     - /data/paperless/data:/usr/src/paperless/data
     - /data/paperless/media:/usr/src/paperless/media
     - /data/paperless/export:/usr/src/paperless/export
   environment:
     PAPERLESS_ADMIN_USER: $ADMIN_USER
     PAPERLESS_ADMIN_PASSWORD: $ADMIN_PASSWORD
     PAPERLESS_REDIS: redis://broker:6379
     PAPERLESS_DBHOST: db
     PAPERLESS_TIKA_ENABLED: 1
     PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
     PAPERLESS_TIKA_ENDPOINT: http://tika:9998
     PAPERLESS_OCR_LANGUAGE: deu
     PAPERLESS_TIME_ZONE: Europe/Berlin
     PAPERLESS_CONSUMER_ENABLE_BARCODES: "true"
     PAPERLESS_CONSUMER_ENABLE_ASN_BARCODE: "true"
     PAPERLESS_CONSUMER_BARCODE_SCANNER: ZXING
     PAPERLESS_EMAIL_TASK_CRON: '*/10 * * * *'
     USERMAP_UID: "1002"
     USERMAP_GID: "1002"

 gotenberg:
   image: gotenberg/gotenberg:8.8
   restart: unless-stopped
   command:
     - "gotenberg"
     - "--chromium-disable-javascript=false"
     - "--chromium-allow-list=.*"

 tika:
   image: ghcr.io/paperless-ngx/tika:latest
   container_name: tika
   restart: unless-stopped
EOL

 cd /home/paperless
 sudo docker compose up -d
}

# Hauptprogramm
update_and_install_dependencies
add_docker_repo
ensure_paperless_user_and_group
install_docker
configure_samba
deploy_containers

sleep 60
sudo chown -R paperless:paperless /data/paperless 

# Lokale IP-Adresse ermitteln
LOCAL_IP=$(hostname -I | awk '{print $1}')

echo -e "\n🚀 **Paperless ist jetzt bereit!**"
echo -e "🔗 **Zugriff im Browser:** http://$LOCAL_IP:8001\n"
echo -e "🔗 ** Bitte einmal neu booten"

Um die Scripte unter Linux vom Webserver zu laden, kannst du auch folgenden Befehl verwenden.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
wget https://blog.smarthomeundmore.de/wp-content/uploads/install_paperless.sh
wget https://blog.smarthomeundmore.de/wp-content/uploads/backup.sh
wget https://blog.smarthomeundmore.de/wp-content/uploads/restore.sh
wget https://blog.smarthomeundmore.de/wp-content/uploads/install_paperless.sh wget https://blog.smarthomeundmore.de/wp-content/uploads/backup.sh wget https://blog.smarthomeundmore.de/wp-content/uploads/restore.sh
wget https://blog.smarthomeundmore.de/wp-content/uploads/install_paperless.sh
wget https://blog.smarthomeundmore.de/wp-content/uploads/backup.sh
wget https://blog.smarthomeundmore.de/wp-content/uploads/restore.sh

Danach müssen sie mit:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
chmod +x install_paperless.sh
chmod +x backup.sh
chmod +x restore.sh
chmod +x install_paperless.sh chmod +x backup.sh chmod +x restore.sh
chmod +x install_paperless.sh
chmod +x backup.sh
chmod +x restore.sh

ausführbar gemacht werden.

Script backup.sh

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/bin/bash
# Skript: backup.sh
# Dieses Skript führt ein Backup über docker-compose aus und verschiebt anschließend die Backup-Datei(en).
echo "Starte Backup: Ein Backup wird jetzt durchgeführt..."
# Wechsel in das Verzeichnis, in dem sich die docker-compose Datei befindet
cd /home/paperless || { echo "Fehler: Verzeichnis /home/paperless nicht gefunden."; exit 1; }
# Führe den docker-compose Befehl aus
sudo docker compose exec webserver document_exporter ../export -z
# Prüfe, ob der Befehl erfolgreich war
if [ $? -eq 0 ]; then
echo "Backup erfolgreich abgeschlossen."
# Prüfen, ob das Quellverzeichnis existiert
if [ -d "/data/paperless/export" ]; then
# Sicherstellen, dass das Zielverzeichnis existiert (falls nicht, wird es angelegt)
mkdir -p /data/paperless/backup
# Prüfen, ob im Quellverzeichnis Dateien vorhanden sind
if compgen -G "/data/paperless/export/*" > /dev/null; then
echo "Verschiebe Backup-Datei(en) nach /data/paperless/backup..."
mv /data/paperless/export/* /data/paperless/backup/
if [ $? -eq 0 ]; then
echo "Datei(en) erfolgreich verschoben."
else
echo "Fehler beim Verschieben der Datei(en)."
fi
else
echo "Keine Datei(en) im Verzeichnis /data/paperless/export gefunden."
fi
else
echo "Quellverzeichnis /data/paperless/export existiert nicht."
fi
else
echo "Fehler beim Backup."
fi
#!/bin/bash # Skript: backup.sh # Dieses Skript führt ein Backup über docker-compose aus und verschiebt anschließend die Backup-Datei(en). echo "Starte Backup: Ein Backup wird jetzt durchgeführt..." # Wechsel in das Verzeichnis, in dem sich die docker-compose Datei befindet cd /home/paperless || { echo "Fehler: Verzeichnis /home/paperless nicht gefunden."; exit 1; } # Führe den docker-compose Befehl aus sudo docker compose exec webserver document_exporter ../export -z # Prüfe, ob der Befehl erfolgreich war if [ $? -eq 0 ]; then echo "Backup erfolgreich abgeschlossen." # Prüfen, ob das Quellverzeichnis existiert if [ -d "/data/paperless/export" ]; then # Sicherstellen, dass das Zielverzeichnis existiert (falls nicht, wird es angelegt) mkdir -p /data/paperless/backup # Prüfen, ob im Quellverzeichnis Dateien vorhanden sind if compgen -G "/data/paperless/export/*" > /dev/null; then echo "Verschiebe Backup-Datei(en) nach /data/paperless/backup..." mv /data/paperless/export/* /data/paperless/backup/ if [ $? -eq 0 ]; then echo "Datei(en) erfolgreich verschoben." else echo "Fehler beim Verschieben der Datei(en)." fi else echo "Keine Datei(en) im Verzeichnis /data/paperless/export gefunden." fi else echo "Quellverzeichnis /data/paperless/export existiert nicht." fi else echo "Fehler beim Backup." fi
#!/bin/bash
# Skript: backup.sh
# Dieses Skript führt ein Backup über docker-compose aus und verschiebt anschließend die Backup-Datei(en).

echo "Starte Backup: Ein Backup wird jetzt durchgeführt..."

# Wechsel in das Verzeichnis, in dem sich die docker-compose Datei befindet
cd /home/paperless || { echo "Fehler: Verzeichnis /home/paperless nicht gefunden."; exit 1; }

# Führe den docker-compose Befehl aus
sudo docker compose exec webserver document_exporter ../export -z

# Prüfe, ob der Befehl erfolgreich war
if [ $? -eq 0 ]; then
  echo "Backup erfolgreich abgeschlossen."
  
  # Prüfen, ob das Quellverzeichnis existiert
  if [ -d "/data/paperless/export" ]; then
    # Sicherstellen, dass das Zielverzeichnis existiert (falls nicht, wird es angelegt)
    mkdir -p /data/paperless/backup

    # Prüfen, ob im Quellverzeichnis Dateien vorhanden sind
    if compgen -G "/data/paperless/export/*" > /dev/null; then
      echo "Verschiebe Backup-Datei(en) nach /data/paperless/backup..."
      mv /data/paperless/export/* /data/paperless/backup/
      
      if [ $? -eq 0 ]; then
        echo "Datei(en) erfolgreich verschoben."
      else
        echo "Fehler beim Verschieben der Datei(en)."
      fi
    else
      echo "Keine Datei(en) im Verzeichnis /data/paperless/export gefunden."
    fi
  else
    echo "Quellverzeichnis /data/paperless/export existiert nicht."
  fi
else
  echo "Fehler beim Backup."
fi


Script restore.sh

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/bin/bash
# Skript: restore.sh
# Dieses Skript stellt ein Backup wieder her.
set -e
echo "Starte Wiederherstellung: Das Backup wird nun wiederhergestellt..."
DOCKER_COMPOSE_FILE="/home/paperless/docker-compose.yml"
# Funktion zum Auskommentieren der Umgebungsvariablen in docker-compose.yml
comment_out_env_vars() {
echo "Kommentiere PAPERLESS_ADMIN_USER und PAPERLESS_ADMIN_PASSWORD in der docker-compose.yml aus..."
# Erstelle ein Backup der Datei, falls noch nicht gesichert
if [ ! -f "${DOCKER_COMPOSE_FILE}.bak" ]; then
sudo cp "$DOCKER_COMPOSE_FILE" "${DOCKER_COMPOSE_FILE}.bak"
fi
# Setze sicherheitshalber Schreibrechte
sudo chmod u+w "$DOCKER_COMPOSE_FILE"
# Füge das `#` nur hinzu, falls es noch nicht vorhanden ist
sudo sed -i 's/^\( *PAPERLESS_ADMIN_USER: \)/#\1/' "$DOCKER_COMPOSE_FILE"
sudo sed -i 's/^\( *PAPERLESS_ADMIN_PASSWORD: \)/#\1/' "$DOCKER_COMPOSE_FILE"
echo "Variablen erfolgreich auskommentiert."
}
# Variablen auskommentieren, bevor das Skript weiterläuft
comment_out_env_vars
# Verzeichnisse definieren
BACKUP_DIR="/data/paperless/restore"
EXPORT_DIR="/data/paperless/export"
DIRECTORIES_TO_DELETE=(
"/data/paperless/consume"
"/data/paperless/export"
"/data/paperless/media"
"/data/paperless/postgresql"
"/data/paperless/redis"
)
# Prüfe, ob das Backup-Verzeichnis existiert
if [ ! -d "$BACKUP_DIR" ]; then
echo "Fehler: Backup-Verzeichnis $BACKUP_DIR existiert nicht."
exit 1
fi
# Schritt 1: Docker Compose herunterfahren
echo "Wechsle in /home/paperless und fahre Docker Compose herunter..."
cd /home/paperless || { echo "Fehler: Verzeichnis /home/paperless nicht gefunden."; exit 1; }
sudo docker compose down
# Schritt 2: Lösche die angegebenen Verzeichnisse
echo "Lösche die folgenden Verzeichnisse:"
for dir in "${DIRECTORIES_TO_DELETE[@]}"; do
echo " $dir"
if [ -d "$dir" ]; then
sudo rm -rf "$dir"
echo " -> $dir gelöscht."
else
echo " -> $dir existiert nicht, überspringe..."
fi
done
# Schritt 3: Erstelle das Export-Verzeichnis neu
echo "Erstelle das Verzeichnis $EXPORT_DIR..."
sudo mkdir -p "$EXPORT_DIR"
if [ $? -ne 0 ]; then
echo "Fehler: Konnte $EXPORT_DIR nicht erstellen."
exit 1
fi
# Schritt 4: Suche nach einer Archivdatei im Backup-Verzeichnis (z. B. *.zip)
ARCHIVE_FILE=$(find "$BACKUP_DIR" -maxdepth 1 -type f -name "*.zip" | head -n 1)
if [ -z "$ARCHIVE_FILE" ]; then
echo "Fehler: Keine Archivdatei (*.zip) im Backup-Verzeichnis gefunden."
exit 1
fi
echo "Gefundene Archivdatei: $ARCHIVE_FILE"
# Schritt 5: Kopiere die Archivdatei in das Export-Verzeichnis
echo "Kopiere die Archivdatei nach $EXPORT_DIR..."
sudo cp "$ARCHIVE_FILE" "$EXPORT_DIR"
if [ $? -ne 0 ]; then
echo "Fehler beim Kopieren der Archivdatei."
exit 1
fi
# Schritt 6: Wechsel in das Export-Verzeichnis und entpacke die Archivdatei
cd "$EXPORT_DIR" || { echo "Fehler: Konnte nicht in $EXPORT_DIR wechseln."; exit 1; }
# Überprüfe, ob 'unzip' installiert ist und installiere es gegebenenfalls
if ! command -v unzip >/dev/null 2>&1; then
echo "Das Paket 'unzip' ist nicht installiert. Versuche, es zu installieren..."
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update && sudo apt-get install -y unzip
elif command -v yum >/dev/null 2>&1; then
sudo yum install -y unzip
else
echo "Kein unterstützter Paketmanager gefunden. Bitte installiere 'unzip' manuell."
exit 1
fi
fi
# Entpacken der Archivdatei
ARCHIVE_BASENAME=$(basename "$ARCHIVE_FILE")
echo "Entpacke $ARCHIVE_BASENAME..."
unzip "$ARCHIVE_BASENAME"
if [ $? -ne 0 ]; then
echo "Fehler beim Entpacken von $ARCHIVE_BASENAME."
exit 1
fi
echo "Archiv erfolgreich entpackt."
# Optional: Entferne die kopierte Archivdatei, falls sie nicht mehr benötigt wird
# sudo rm "$ARCHIVE_BASENAME"
# Schritt 7: Starte Docker Compose Container neu
echo "Wechsle zurück nach /home/paperless und starte die Container..."
cd /home/paperless || { echo "Fehler: Verzeichnis /home/paperless nicht gefunden."; exit 1; }
sudo -u paperless docker compose up -d
if [ $? -ne 0 ]; then
echo "Fehler: Docker Compose konnte nicht gestartet werden."
exit 1
fi
sudo chown -R paperless:paperless /data/paperless/consume /data/paperless/media
sudo chmod -R 775 /data/paperless/consume /data/paperless/media
sudo chown paperless:paperless /home/paperless/docker-compose.yml
sleep 60
cd /home/paperless
# Schritt 8: Führe den Importbefehl aus
echo "Führe Importbefehl aus..."
sudo docker compose exec webserver document_importer ../export
sudo chown -R paperless:paperless /data/paperless
if [ $? -eq 0 ]; then
echo "Import erfolgreich abgeschlossen."
else
echo "Fehler beim Import."
exit 1
fi
echo " Bitte einmal das System neu booten ! "
echo "---------------------------ENDE--------------------------------"
#!/bin/bash # Skript: restore.sh # Dieses Skript stellt ein Backup wieder her. set -e echo "Starte Wiederherstellung: Das Backup wird nun wiederhergestellt..." DOCKER_COMPOSE_FILE="/home/paperless/docker-compose.yml" # Funktion zum Auskommentieren der Umgebungsvariablen in docker-compose.yml comment_out_env_vars() { echo "Kommentiere PAPERLESS_ADMIN_USER und PAPERLESS_ADMIN_PASSWORD in der docker-compose.yml aus..." # Erstelle ein Backup der Datei, falls noch nicht gesichert if [ ! -f "${DOCKER_COMPOSE_FILE}.bak" ]; then sudo cp "$DOCKER_COMPOSE_FILE" "${DOCKER_COMPOSE_FILE}.bak" fi # Setze sicherheitshalber Schreibrechte sudo chmod u+w "$DOCKER_COMPOSE_FILE" # Füge das `#` nur hinzu, falls es noch nicht vorhanden ist sudo sed -i 's/^\( *PAPERLESS_ADMIN_USER: \)/#\1/' "$DOCKER_COMPOSE_FILE" sudo sed -i 's/^\( *PAPERLESS_ADMIN_PASSWORD: \)/#\1/' "$DOCKER_COMPOSE_FILE" echo "Variablen erfolgreich auskommentiert." } # Variablen auskommentieren, bevor das Skript weiterläuft comment_out_env_vars # Verzeichnisse definieren BACKUP_DIR="/data/paperless/restore" EXPORT_DIR="/data/paperless/export" DIRECTORIES_TO_DELETE=( "/data/paperless/consume" "/data/paperless/export" "/data/paperless/media" "/data/paperless/postgresql" "/data/paperless/redis" ) # Prüfe, ob das Backup-Verzeichnis existiert if [ ! -d "$BACKUP_DIR" ]; then echo "Fehler: Backup-Verzeichnis $BACKUP_DIR existiert nicht." exit 1 fi # Schritt 1: Docker Compose herunterfahren echo "Wechsle in /home/paperless und fahre Docker Compose herunter..." cd /home/paperless || { echo "Fehler: Verzeichnis /home/paperless nicht gefunden."; exit 1; } sudo docker compose down # Schritt 2: Lösche die angegebenen Verzeichnisse echo "Lösche die folgenden Verzeichnisse:" for dir in "${DIRECTORIES_TO_DELETE[@]}"; do echo " $dir" if [ -d "$dir" ]; then sudo rm -rf "$dir" echo " -> $dir gelöscht." else echo " -> $dir existiert nicht, überspringe..." fi done # Schritt 3: Erstelle das Export-Verzeichnis neu echo "Erstelle das Verzeichnis $EXPORT_DIR..." sudo mkdir -p "$EXPORT_DIR" if [ $? -ne 0 ]; then echo "Fehler: Konnte $EXPORT_DIR nicht erstellen." exit 1 fi # Schritt 4: Suche nach einer Archivdatei im Backup-Verzeichnis (z. B. *.zip) ARCHIVE_FILE=$(find "$BACKUP_DIR" -maxdepth 1 -type f -name "*.zip" | head -n 1) if [ -z "$ARCHIVE_FILE" ]; then echo "Fehler: Keine Archivdatei (*.zip) im Backup-Verzeichnis gefunden." exit 1 fi echo "Gefundene Archivdatei: $ARCHIVE_FILE" # Schritt 5: Kopiere die Archivdatei in das Export-Verzeichnis echo "Kopiere die Archivdatei nach $EXPORT_DIR..." sudo cp "$ARCHIVE_FILE" "$EXPORT_DIR" if [ $? -ne 0 ]; then echo "Fehler beim Kopieren der Archivdatei." exit 1 fi # Schritt 6: Wechsel in das Export-Verzeichnis und entpacke die Archivdatei cd "$EXPORT_DIR" || { echo "Fehler: Konnte nicht in $EXPORT_DIR wechseln."; exit 1; } # Überprüfe, ob 'unzip' installiert ist und installiere es gegebenenfalls if ! command -v unzip >/dev/null 2>&1; then echo "Das Paket 'unzip' ist nicht installiert. Versuche, es zu installieren..." if command -v apt-get >/dev/null 2>&1; then sudo apt-get update && sudo apt-get install -y unzip elif command -v yum >/dev/null 2>&1; then sudo yum install -y unzip else echo "Kein unterstützter Paketmanager gefunden. Bitte installiere 'unzip' manuell." exit 1 fi fi # Entpacken der Archivdatei ARCHIVE_BASENAME=$(basename "$ARCHIVE_FILE") echo "Entpacke $ARCHIVE_BASENAME..." unzip "$ARCHIVE_BASENAME" if [ $? -ne 0 ]; then echo "Fehler beim Entpacken von $ARCHIVE_BASENAME." exit 1 fi echo "Archiv erfolgreich entpackt." # Optional: Entferne die kopierte Archivdatei, falls sie nicht mehr benötigt wird # sudo rm "$ARCHIVE_BASENAME" # Schritt 7: Starte Docker Compose Container neu echo "Wechsle zurück nach /home/paperless und starte die Container..." cd /home/paperless || { echo "Fehler: Verzeichnis /home/paperless nicht gefunden."; exit 1; } sudo -u paperless docker compose up -d if [ $? -ne 0 ]; then echo "Fehler: Docker Compose konnte nicht gestartet werden." exit 1 fi sudo chown -R paperless:paperless /data/paperless/consume /data/paperless/media sudo chmod -R 775 /data/paperless/consume /data/paperless/media sudo chown paperless:paperless /home/paperless/docker-compose.yml sleep 60 cd /home/paperless # Schritt 8: Führe den Importbefehl aus echo "Führe Importbefehl aus..." sudo docker compose exec webserver document_importer ../export sudo chown -R paperless:paperless /data/paperless if [ $? -eq 0 ]; then echo "Import erfolgreich abgeschlossen." else echo "Fehler beim Import." exit 1 fi echo " Bitte einmal das System neu booten ! " echo "---------------------------ENDE--------------------------------"
#!/bin/bash
# Skript: restore.sh
# Dieses Skript stellt ein Backup wieder her.

set -e

echo "Starte Wiederherstellung: Das Backup wird nun wiederhergestellt..."

DOCKER_COMPOSE_FILE="/home/paperless/docker-compose.yml"

# Funktion zum Auskommentieren der Umgebungsvariablen in docker-compose.yml
comment_out_env_vars() {
  echo "Kommentiere PAPERLESS_ADMIN_USER und PAPERLESS_ADMIN_PASSWORD in der docker-compose.yml aus..."

  # Erstelle ein Backup der Datei, falls noch nicht gesichert
  if [ ! -f "${DOCKER_COMPOSE_FILE}.bak" ]; then
    sudo cp "$DOCKER_COMPOSE_FILE" "${DOCKER_COMPOSE_FILE}.bak"
  fi

  # Setze sicherheitshalber Schreibrechte
  sudo chmod u+w "$DOCKER_COMPOSE_FILE"

  # Füge das `#` nur hinzu, falls es noch nicht vorhanden ist
  sudo sed -i 's/^\( *PAPERLESS_ADMIN_USER: \)/#\1/' "$DOCKER_COMPOSE_FILE"
  sudo sed -i 's/^\( *PAPERLESS_ADMIN_PASSWORD: \)/#\1/' "$DOCKER_COMPOSE_FILE"

  echo "Variablen erfolgreich auskommentiert."
}

# Variablen auskommentieren, bevor das Skript weiterläuft
comment_out_env_vars

# Verzeichnisse definieren
BACKUP_DIR="/data/paperless/restore"
EXPORT_DIR="/data/paperless/export"
DIRECTORIES_TO_DELETE=(
  "/data/paperless/consume"
  "/data/paperless/export"
  "/data/paperless/media"
  "/data/paperless/postgresql"
  "/data/paperless/redis"
)

# Prüfe, ob das Backup-Verzeichnis existiert
if [ ! -d "$BACKUP_DIR" ]; then
  echo "Fehler: Backup-Verzeichnis $BACKUP_DIR existiert nicht."
  exit 1
fi

# Schritt 1: Docker Compose herunterfahren
echo "Wechsle in /home/paperless und fahre Docker Compose herunter..."
cd /home/paperless || { echo "Fehler: Verzeichnis /home/paperless nicht gefunden."; exit 1; }
sudo docker compose down

# Schritt 2: Lösche die angegebenen Verzeichnisse
echo "Lösche die folgenden Verzeichnisse:"
for dir in "${DIRECTORIES_TO_DELETE[@]}"; do
  echo "  $dir"
  if [ -d "$dir" ]; then
    sudo rm -rf "$dir"
    echo "    -> $dir gelöscht."
  else
    echo "    -> $dir existiert nicht, überspringe..."
  fi
done

# Schritt 3: Erstelle das Export-Verzeichnis neu
echo "Erstelle das Verzeichnis $EXPORT_DIR..."
sudo mkdir -p "$EXPORT_DIR"
if [ $? -ne 0 ]; then
  echo "Fehler: Konnte $EXPORT_DIR nicht erstellen."
  exit 1
fi

# Schritt 4: Suche nach einer Archivdatei im Backup-Verzeichnis (z. B. *.zip)
ARCHIVE_FILE=$(find "$BACKUP_DIR" -maxdepth 1 -type f -name "*.zip" | head -n 1)
if [ -z "$ARCHIVE_FILE" ]; then
  echo "Fehler: Keine Archivdatei (*.zip) im Backup-Verzeichnis gefunden."
  exit 1
fi
echo "Gefundene Archivdatei: $ARCHIVE_FILE"

# Schritt 5: Kopiere die Archivdatei in das Export-Verzeichnis
echo "Kopiere die Archivdatei nach $EXPORT_DIR..."
sudo cp "$ARCHIVE_FILE" "$EXPORT_DIR"
if [ $? -ne 0 ]; then
  echo "Fehler beim Kopieren der Archivdatei."
  exit 1
fi

# Schritt 6: Wechsel in das Export-Verzeichnis und entpacke die Archivdatei
cd "$EXPORT_DIR" || { echo "Fehler: Konnte nicht in $EXPORT_DIR wechseln."; exit 1; }

# Überprüfe, ob 'unzip' installiert ist und installiere es gegebenenfalls
if ! command -v unzip >/dev/null 2>&1; then
  echo "Das Paket 'unzip' ist nicht installiert. Versuche, es zu installieren..."
  if command -v apt-get >/dev/null 2>&1; then
    sudo apt-get update && sudo apt-get install -y unzip
  elif command -v yum >/dev/null 2>&1; then
    sudo yum install -y unzip
  else
    echo "Kein unterstützter Paketmanager gefunden. Bitte installiere 'unzip' manuell."
    exit 1
  fi
fi

# Entpacken der Archivdatei
ARCHIVE_BASENAME=$(basename "$ARCHIVE_FILE")
echo "Entpacke $ARCHIVE_BASENAME..."
unzip "$ARCHIVE_BASENAME"
if [ $? -ne 0 ]; then
  echo "Fehler beim Entpacken von $ARCHIVE_BASENAME."
  exit 1
fi
echo "Archiv erfolgreich entpackt."

# Optional: Entferne die kopierte Archivdatei, falls sie nicht mehr benötigt wird
# sudo rm "$ARCHIVE_BASENAME"

# Schritt 7: Starte Docker Compose Container neu
echo "Wechsle zurück nach /home/paperless und starte die Container..."
cd /home/paperless || { echo "Fehler: Verzeichnis /home/paperless nicht gefunden."; exit 1; }
sudo -u paperless docker compose up -d
if [ $? -ne 0 ]; then
  echo "Fehler: Docker Compose konnte nicht gestartet werden."
  exit 1
fi

sudo chown -R paperless:paperless /data/paperless/consume /data/paperless/media
sudo chmod -R 775 /data/paperless/consume /data/paperless/media
sudo chown paperless:paperless /home/paperless/docker-compose.yml


sleep 60

cd /home/paperless
# Schritt 8: Führe den Importbefehl aus
echo "Führe Importbefehl aus..."
sudo docker compose exec webserver document_importer ../export
sudo chown -R paperless:paperless /data/paperless 
if [ $? -eq 0 ]; then
  echo "Import erfolgreich abgeschlossen."
else
  echo "Fehler beim Import."
  exit 1
fi
echo " Bitte einmal das System neu booten ! "
echo "---------------------------ENDE--------------------------------"

ASN QR Codes generieren

Avery Zweckform QR-Code Generator von Tobias L. Meier: https://tobiasmaier.info/asn-qr-code-label-generator/

Home Assistant Rest API Sensoren

Im Video habe ich auch gezeigt, wie man einen Sensor in Home Assistant erstellt, um sich die Anzahl der Dokumente im Posteingang anzeigen zu lassen. Die Informationen dazu habe ich von Flemming´s Blog, wo einige Beispielsensoren zu finden sind. Tolle Arbeit und sehr gut erklärt.

Monitoring Paperless-ngx in Home-Assistant – Flemming’s Blog

Empfohlene Hardware für die Digitalisierung und die QR Codes

Ein weiterer Scanner, der häufiger im Kontext mit paperless-ngx genannt wird, ist der Brother ADS-1700W. Da ich diesen allerdings nicht selber getestet habe, kann ich keine direkte Empfehlung dazu aussprechen.

Solltest du in den Scripten noch Fehler finden, kannst du mir gerne deine Korrekturen als Mail zukommen lassen. Meine Kontakdaten findest du im Impressum.

📌 Home Assistant Sensordaten exportieren & in Excel nutzen! 🚀

Möchtest du Sensordaten aus Home Assistant exportieren und diese in Excel oder anderen Tools weiterverarbeiten? In meinem neuesten Video zeige ich dir, wie du mit einfachen Schritten deine Daten extrahierst, speicherst und optimal aufbereitest. Dabei erhältst du praktische Tipps, die dir helfen, deine Daten in handliche Formate zu überführen – ideal für den privaten Gebrauch oder berufliche Projekte.

Lass dich von den vielfältigen Möglichkeiten inspirieren und erweitere deine Kenntnisse im Umgang mit Home Assistant. So wird der Datenexport zu einem spannenden und unkomplizierten Prozess!

Was dich im Video erwartet:

  • Wie du Sensordaten aus Home Assistant extrahierst 📡
  • Welche Möglichkeiten es für den Export gibt 🔄
  • Wie du die Daten für Excel & Co. optimierst 📊

Video:
Schau dir das Video hier an: https://youtu.be/iEUIEaDh5XU