Influxdb V2 Löschen von bestimmten Einträgen

Die Standard-Syntax von Influxdb V2 ist “Flux”. Um mit Flux bestimmte Einträge aus einem measurement (Tabelle) zu entfernen, muss man den Timestamp verwenden:

  1. Login auf Influx Host als root=> influx kann nun mit “influx <statement>” angesprochen werden.
  2. Löschen von allen Einträgen aus
    • dem Bucket iobroker
    • Tabelle javascript.0.Solarpower.Huawei.Meter.ReverseActiveEnergy
    • vom 7.2.2024 19:00 und 7.2.2024 19:15
influx delete --bucket iobroker --start 2024-02-07T19:00:00.000Z --stop 2024-02-07T19:15:00.000Z --predicate '_measurement="javascript.0.Solarpower.Huawei.Meter.ReverseActiveEnergy"'

Um sicherzustellen, dass auch die richtigen Einträge erwischt werden, bitte zuerst über den Data Exlorer die Daten anzeigen lassen:

from(bucket: "iobroker")

  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)

  |> filter(fn: (r) => r["_measurement"] == "javascript.0.Solarpower.Huawei.Meter.ReverseActiveEnergy")

  |> filter(fn: (r) => r["_field"] == "value")

  |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)

  |> yield(name: "mean")

Influxdb v2 auf Proxmox (LXC)

