Panel für Hausautomation – 2. Versuch

Nachdem mein erster Versuch ein Panel für die Hausautomation zu erstellen, gescheitert ist (siehe https://www.dev-metal.ch/?p=1586) ist dies nun der zweite Versuch. Das Grundsetting ist das gleiche  geblieben:

Hardware:

Installation

Neu verwende ich nicht fullpageos sondern das raspberry pi OS. Die Full-Version in der 64bit Variante.

Raspberry Pi Installation wie gewohnt durch schreiben eines SD-Images. Ich aktiviere dabei den SSH-Server gleich mit. Ich konfiguriere das OS auch so, dass ein autologin stattfindet. Am Ende eines Bootvorgangs gelangt man damit direkt auf den eingeloggten Desktop.

Welectron gibt an, dass man für die Installation auf einem Raspberry Pi folgende Anpassungen an der /boot/config.txt vornehmen muss:

# uncomment to force a specific HDMI mode (this will force VGA)
hdmi_group=2
hdmi_mode=82
hdmi_cvt 1920 1080 60 6 0 0 0

Diese Anpassungen waren aber in meinem Falle gar nicht nötig. Das Panel wurde sofort korrekt erkannt.

X11VNC Server

Da es sich hierbei um ein Panel handelt, sind Tastatur und Maus nicht fix montiert. Entsprechend macht es Sinn, das Gerät per Remote steuern zu können. Das wird mit X11VNC-Server umgesetzt. X11VNC ermöglicht es existierende X11-Sessions per VNC weiterzuleiten:

x11vnc installieren

sudo apt-get update
sudo apt-get install x11vnc

Server testeshalber starten

x11vnc -usepw -forever -display :0

Beim ersten Start wird das Setzen eines Passwortes verlangt. Hier entsprechend eines setzen.

Nun noch sicherstellen, dass der X11VNC-Server beim booten bzw. beim Login des Users

nano /home/pi/.config/autostart/x11vnc.desktop

Folgende Zeilen eingeben

[Desktop Entry]
Type=Application
Name=X11VNC
Exec=x11vnc -usepw -forever -display :0
StartupNotify=false

Raspberry Pi neu starten.

sudo reboot

Ab sofort ist der VNC-Server verfügbar. Ein Client kann nun mit

 vncviewer <ip>:0

auf den Raspberry Pi zugreifen.

Chromium installieren

Chromium bietet einen Kiosk-Mode. Dieser wurde bei fullpageos auch verwendet. Ich verwende der Einfachheit halber den gleichen Browser, mit den gleichen Start-Parametern:

Installieren:

 sudo apt-get install raspberrypi-ui-mods chromium-browser

Damit die Mouse-Curser entfernt werden können, muss noch unclutter installiert werden

 sudo apt-get install unclutter

Ein Config-Verzeichnis im eigenen ~/ erstellen:

 mkdir -p /home/pi/.config/lxsession/LXDE-pi/

Script aufsetzen

 nano /home/pi/.config/lxsession/LXDE-pi/autostart

und folgendermassen befüllen

# @xset s off ^[#(Screensaver ausschalten) Geht alternativ auch über die Oberfläche.
@xset -dpms #(Energiesparmodus deaktivieren) Geht alternativ auch über die Systemeinstellungen
# @xset s noblank #(Screensaver ausschalten)
@chromium-browser --v=0 --kiosk --touch-events=enabled --disable-pinch --noerrdialogs --simulate-outdated-no-au='Tue, 31 Dec 2099 23:59:59 GMT' --disable-session-crashed-bubble --disable-component-update --overscroll-history-navigation=0 --disable-features=Translate --app=http://primary-spacelynk.home.arpa/scada-vis
@unclutter -idle 0 # besagt, dass der Mouse-Curser 0s nach der letzten Aktivierung ausgeblendet werden soll

Ich lasse hier bewusst den Screensaver an (auskommentieren von @xset s off und #@xset s noblank). Das Panel soll schwarz werden, sobald es eine weile nicht gebraucht wird.

xscreensaver

Xscreensaver soll nach einigen Minuten inaktivität das Panel auf „Blank“ setzen, also einen schwarzen Bildschirm an das Panel senden.

Installation

sudo apt-get install xscreensaver

Komplettes entfernen des Maus-Cursors

Unclutter entfernt den Maus-Cursor nicht komplett. Es blendet den Cursor lediglich nach x.xx sekunden inaktivität wieder aus. Wenn man aber auf das Touchpanel streicht, bleibt der Cursor auch dann sichtbar, wenn man -idle 0 konfiguriert hat.

Man kann die Maus auch komplett ausblenden. Damit ist dann aber die Maus auch  nicht verfügbar, wenn man auf dem Raspi eine Maus anschliesst:

vi /etc/lightdm/lightdm.conf
#xserver-command=X 
neu:  xserver-command=X -nocursor

xdotool

xdotool bietet die Möglichkeit per command-line (ssh) Maus und Tastatur-events an die x-session zu senden:

sudo apt-get install xdotool

Folgendes Script (geklaut bei fullpageos) setzt das Chromium-Fenster aktiv und senden ein refresh (ctrl+f5)

#!/bin/bash
export DISPLAY=:0
sleep 1
WID=$(xdotool search --onlyvisible --class chromium|head -1)
xdotool windowactivate ${WID}
xdotool key ctrl+F5

xdotool key F11

Mausklicks für Kamera-Auswahl

Wenn es an der Türe klingelt, soll das Panel automatisch auf der Visualisierung das Kamerabild einblenden. Dies kann man nun mit xdotool wunderbar umsetzen. Folgendes Script simuliert zwei Toches auf dem Panel und wählt damit das gewünschte Kamerabild automatisch aus. Dieses Script wird von der Kamera getriggert, sobald jemand die Klingel getätigt hat:

#!/bin/bash
export DISPLAY=:0
sleep 1
WID=$(xdotool search --onlyvisible --class chromium|head -1)
xdotool windowactivate ${WID}

### Select Kamera-Menu
xdotool mousemove 1720 900 click 1
sleep .5

### Select Mobotix Camera
xdotool mousemove 250 200 click 1

 

Reboot to Chromium/Desktop

Falls ich mal den Desktop per VNC benötige, habe ich mir zwei bash-scripte geschrieben, welche das autostart-File entfernt und duchbootet (bootToDesktop.sh) oder das autostart-File nach /home/pi/.config/lxsession/LXDE-pi/ schreibt und bootet (bootToChromium.sh).

Problembehebungen

Wayland Display Server / ydotool

Wenn man xdotool unter Wayland (z.B. Ubuntu 22.04) verwendet kann das Problem auftauchen, dass xdotool den „Black-Screen“ nicht wieder deaktiviert. Will hiessen, dass die Mausbewegungen und Clicks zwar ausgeführt werden, der Bildschirm selber aber Schwarz bleibt, wenn er mal in den „Tiefschlaf“ gefallen ist. Abhilfe bringt dann ydotool:

ydotool kann nicht aus den Quellen installiert werden (veraltet). Stattdessen hier eine Anleitung, wie man ydotool aus Github selber bildet:

Nach der Installation konnte ydotool immer noch nicht als normaler User ausgeführt werden, weil das Socket-File nicht gefunden wird. Hier die Lösung dafür:

Schlussendlich habe ich einfach in meinen xdotool-Files erst einen ydotool command ausgeführt. Dieser aktiviert den Screen. Anschliessend führe ich mit xdotool fort:

#!/bin/bash
export DISPLAY=:0
YDOTOOL_SOCKET="/tmp/.ydotool_socket" ydotool mousemove --absolute -- 1720 800

sleep .5

WID=$(xdotool search --onlyvisible --class chromium|head -1)
xdotool windowactivate ${WID}

### Select Kamera-Menu
xdotool mousemove 1720 800 click 1

sleep .1

### Select Axis Kinderzimmer Camera
xdotool mousemove 900 600 click 1

 

SWAP Speicher erhöhen

Es zeigt sich, dass Chromium sehr Speicherhungrig ist und das Anzeigen von sehr grossen Grafana-Panels das System zum erliegen bringen kann. Deswegen habe ich den SWAP Speicher auf 2048 erhöht: https://pimylifeup.com/raspberry-pi-swap-file/

WLAN Verbindung (Stabilität) verbessern

Der Standard WLAN Adapter des Raspberry PIs 4 ist zwar schnell aber seine Reichweite ist nicht wirklich gut. Deswegen verwende ich einen WLAN USB-Stick, der auch vom System bereits automatisch erkannt und eingebunden wurde (als Wlan1). Um sicherzustellen, dass der Raspi nur über diesen Wlan1 Adapter kommuniziert habe ich zu einem kleinen Trick gegriffen. Unter

/etc/wpa_supplicant/wpa_supplicant.conf

kann bekanntlich das WLAN konfiguriert werden. Alle Wlan Adapter verwenden diese Konfig-File.

Man kann aber auch mehrere solcher Konfig-Files anlegen und diese den Adaptern zuweisen. Dies nach dem Muster wpa_supplicant-„$interface“.conf

Um Wlan0 nicht mehr reden zu lassen, habe ich ein File wpa_supplicant-wlan0.conf ohne entsprechende Netzwerk-Konfig erstellt.

cp wpa_supplicant.conf wpa_supplicant-wlan0.conf

Das wlan0 File sieht dann so aus:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=CH

network={
}

Damit wird für den Adapter Wlan0 dieses Konfig-File verwendet, welches sich entsprechend gar nicht verbindet. Alle anderen Wlan Adapter verwendet weiterhin wpa_supplicant.conf. Damit verbindet sich Wlan1 und Wlan0 bleibt stumm.

Optionale Info: HDMI Power off

Mein Panel besitzt eine Hintergrundbeleuchtung. Dieses blieb bei fullpageos  an, wenn xscreensaver einen Blank-Screen sendete. Dies konnte ich folgendermassen ausschalten:

sudo vcgencmd display_power 0  # HDMI Power off
sudo vcgencmd display_power 1  # HDMI Power on

Kios-Mode verlassen

  • Über VNC verbinden und  Alt+F4 drücken oder
  • über SSH mit ps -ef | grep chromium die Prozess-ID herausfinden und den Prozess killen.

 

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.

Shinobi auf HC4

Mein neues HC4 NAS möchte ich gerne auch als Überwachungs-Station verwenden. Ich entscheide mich Shinobi eine Chance zu geben.

Da Shinobi eine MariaDB einsetzt, wird es hier etwas „unseriös“. Dies, weil ich das Betriebssystem auf dem HC4 auf einer SD Karte betreibe. Eine Datenbank auf einer SD-Karte zu betreiben ist bekanntlich eine sehr schlechte Idee. Deswegen werde ich das Daten-Verzeichnis von mariaDB nach der Installation auf die HDD Disk verlegen (siehe Installation). Das wird zwar die Geschwindigkeit der DB reduzieren, aber dafür  auch die „Anzahl writes“ auf die SD-Karte.

Im weiteren ist Armbian nicht unter dem offiziell unterstützen OS. Es wird Ubuntu empfohlen. Armbian bassiert aber wie Ubuntu auf Debian. Es besteht also eine Chance… 😉

Installation

Hier habe ich Installations-Instruktionen für Shinobi auf Armbian gefunden:

https://i12bretro.github.io/tutorials/0548.html

sudo apt update
sudo apt upgrade -y
sudo apt install git -y
cd ~git clone https://gitlab.com/Shinobi-Systems/Shinobi.git Shinobi
cd Shinobi
sudo chmod +x INSTALL/ubuntu.sh
  • mariadb installieren (y) und passwort setzen
  • shinobi Datenbank installieren (y)
  • State Shinobi on boot (y)

===> Installation beendet.

NodeJs

Während der Installation wurde ich darauf hingewiesen, dass die aktuell installierte Version von nodejs veraltet ist. Auf armbian „jammy“ ist aktuell Verison 12 installiert. Ich installiere nun Version 16 (LTS-Version), welche von shinobi empfohlen wird:

Achtung, bevor die Installation der neuen VErsion durchgeführt werden kann, sollte die alte nodejs Version deinstalliert werden:

sudo apt-get purge nodejs
sudo apt-get autoremove

Anschliessend den Instruktionen von Shinobi folgen:

https://hub.shinobi.video/articles/view/JX1o76s8R8Lm56D

MariaDb Datenverzeichnis wechseln (armbian)

Da ich die mariadb auf einer SD-Karte betreibe, verschiebe die die Datenverzeichnisse auf die HDD:

Als erstes überprüfen wir, wo sich das Datenverzeichnis von MariaDb befindet

sudo mysql -u root -p
MariaDB [(none)]> select @@datadir;
+-----------------+
| @@datadir |
+-----------------+
| /var/lib/mysql/ |
+-----------------+
1 row in set (0.000 sec)
MariaDB [(none)]> exit

Offenkundig liegt es unter /var/lib/mysql. Dieses Verzeichnis müssen wir nun auf unser gewünschtes Ziel hin syncronisieren.

Dazu erstmal die DB stoppen

sudo service mariadb stop

Ich habe mir für das Zielverzeichnis ein subvolume auf btrfs erstellt. Die Daten sollen neu auf „/mnt/program_data/mariadb/data“ geschrieben werden:

sudo rsync -av /var/lib/mysql /mnt/program_data/mariadb/data

Zur Sicherheit das alte Datenverzeichnis umbenennen

sudo mv /var/lib/mysql /var/lib/mysql.bak

Jetzt „biegen“ wir das data Verzeichnis der MariaDB Konfiguration auf das neue Ziel um.

sudo vi /etc/mysql/mariadb.conf.d/50-server.cnf
[mysqld]
. . .
datadir=/mnt/program_data/mariadb/data/mysql
socket=/mnt/program_data/mariadb/data/mysql/mysql.sock
sudo vi /etc/mysql/mariadb.conf.d/50-client.cnf
[client]
socket=/mnt/program_data/mariadb/data/mysql/mysql.sock

[client-mariadb]

Jetzt mariadb neu starten

sudo service mariadb start

und status überprüfen

sudo service mariadb status

Und nun noch überprüfen ob mariadb die änderung übernommen hat:

sudo mysql -u root -p
MariaDB [(none)]> select @@datadir;
+---------------------------------------+
| @@datadir |
+---------------------------------------+
| /mnt/program_data/mariadb/data/mysql/ |
+---------------------------------------+
1 row in set (0.000 sec)
MariaDB [(none)]> exit

MariaDB Runlevel

Da ich die DB auf einem btrfs mount verschoben habe, muss sichergestellt sein, dass MariaDB erst dann gestartet wird, wenn die mounts im System verfügbar sind. Es ist daher nötig, die Reihenfolge der Services zu beeinflussen. Hier habe ich beschrieben wie ich das konkret umgesetzt habe.

Konfiguration shinobi

Über die Admin-Oberfläche einloggen:

http://192.168.x.x:8080/super
  • Passwort von admin@shinobi.video ändern unter „Preferences“ ändern.
  • Neuer Account unter „Accounts“ erstellen.

Die Videos sollen auf meinem HC4 auf den HDD gespeichert werden, nicht auf dem default „video“, welches shinobi vorgibt. Dazu in der Config „Streamdir“ und „VideoDir“ anpassenAnschliessend reboot oder Shinobi Restart.

Jetzt über der Benutzer-Oberfläche mit dem eben erstellen User einloggen.

http://192.168.x.x:8080

Anschliessend diesen punkten folgen:

Was ist zu tun nach einer Shinobi-Installation?

Restart Shinobi

Wenn sich Shinobi aus irgendeinem Grunde aufgehängt hat, kann man den Service neu starten:

cd ~/Shinobi
sudo pm2 restart all

Logs

Die Shinobi-Logs sind über PM2 einsehbar

sudo pm2 logs

Steams

Einder der Gründe wieso ich mich für Shinobi entschieden habe, ist die Möglichkeit alle Streams für externe Anwendungen (z.B. zum Einbinden als iFrame) zu verwenden. Hier ein Link auf die Dokumentation, wie die Streams eingebunden werden können.

Temporär vs. Permanenter API-Key

Ich hatte zu Beginn das Problem, dass nach jedem Shinobi Restart die Stream-Adresse geändert hat. Konkret ändert der API-Key unter welchem auf den Stream zugegriffen werden kann. Hier findet man die Lösung. Offenbar gibt es ein temporärer API-Key, der bei verwendet wird, wenn man auf der Kamera-Übersichtsseite einen Stream anwählt. Und dann gibt es noch einen permanenten API-Key. Diesen muss man einmalig erstellen. Dabei kann man auch den Zugriff auf eine bestimmte IP eingrenzen. Für die Einbindung des Streams in eine andere Applikation muss der permanente API-Key verwendet werden.

Links

Shinobi Closed Circuit TV (CCTV): Creating a Video Monitoring System Using the ODROID-HC2

https://i12bretro.github.io/tutorials/0548.html

How To Configure a Linux Service to Start Automatically After a Crash or Reboot – Part 2: Reference

https://docs.shinobi.video/

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

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 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