Hier beschreibe ich eine Möglichkeit eine Influxdb auf Proxmox containerbasiert zu installieren.

  1. Login Proxmox
  2. Proxmox-Host Shell anwählen => Commando Prompt wird angezeigt
  3. Folgenden Befehl eingeben (aus https://tteck.github.io/Proxmox/)
    bash -c "$(wget -qLO - https://github.com/tteck/Proxmox/raw/main/ct/influxdb.sh)"
    • Settings: “Advanced”
    • OS: Wähle Debian>Ubuntu 22.04 (LTS)
    • Container Type: Unprivileged
    • Password: Setze Root Passwort
    • Container ID: default belassen
    • Hostname: influxdbV2
    • Disk Size in GB: 8
    • CPU Cores: 2
    • RAM in MiB: 2048
    • Bridge: vmbr0
    • IP Adress: dhcp
    • IPv6: enable
    • MTU Size: blank
    • DNS Search Domain: blank
    • DNS Server IP: 192.168.3.1
    • MAC Address: blank
    • Vlan: blank
    • Enable Root SSH Access: yes
    • Enable Verbose Mode: no
    • Create InfluxDB LXC: yes

  • Als nächstes kann ausgewählt werden, welche Influxdb Version installiert werden soll. Hier wähle ich Version 2.
  • Telegraf installiere ich auch gleich mit.
  • Damit ist die Installation auch schon abgeschlossen.
  • Als nächstes überprüfen ob der Container korrekt erstellt wurde.

InfluxDB Configuration

  • Öffne einen Browser mit Link “http://<ip Adresse des Containers>:8086
  • Es öffnet sich die Browser-Oberfläche von Influxdb V2
  • Get Startet
  • Username: admin
  • Passwort: => passwort
  • Organisation Name: Home
  • Initial Bucket Name: iobroker
  • Kopiere den Operater API Token an einen sicheren Ort
  • Let’s get startet!

Damit ist die InfluxDB als LXC Container installiert und grundsätzlich konfiguriert.

Migriere Influxdb V1 Bucket nach Influxdb V2

Nun möchte ich bestehendes Bucket einer Influxdb V1.8 in die neue Influxdb V2 migrieren.

  • SSH Login auf Influxdb V1
  • Folgender Befehl schreibt das Bucket in ein Line Protokoll File (auszuführen als root user):
    influx_inspect export -database iobroker -datadir /mnt/files/influxdb/data -waldir /mnt/files/influxdb/wal -compress -out iobroker.line.gz
  • Das erstelle File “iobroker.line.gz” auf die Zielmaschine kopieren
    scp iobroker.line.gz <user>@<ipadresse des LXC Containers>:
  • Jetzt mit ssh auf der Zielmaschine einloggen
  • das iobroker.line.gz entpacken
    gzip -d iobroker.line.gz
  • Bevor das entpackte File jetzt importiert werden kann, musste ich dieses noch manipulieren.
    vi iobroker.line
    Den gesamten Header löschen:
    #INFLUXDB EXPORT: 2023-01-01T01:59:59+01:00 - 2262-04-12T00:47:16+01:00
    #DDL
    CREATE DATABASE iobroker WITH NAME autogen
    #DML
    #CONTEXT-DATABASE:iobroker
    #CONTEXT-RETENTION-POLICY:autogen
    #writing tsm data
  • Jetzt das file iobroker.line importieren
    influx write -b iobroker --org Home --token <token> -f iobroker.line

Links:

Huawei Sun2000 Wechselrichter mit Telegraf und Grafana

Seit einigen Tagen werkelt bei mir eine PV-Anlage:

  • 2 Wechselrichter SUN2000-10KTL-M1
    • Bietet ein eigenes WLAN Netz (zwecks Konfiguration des Wechselrichters)
  • Einen Dongle (SDongleA) auf dem Master Wechselrichter für FusionSolar App
    • Bietet sowohl ein WLAN Adapter sowie
    • direkter LAN-Anschluss
    • Beides über DHCP

Ziel

Die Werte werden soweit ok auf das FusionSolar Portal von Huawei. Aber ich möchte gerne alle Werte direkt lokal beziehen und auf Grafana darstellen. Hier logge ich meine Erfahrungen und irgendwann hoffentlich auch eine Erfolgsmeldungen.

Good to know

  • Der Wechselrichter selber erstellt ein eigenes WLAN zwecks Konfiguration des Geräts.
  • Der Dongle am Wechselrichter ermöglicht es auf ein vorhandenes WLAN zu verbinden oder ein Netzwerkkabel auf einen Router anzuschliessen. Hauptziel dieses Dongels ist es wohl, die Daten auf FusionApp bzw. in die Cloud zu bringen. Der Dongle selber bietet auch die Möglichkeit Daten per “Modbus TCP” abzufragen. Diese Schnittstelle ist aber sehr unausgereift. Erste Tests mit Telegraf (modbus plugin) haben gezeigt, dass regelmässige Abfragen (z.B. alle 5s) nicht gehen (i/o timeout). Grund dafür ist wahrscheinlich, dass nach der Modubs-Anmeldung 2s gewartet werden muss, bis die erste Register-Abfrage durchgeführt werden kann (eine Huawei Eigenheit). Ich gehe aktuell davon aus, dass Telegraf damit (wenig überraschend) nicht umgehen kann.
  • Die Daten können auch per Modbus TCP am Wechselrichter selber abgefragt werden, sofern man sich mit dem WLAN des Wechselrichters verbunden hat.

Modbus TCP vs Huawei

Man könnte meinen, dass Huawei etwas auf “Kriegsfuss” mit Modbus TCP ist. Regelmässige Abfragen mit Standard Modbus-Clients (z.B. Telegraf oder ioBroker Modbus) schlagen die meiste Zeit fehl. Hier wird davon berichtet, dass die Modbus-Ansteuerung vom Huawei Sun2000 Wechselrichter über TCP etwas speziell sei. Nach dem öffnen des TCP-Ports muss offenbar noch eine 2s Pause eingehalten werden, da sonst keine Daten zurück geliefert werden. Auch wird nicht jede Modbus-TCP-Anfrage mit den angeforderten Registern beantwortet. Huawei melden in diesem Falle “Slave device busy (retry request again later)”.

Modbus auf Wechselrichter aktivieren

Damit der Wechselrichter mit Modubs TCP kommuniziert, muss dies erstmal aktiviert werden. Das geht einerseits über die FusionSolar App (Menupunkt “ich>Inbetriebnahme des Geräts”). Hier einfach das Gerät auswählen. Anschliessend wird versucht auf das Gerät zuzugreifen. Auch wenn da steht “Inbetriebnahme des Geräts” wird einfach nur das “Konfigurations-App” gestartet. Ich vermute mal, dass in der FusionSolar App die App Sun2000 integriert ist. Also keine Angst haben, dass da ein zusätzliches Gerät in Betrieb genommen wird.

Die andere Variante ist, wie erwähnt, die Sun2000 App. Diese ermöglicht ebenfalls die Verbindung mit dem Wechselrichter-WLAN.

Beide Apps sind über den Huawei App Store erhältlich. Ich habe es leider nicht auf anderen Wegen geschafft die APKs zu beziehen. => Also Appstore Installieren, App beziehen und Appstore (hoffentlich für immer) wieder deinstallieren.

Wichtig:
Der Wechselrichter muss mindestens über Firmware Version V200R001C00SPC115 verfügen. Falls nicht, muss die Firmware aktualisiert werden. Das geht über die FusionSolar App. Hierfür braucht es aber explizit einen Installer-Account. Wenn ihr diesen nicht habt, muss dies der Installateur nachholen.

Wenn man über den Wechselrichter modbus verwendet, benötigt man den Port 6607 anstelle von 502!

DD-WRT

Routing von Port 6607 von 192.168.3.3 nach 192.168.200.1 (“WAN” Adresse des Routers nach Wechselrichter)

Routing auf dd-wrt um die IP-Adresse aus 192.168.3/24 als 192.168.200.2 (ip Adresse des WLAN-Clients) aussehen zu lassen

root@DD-WRT:~# iptables -I PREROUTING -t nat -p tcp -d 192.168.3.3 --dport 6607 -j DNAT --to-destination 192.168.200.1:6607
root@DD-WRT:~# iptables -I POSTROUTING -t nat -d 192.168.200.1 -s 192.168.3/24 -p tcp --dport 6607 -j SNAT --to 192.168.200.2

Damit sollte anschliessend ein Telnet Test aus dem 192.168.3./24 Netz  nach 192.168.200.1 (Port 6607) erfolgreich sein:

telnet 192.168.3.3 6607

Damit diese Regeln auch nach Reboot überleben, kann man sie auf dd-wrt Command-Shell GUI (Administration – Commands) eintragen und Speichern. Danach sollten die Regeln auch nach einem Reboot aktiv sein.

Modbus auf SDongleA aktivieren

Auf die gleiche Art und Weise soll auch Modbus TCP auf dem Dongle aktiviert werden. Den Dongle kann man sowohl per WLAN als auch per LAN-Kabel anschliessen. Ich habe beide Varianten (versuchsweise) installiert. Der Dongle kann sowohl WLAN als auch LAN gleichzeitig betreiben.

Wenn der Dongle sich mit dem Heimnetz verbunden hat, war es für mich anschliessend aber nicht mehr möglich, das Dongle-Eigene WLAN zu sehen. Der Dongle scheint das eigene WLAN abzuschalten, sobald man sich per LAN verbindet.

Wichtige Attribute PV Anlage

KennzahlenBezeichnungModubs Register
Netzbezug (-) / Netzeinspeisung (+)Der jeweils letzte Wert aus
Huawei.Meter.ActivePower (W)
Meter.ActivePower
37113 (W)
PV – Aktuelle ProduktionAddition von
– Huawei.Inverter.1.InputPower (kW), letzter Wert +
– Huawei.Inverter.2.InputPower (kW), letzter Wert
Inverter.x.InputPower
32064 (kW)
Aktuelle Hauslast / Verbrauch HausDerived.HouseConsumption (W), letzter Wert

Berechnet aus:
(Huawei.Inverter.1.ActivePower (kW) * 1000 + Huawei.Inverter.2.ActivePower (kW) * 1000) –
Huawei.Meter.ActivePower
Inverter.x.ActivePower 32080 (kW)

Meter.ActivePower
37113 (W)
Aktuelle Leistung pro InverterHuawei.Inverter.x.ActivePower (kW) Inverter.x.ActivePower 32080 (kW)
Produktion / PV Produktion pro InverterHuawei.Inverter.x.AccumulatedEnergyYield (kWh)Huawei.Inverter.x.AccumulatedEnergyYield
32106 (kWh)
NetzeinspeisungHuawei.Meter.PositiveActiveEnergyHuawei.Meter.PositiveActiveEnergy
37119 (kWh)
Eigenverbrauch aus PVTagessummen aus Huawei.Inverter.x.AccumulatedEnergyYield –
Tagessumme aus Huawei.Meter.PositiveActiveEnergy
Huawei.Inverter.x.AccumulatedEnergyYield
32106 (kWh)

Huawei.Meter.PositiveActiveEnergy
37119 (kWh)
Eigenverbrauch aus PV in %100 * Eigenverbrauch aus PV / Produktion
Netzeinspeisung in &100 * Heutige Netzeinspeisung / Produktion
Netzbezug (akkumuliert)Huawei.Meter.ReverseActiveEnergy (kWh)37121 (kWh)
Direktverbrauch aus PVTagessummen aus
Huawei.Inverter.x.DailyEnergyYield

Tagessumme aus
Huawei.Meter.PositiveActiveEnergy
Inverter.x.DailyEnergyYield
32114 (kWh)

Huawei.Meter.PositiveActiveEnergy
37119 (kWh)
Verbrauch aus Netz in %EigenverbrauchAusPV:
Produktion PV: Tagessummen aus
Huawei.Inverter.x.AccumulatedEnergyYield (kWh)

Netzeinspeisung Huawei.Meter.PositiveActiveEnergy


Gesamtverbrauch:
EigenverbrauchAusPV +
Netzbezug
Huawei.Meter.ReverseActiveEnergy)

100 * Gesamtverbrauch / EigenverbrauchAusPV
Verbrauch aus PV in % (Autarkiegrad)
PV-ErzeugungActive Power Inverter + Battery Power
Aktueller PV-Ertrag
Das was aktuell vom Dach kommt:
Input Power32064
Aktuelle Leistung vom “Dach” in WattInverter.Input_Power
PV-GesamtertragAccumulated energy yield32106
PV-TagesertragDaily energy yield32114
PV Tagesverbrauch – Wieviel kWh wurden heute direkt aus der PV Produktion bezogen (Autarkie)Inverter.[1,2].DailyEnergyYield – GridExportToday
PV Gesamteigenverbrauch / Direktverbrauch aus PVAccumulated energy yield – abzüglich Gesamtexport ins Netz (Positive active electricity)32106 – 37119
Heutiger NetzbezugSolarpower.Derived.GridImportToday
Netzbezug/Einspeisung
Bezug oder Einspeisung vom/zum Versorger in Watt.
Positive Werte = Bezug, negative Werte = Einspeisung
Meter.Active_Power
37113
Aktuelle Einspeisung des Inverters in das Hausnetz.
Also die aktuelle “Leistung” des Hauses in Watt
Addition aus PV Erzeugung und ggf. Batterie-Entladung
Inverter.Active_Power
Hauslast aktuellActive Power Inverter – Meter.Active_Power32080 – 37113
Gesamtexport ins Netz (verkauft)Positive active energy37119 (kWh)
Gesamtimport aus dem Netz (gekauft)Reverse Active Energy37121 (kWh)
Gesamtverbrauch StromPV-Gesamtertrag + Gesamtexport ins Netz + 37121 Reverse active Power (Ges.import aus Netz)
PV1_Voltage und PV1_Current: Aktuelle Spannung und Strom von String, U * I = P, somit ergibt sich daraus, wieviel Leistung der String aktuell liefert in Watt
Akku-Ladestand: Energy storage37004
Akku-Ladung des Tagescurrent day charge capacity37015
Akku-Entladung des Tagescurrent day discharge capacity37017
Aktuelle Leistung an der Batterie in Watt, negative Zahlen = Batterie wird entladen, positive Zahlen = Batterie wird geladenBattery_Power
Ladezustand in %Battery_SOC

Links

Armbian SD Karte klonen

Ich verwende für mein HC4 NAS ein Armbian, welches auf einer SD Karte installiert ist. Zwecks Backup wird diese SD Karte geklont.

Hier habe ich bereits beschreiben, wie man ein Klon für ein Raspberry Pi OS durchführen kann.

Für das Klonen der Armbian SD Karte wollte ich eigentlich ein Image wie hier beschreiben erstellen und dieses dann auf eine neue SD-Karte schreiben. Leider schlug dies fehl. Egal ob das Image mit dd, usbimager oder mit Win32DiskImager erstellt wurde. Die Ziel SD-Karte konnte anschliessend den HC4 nicht booten (Kernel Panic). Es schien als ob die zu klonende SD-Karte bereits so fehlerhaft ist, dass ein 1:1 Klon auf Bit-Ebene nicht mehr geht (reine Spekulation. Ich weiss auch nicht ob das überhaupt möglich wäre).

Nichts desto trotz habe ich deswegen die Strategie gewechselt und das Image aus dem laufenden Betrieb gezogen. Hier habe ich das für den Raspberry Pi bereits beschrieben. Für Armbian braucht es aber ein anderes Script. Hier bin ich fündig geworden

Hotclone Script (siehe auch hier )

#!/bin/bash
#----------------------------------------------------
# armbian_hotclone.sh
#
# Copies the sdcard your Armbian system is running from 
# to a new sdcard in an USB-attached card reader. 
#
# The new sdcard can be of any size as long as it can hold 
# the data content of the original card.
#
# The cloned card should be tested after creation to ensure
# it can be used for desaster recovery.
#
# c) Rodolfo 2016-06-19 enjoy !
#-----------------------------------------------------
#

ARMBIAN_ORIG=/dev/mmcblk0
ARMBIAN_CLONE=/dev/sdd

# Clone partial image of original SDcard ( bootstuff + partition table + start of first partition )
# we just copy 4M to account for strange partition alignment

dd if=$ARMBIAN_ORIG of=$ARMBIAN_CLONE bs=1M count=4

# Delete invalid partition of target SDCARD and create/format new ext4-partition

umount $ARMBIAN_CLONE"1"
echo -e "p\nd\nn\n\n\n\n\np\nw\nq\n" | fdisk $ARMBIAN_CLONE 
echo -e "y\n" | mkfs.ext4 $ARMBIAN_CLONE"1"

# Target mount

mkdir /mnt/armbian_clone
mount $ARMBIAN_CLONE"1" /mnt/armbian_clone
rm -r /mnt/armbian_clone/* # cleanup lost+found

# System copy to SDcard

time rsync -avSz --exclude=/dev/* --exclude=/proc/* --exclude=/sys/* --exclude=/media/* \
--exclude=/mnt/* --exclude=/run/* --exclude=/tmp/* / /mnt/armbian_clone

sync

umount $ARMBIAN_CLONE"1"

Ablauf

  1. Starte Armbian und schliesse einen SD-Card Adapter an
  2. Lege eine leere SD-Karte in den SD-Card Adapter
  3. Füre “sudo fdisk -l” aus und ermittle das Device => bei mir war es /dev/sdd
  4. Ändere den Script-Parameter ARMBIAN_CLONE entsprechend auf
    ARMBIAN_CLONE=/dev/sdd
    Auf diese SD-Karte soll das Skript den Klone ausführen
  5. Rufe das Script auf
    sudo ./armbian_hotclone.sh
    Das Script formatiert die SD-Karte und kopiert Bootloader, Partition-Table sowie die Daten auf die neue Karte.
  6. Am Schluss muss noch die UUID auf der geklonten Karte angepasst werden. Dafür
    blkid
    aufrufen und die UUID der neuen Karte notieren.
  7. Diese UUID muss in folgenden Files auf der geklonten Karte angepasst werden
    1. /boot/armbianEnv.txt
    2. /etc/fstab
  8. Damit sollte die geklonte Karte einsatzbereit sein

Auf diese Weise ist ein Klon der Armbian SD-Karte doch noch gelungen.

Systemd Service – Startreihenfolge und warten auf Godot

Für meine  NAS Lösung habe ich ein Raid1, basierend auf btrfs eingesetzt. Services wie Video-Recording und die Bibliotheks-Software speichern dabei ihre Daten auf Mount-Verzeichnisse aus btrfs ab. Leider kam es vor, dass das Mounten der btrfs Verzeichnisse länger dauerte, als das starten der systemd Services. Das führte zur unschönen Situation, dass das System nach einem Reboot im Status “degraded” hängen blieb, weil benötigte Verzeichnisse noch nicht gemountet waren. Folgende Services waren bei mir betroffen:

  • /lib/systemd/system/mariadb.service (für shinobi)
  • /etc/systemd/system/calibre-server.service (für calibre)
  • /etc/systemd/system/cps.service (für calibre)
  • /etc/systemd/system/pm2-root.service (für shinobi)

Ich habe das gelöst, indem ich einen eigenes systemd Target definiert habe und besagte Services auf dieses Target, welches nach “multi-user.target” ausgeführt wird, gesetzt habe.

Und so geht das:

Erstelle ein eigenes Target

vi /etc/systemd/system/custom.target
[Unit]
Description=My Custom Target - um sicherzustellen, dass caliberdb cps und mariadb ganz am schluss starten
Requires=multi-user.target
After=multi-user.target
AllowIsolate=yes

Betroffene Systemd Services auf custom.target legen

Die betroffenen Services werden nun nach custom.target gelegt. Gleichzeitig habe ich eine “sleep” Phase eingebaut um dem btrfs mount sicher genügend zeit zu geben. Damit triggere ich den Start der Services schön nacheinander.

mariadb.service

vi /lib/systemd/system/mariadb.service
[Unit]
...
After=multi-user.target
...

[Install]
...
WantedBy=custom.target
...

[Service]
...
# Warte 120s
TimeoutStartSec=300
ExecStartPre=/bin/sleep 120
...

Services neu installieren

sudo systemctl disable mariadb.service 
sudo systemctl enable mariadb.service

calibre-server.service

vi /etc/systemd/system/calibre-server.service

## startup service
[Unit]
Description=calibre content server
After=multi-user.target

[Service]
...
TimeoutStartSec=300
ExecStartPre=/bin/sleep 140
...

[Install]
WantedBy=custom.target

Services neu installieren

sudo systemctl disable mariadb.service 
sudo systemctl enable mariadb.service

cps.service

vi /etc/systemd/system/cps.service
[Unit]
Description=Calibre-Web
After=multi-user.target

[Service]
...
TimeoutStartSec=300 
ExecStartPre=/bin/sleep 160
...

[Install]
WantedBy=custom.target

Services neu installieren

sudo systemctl disable mariadb.service 
sudo systemctl enable mariadb.service

pm2-root.service

vi /etc/systemd/system/pm2-root.service
[Unit]
...
After=multi-user.target
...

[Install]
WantedBy=custom.target

[Service]
..
TimeoutStartSec=300 
ExecStartPre=/bin/sleep 180
...

Services neu installieren

sudo systemctl disable mariadb.service 
sudo systemctl enable mariadb.service

Links

OpnSense Multicast: Miele XGW3000 / WLAN Tockner in unterschiedlichem Subnet

Ich verwende einen Miele XGW3000 als Zigbee Gateway, welches im LAN (192.168.20.x) angeschlossen ist (fixe IP über DHCP). Gleichzeitig betreibe ich ein WLAN Netz (192.168.30.x). Die beiden Netze sind über zwei Ports an der OpnSense Firewall angeschlossen (LAN/WLAN Interface). Am WLAN ist der Trockner verbunden (fixe IP über DHCP). Das XGW3000 erkennt über Multicast die WLAN Geräte. Da Mulitcast aber auf das Netz-Segment beschränkt ist, findet der XGW3000 aus dem LAN den Trockner im WLAN natürlich nicht.

Hier beschreibe ich, wie ich die Verbindung doch noch hinbekommen habe:

  1. Installation Plugin “UDP Broadcast Relay”
  2. Konfiguration Plugin (Services>UDP Broadcast Relay). Die Multicast-Adresse sowie den Port habe ich mittels Wireshark ausgelesen.
  3. Firewall
    1. LAN
    2. WLAN
  4. NAT > Outbound

Wichtige Anmerkung

Diese “sehr offen” Firewall Rules habe ich nur temporär gesetzt bzw. nach dem erfolgreichen XGW3000 Scan wieder deaktiviert. Denn wenn der XGW3000 das Gerät bzw. die IP Adresse aus dem anderen Subnet mal gefunden hat, bleibt die Verbindung bestehen (weil die IP bekannt ist). Deswegen macht es auch Sinn, dem Gerät eine fixe IP Adresse (über DHCP) zu vergeben.

Schlussendlich habe ich dann nur noch eine Firewall-Rule aktiv, welche die direkte 1:1 Kommunikation zwischen den beiden Geräten erlaubt.

 

 

Bash Scripting: Existieren aktuelle Files in einem Ordner?

Ich verwende seit einiger Zeit Shinobi als Video-Recorder für meine Kameras. Die Installation habe ich hier beschreiben.

Problem

Nun kam es einmal vor, dass Shinobi die Aufnahmen ungeplant gestoppt hat. Damit ich dies schneller bemerke habe ich mir ein Bash-Script gezimmert.

Anforderungen:

  • Skript soll regelmässig überprüfen ob sich in den Video-Verzeichnissen aktuelle Aufnahmen befinden.
  • Falls sich keine aktuellen Aufnahmen darin befinden, soll eine Pushover Nachricht ausgelöst werden.

Umsetzung

Folgendes Script überprüft vordefinierte Verzeichnisse und sendet eine Pushover-Nachricht, falls sich in den Verzeichnissen keine aktuellen Files befinden.

Für das versenden der pushover Nachricht wird das Script von https://github.com/akusei/pushover-bash verwendet.

#!/bin/bash

#***********************************************************************************************
#**
#** Dieses Script überprüft ob sich aktuelle Video-Files in den dafür vorgesehenen Verzeichnissen
#** befindet.
#**
#***********************************************************************************************

#***********************
# Variablen
#***********************
notOlderThan="10" # die Files dürfen nicht älter als diese Variable (in minuten) sein
sourcepath="/home/xxx/checkVideosAvailable/"
paths=( "${sourcepath}videos" "${sourcepath}videos2" "${sourcepath}videos3") # Die zu überprüfenden Verzeichnisse (Array)
pushover_App_Key="xxxxx" #Pushover API Key
pushover_User_Key="xxxxx" #Pushover User Key
out=$(mktemp /tmp/message.XXXXXXXX) #Temp-File zum Aufbereiten der Pushover-Nachricht
timestampLocation="./timestamp" #Pfad und Name zum timestamp File, welches für die Überprüfung des alters gebraucht wird.


#***********************
# Logik
#***********************
filesExists=true

# Erstelle ein File "timestamp" mit einem Timestamp "jetzt - $notOlderThan min". 
# Dieses File wird anschliessend verwendet um über den "find" Befehl das Alter der Files vergleichen zu können. 
date --date="-$notOlderThan minutes" +"%Y%m%d%H%M" | xargs touch $timestampLocation -mt

#iteriere über die paths und überprüfe ob sich darin Files befinden, welche jünger als $notOlderThan bzw. das File $timestampLocation sind 
for i in "${paths[@]}"
do
#echo "Testing $i" >> "$out"
# Suche Files, welche neuer als das erstellte timestamp-file sind.
if test "`find $i/. -newer $timestampLocation -type f`"
then
echo "Aktuelle Video-Files existieren in $i"
else
filesExists=false
echo "Es existieren keine aktuellen Video-Files in \n $i"
fi
done

if [ "$filesExists" = false ] ; 
then
echo "Sende Pushover Nachricht"
cat "$out" | xargs -0 -I XX ./pushover.sh -t $pushover_App_Key -u $pushover_User_Key -m XX
fi

# Entferne die temp Files
rm "$out"
rm $timestampLocation

Installation auf HC4

Das obige bash-Script inkl. Pushover Bashscript in ein Verzeichnis schreiben (z.B. nach /home/xxxx/checkVideosAvailable/ )

cronjob

Das Script soll als cron-job jede Stunde laufen.

sudo -s
crontab -e
-------------
45 * * * * /bin/bash /home/xxx/checkVideosAvailable/checkVideosAvailable.sh > /dev/null 2>&1

Synchronisation HC4 NAS nach Qnap TS-109

Hier habe ich beschrieben, wie man einen rsync-job von eine Thecus NAS nach Qnap TS-109 einrichten kann. Mittlerweile ist mein Thecus NAS Geschichte. Stattdessen läuft das NAS, basierend auf einem Odroid HC4 in meinen 4 Wänden.

Das HC4 NAS verfügt zwar über ein Raid1. Aber die wichtigsten Daten sollen 1:1 noch auf ein weiteres Backup NAS (TS-109) kopiert werden.

Damit Rsync funktioniert muss ein Gerät als Server und eines als Client agieren. Dabei stellt der Client als Initiator eine Verbindung zum Server her und lädt Files herunter oder transferiert Files zum Server.

HC4 NAS (Rsync Server)

Das HC4 wird als RSYNC Server installiert (im Sinne eines Dienstes):

sudo apt-get install rsync

Nach der Installation von rsync müssen zwei Dateien erstellt werden.

Konfigurations-Datei

sudo vi /etc/rsyncd.conf

Diese mit folgendem Inhalt befüllen:

pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsync.log
#hosts allow = 192.168.2.254:255.255.255.0
hosts allow = 192.168.1.101

[testData]
path = /mnt/test123
comment = RSYNC FILES
read only = true
timeout = 300
uid = sys
gid = nogroup
#auth users = rsync1
#secrets file = /etc/rsyncd.secrets

Der rsync-Zugriff erfolgt in diesem Falle über den user “sys”. Hier kann ein beliebiger User konfiguriert werden. Es ist aber wichtig, dass dieser User auch entsprechende Rechte auf dem lokalen Ordner (/mnt/test123) besitzt. Es können beliebig viele solcher “rsync-shares” erstellt werden. Es ist damit auch möglich nur einzelne Unterverzeichnisse zu synchen:

auth users
Hier kommen die Benutzer, die Zugriff auf dieses Modul haben werden. Diese Benutzer müssen nicht unbedingt auf dem System vorhanden sein. Dies sind rsync-Benutzer, die in der Secrets-Datei aufgeführt sein sollten, die in der nächsten Zeile der Konfigurationsdatei beschrieben wird.

secrets-Datei
Das ist die Datei, in der die rsync-Benutzer erstellt werden und die für den Rsync-Server zum Lesen verfügbar ist.

Secrets-Datei

Wenn man die Autentifizierung anwenden möchte, muss entsprechend noch die Secrets-Datei erstellt werden.

Die Secrets-Datei wird in /etc mit dem Namen rsyncd.secrets erstellt und enthält die Paare aus Benutzernamen und Passwort, welche von rsync geprüft werden.

sudo vi /etc/rsyncd.secrets

Mit folgendem Inhalt befüllen

 rsinc1:beispielPassword

Wie wir sehen, ist das Passwort direkt als Text und unverschlüsselt abgelegt. Deswegen ist es eine gute Idee nach Erstellung dieses Files den Zugriff nur noch für Root zu erlauben:

sudo chmod 0640 /etc/rsyncd.secrets

Starten des Rsync-Server Dienstes

sudo rsync --daemon

Es folgt keine weitere Meldung von rsync. Man kann aber überprüfen, ob der rsync daemon läuft:

ps -ef | grep rsync-----
root 821310 1 0 17:23 ? 00:00:00 rsync --daemon

Auch das Log bestätigt, dass alles ok ist:

$ tail /var/log/rsync.log
2022/09/22 17:23:20 [821310] rsyncd version 3.2.3 starting, listening on port 873

RSYNC beim Booten starten

sudo systemctl enable rsync

Zusätzlich:
Dieser Service soll nach dem mounten der btrfs Shares durchgeführt werden. Deswegen setze ich das “After Target” auf “After=runlevel4.target”

sudo vi /etc/systemd/system/multi-user.target.wants/rsync.service

...
After=runlevel4.target
...

Qnap TS-109 (Rsync Client)

Das Qnap TS-109 ist das Zielgerägt bzw. das “target” wohin die Dateien aus dem HC4 kopiert werden sollen.  Es initiiert in der Rolle als “Client” eine Verbindung zum Rsync Server und kopiert anschliessend die Daten:

  • Login über das Qnap TS-109 Webinterface
  • Erstellen der Zielverzeichnisse. z.B. “BackupHC4/test123”, etc.
  • Das Qnap TS-109 liefert bereits ein SSH-Login Plugin mit. Dieses aktivieren.
  • Login über SSH
  • Das Qnap TS-109 liefert ebenfalls bereits rsync out of the box mit.
  • Nun können auf dem Qnap TS-109 rsync Befehle gegen das HC4 ausgeführt werden.
    Folgender Befehl kopiert alle Daten aus dem HC4 Source-Verzeichnis /mnt/test123 in das Qnap TS-109 Zielverzeichnis /share/HDA_DATA/BackupHC4/test123/.
    Parameter delete = gelöschte Dateien werden auch in der Sicherung gelöscht
    Parameter stats = zeigt einen ausführlicheren Report am Ende einer Übertragung an.
rsync -a --delete --stats hc4IP::testData /share/HDA_DATA/BackupHC4/ralwet_data

Backup automatisieren

Nun, da rsync funktioniert ist es Zeit das ganze automatisiert, in regelmässigen Zeitabständen auszuführen.

  • copy_all.sh File unter /mnt/HDA_ROOT erstellen
cd /mnt/HDA_ROOT
vi copy_all.sh

Script:

#!/bin/sh
#
# called by cron to backup the HC4 NAS to the Qnap TS-109 via rsync
echo "start backup via rsync : `date`"
echo "syncing folder : test"
rsync -a --delete --stats hc4IP::testData /share/HDA_DATA/BackupHC4/ralwet_data
echo "end backup via rsync : `date`"
echo "+++++++++++++++++++++++++++++++++++++++++++++++++"

File ausführbar machen

chmod +x copy_all.sh

Nun die crontab des Qnap TS-109 anpassen (“crontab -l” listet die aktuellen Einträge auf)

vi /etc/config/crontab

folgenden Eintrag hinzfügen. Das Script wird nun jeden Sonntag um 1:00 Uhr ausgeführt. Die Logdatei wird in das Root-Verzeichnis des Backups geschrieben.

0 1 * * 0 /mnt/HDA_ROOT/copy_all.sh >> /share/HDA_DATA/BackupHC4/rsync.log 2>&1

crontab neu laden

crontab /etc/config/crontab

cron restarten

/etc/init.d/crond.sh restart

Links

Calibre und Calibre-web auf HC4 mit armbian

Auf meinem HC4 NAS soll Calibre die Bibliotheksverwaltung meiner eBooks übernehmen. Hier wird die Installation beschrieben.

Seit Mitte 2022 ist die Version 6.0 von Calibre verfügbar, welche die ARM CPU Architektur unter Linux unterstützt. Es waren bisher zwar auch Debian-Pakete für Calibre verfügbar, diese waren aber meist veraltet. Calibre empfielt explizit, keine Distro-Pakete einzusetzen und statdessen ihren Installer zu verwenden.

Installation

Notwendige Pakages installieren

  • python ≥ 3.3 => armbian liefert bereits 3.10 mit.
  • xdg-utils
  • wget => wget bereits auf armbian installiert.
  • xz-utils
  • libegl1
  • libopengl0
sudo apt-get install xdg-utils
sudo apt-get install xz-utils
sudo apt-get install libegl1
sudo apt-get install libopengl0

Nun kann Calibre über das installer-Skript installiert werden. Ich führe eine isolierte Installation durch und installiere Calibre auf einem eigens dafür eingerichteten Platz auf der HDD:

wget -nv -O- https://download.calibre-ebook.com/linux-installer.sh | sh /dev/stdin install_dir=/mnt/program_data/calibre-bin isolated=y

Damit ist Calibre unter /mnt/program_data/calibre-bin installiert. Calibre ist eine Desktop Anwendung, welche über eine Server-Komponente verfügt. Logischerweise kann Calibre selber nicht gestartet werden, da wir ja einen headless Server einsetzen. Folgender Aufruf führt entsprechend zu einem Fehler:

/mnt/program_data/calibre-bin/calibre/calibre

Um die Server-Komponente starten zu können, müssen noch einige Schritte getan werden:

cd /mnt/program_data/calibre-bin
mkdir mkdir calibre-library
cd calibre-library

irgend ein eBook herunterladen

wget http://www.gutenberg.org/ebooks/46.kindle.noimages -O christmascarol.mobi

Das Buch der Calibre-db hinzufügen:

cd /mnt/program_data/calibre-bin/calibre
./calibredb add /mnt/program_data/calibre-bin/calibre-library/*.mobi --with-library /mnt/program_data/calibre-bin/calibre-library/Calibre

Damit wurde eine Calibre Library unter /mnt/program_data/calibre-bin/calibre-library/Calibre erstellt und gleichzeitig das Buch hinzugefügt.

Nun kann der Calibre-Server gestartet werden. Da ich den Standart-Port 8080 breits verwende, weise ich über den Parameter –port den Port 8081 zu:

cd /mnt/program_data/calibre-bin/calibre
./calibre-server --port 8081  /mnt/program_data/calibre-bin/calibre-library/Calibre

Nun, da der Server läuft, kann man das Web-Interface aufrufen:

http://192.168.x.xxx:8081

Service erstellen

Achtung: Dieser Service soll nach dem mounten der btrfs Shares durchgeführt werden. Es ist daher nötig, die Reihenfolge der Services zu beeinflussen. Hier habe ich beschrieben wie ich das konkret umgesetzt habe.

sudo vi /etc/systemd/system/calibre-server.service
## startup service
[Unit]
Description=calibre content server
After=runlevel4.target => eigenes Target siehe https://www.dev-metal.ch/?p=1913

[Service]
Type=simple
User=xxx
Group=<Gruppe, welche Schreibzugriff auf /mnt/multimedia/books hat>
ExecStart=/mnt/program_data/calibre-bin/calibre/calibre-server --port 8081 /mnt/program_data/calibre-bin/calibre-library/Calibre --enable-local-write

[Install]
WantedBy=multi-user.target  => eigenes Target siehe https://www.dev-metal.ch/?p=1913
sudo systemctl enable calibre-server
sudo service calibre-server start

Ab sofort wird Calibre-Server als Service beim System-Boot mit gestartet.

Die Bücherbilbiothek Calibre hinzufügen

Ich verfüge bereits über sehr viele eBooks, welches sich unter /mnt/multimeda/books befinden. Dies können nun der Calibre-DB hinzugefügt werden:

./calibredb add /mnt/multimedia/books/ -r --with-library http://localhost:8081#Calibre

Zu beachten ist hier, dass für den library-pfad die lokale http URL verwendet wird. Dies ist nötig, weil calibredb ansonsten den Aufruf bei laufendem Server nicht erlaubt. Da wir den Service mit –enable-local-write gestartet haben, kann calibredb über die lokale URL (localhost) dennoch direkte Bücher hinzufügen.

Im weiteren werden hier die Bücher von /mnt/multimedia/books nach Calibre kopiert.

Automatisch Bücher der Bibliothek hinzufügen

Es gäbe die Möglichkeit einen “Listener-Ordner” zu definieren, über welchem calibredb dann jeweils Bücher direkt importiert. Dann müssten die bücher nur in diesen Ordner kopiert werden und diese würden dann automatisch nach Calibre eingelesen: https://www.digitalocean.com/community/tutorials/how-to-create-a-calibre-ebook-server-on-ubuntu-20-04#step-6-mdash-optional-automatically-adding-books-to-your-calibre-library

Dies verwende ich aber (mal bis auf weiteres) nicht, da Bücher auch elegant über die Weboberfläche von Calibre oder Calibre-Web hochgeladen werden können.

Calibre-web

Das Standard- Web-Interface von Calibre ist zwar zu gebrauchen, aber sicher nicht “state of the art”. Es gibt ein Projekt “Calibre-Web“, welches ein schöneres Interface für die Verwaltung einer Calibre Datenbank bietet (https://github.com/janeczku/calibre-web/wiki/Manual-installation):

sudo apt install python3-pip python3-venv python3-dev

Installations-Verzeichnis erstellen:

mkdir /mnt/program_data/calibre-bin/calibre-web
cd /mnt/program_data/calibre-bin/calibre-web

Virtuelle Umgebung für calibre-web in ordner venv erstellen

python3 -m venv venv

Calibreweb in virutelle Umgebung installieren:

cd /mnt/program_data/calibre-bin/calibre-web
./venv/bin/python3 -m pip install calibreweb

Calibre-Web starten

./venv/bin/python3 -m calibreweb

URL öffnen

http://192.168.x.x:8083

Login

Default admin login:
Username: admin
Password: admin123

Calibre Datenbank konfigurieren

Calibre-Web Konfig Files

Alle Konfig-Files (settings database, logfiles) befinden sich unter

cd /homes/[username]/.calibre-web

zusätzlichen Konfig-Files (für gdrive,  gmail, etc.) sind dort zu konfigurieren.

Calibre-Web als Service installieren

Siehe https://github.com/janeczku/calibre-web/wiki/Setup-Service-on-Linux#start-calibre-web-as-service-under-linux-with-systemd

Achtung: Dieser Service soll nach dem mounten der btrfs Shares durchgeführt werden. Es ist daher nötig, die Reihenfolge der Services zu beeinflussen. Hier habe ich beschrieben wie ich das konkret umgesetzt habe.

Service File erstellen

sudo vi /etc/systemd/system/cps.service
[Unit]
Description=Calibre-Web
After=runlevel4.target => eigenes Target. Siehe https://www.dev-metal.ch/?p=1913

[Service]
Type=simple
User=ralwet
ExecStart=/mnt/program_data/calibre-bin/calibre-web/venv/bin/python3 -m calibreweb

[Install]
WantedBy=multi-user.target => eigenes Target. Siehe https://www.dev-metal.ch/?p=1913

Service aktivieren

sudo systemctl enable cps.service

Service starten

sudo service cps status

Gut zu wissen:

Installations-Pfad

Hier wird die Installation über den pip paket-manager durchgeführt. Wenn man wissen will, wo calibre-web effektiv installiert ist:

/mnt/program_data/calibre-bin/calibre-web/venv/bin/pip show calibreweb

Name: calibreweb
Version: 0.6.19
Summary: Web app for browsing, reading and downloading eBooks stored in a Calibre database.
Home-page: https://github.com/janeczku/calibre-web
Author: @OzzieIsaacs
Author-email: Ozzie.Fernandez.Isaacs@googlemail.com
License: GPLv3+
Location: /mnt/program_data/calibre-bin/calibre-web/venv/lib/python3.10/site-packages
Requires: advocate, APScheduler, Babel, backports-abc, chardet, Flask, Flask-Babel, Flask-Login, Flask-Principal, flask-wtf, iso-639, lxml, PyPDF3, pytz, requests, SQLAlchemy, tornado, unidecode, Wand, werkzeug
Required-by:
Security-Header

Der Security-Header kann hier angepasst werden. => Man muss aber wissen was man tut… 😉

vi /mnt/program_data/calibre-bin/calibre-web/venv/lib/python3.10/site-packages/calibreweb/cps/web.py

@app.after_request
def add_security_headers(resp):
# csp = "default-src 'self'"
# csp += ''.join([' ' + host for host in config.config_trustedhosts.strip().split(',')])
# csp += " 'unsafe-inline' 'unsafe-eval'; font-src 'self' data:; img-src 'self' "
# if request.path.startswith("/author/") and config.config_use_goodreads:
# csp += "images.gr-assets.com i.gr-assets.com s.gr-assets.com"
# csp += " data:"
# resp.headers['Content-Security-Policy'] = csp
# if request.endpoint == "edit-book.show_edit_book" or config.config_use_google_drive:
# resp.headers['Content-Security-Policy'] += " *"
# elif request.endpoint == "web.read_book":
# resp.headers['Content-Security-Policy'] += " blob:;style-src-elem 'self' blob: 'unsafe-inline';"
# resp.headers['X-Content-Type-Options'] = 'nosniff'
# resp.headers['X-Frame-Options'] = 'SAMEORIGIN'
# resp.headers['X-XSS-Protection'] = '1; mode=block'
# resp.headers['Strict-Transport-Security'] = 'max-age=31536000;'
return resp

 

Links

 

OpnSense – Geo IP Blockierung

Aktuell könnte es Sinn machen, gewisse Regionen auf der Firewall gleich direkt zu blockieren. Dies kann man mit OpnSense sehr elegant lösen:

  • Erstelle einen Alias mit Typ “GeoIp”:
    Erstelle eine Floating-Rule auf der Firewall: