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
mount / umount HowTo
Pure-FTP Server auf Ubuntu Server installieren
Pure-FTP ist ein einfach zu installierender und sicherer FTP-Server. Er lässt sich jedoch nicht wie sonst gewohnt über ein Konfig-File konfigurieren. Vielmehr wird der Server (pureftpd) über ein Wrapper-Script aufgerufen, welches dem Server die Konfigurations-Parameter direkt beim Aufruf des Prozesses mitreicht. Die Konfiguration kann aber trotzdem recht einfach durchgeführt werden. Im Verzeichnis
/etc/pure-ftpd/conf
können „One-Liner“ Files erstellt werden, welche vom Wrapper-Script gelesen und als Parameter verwendet werden. Siehe dazu weiter unten die Konfiguration.
Das Wrapper-Script wird hier genauer beschreiben: https://manpages.debian.org/experimental/pure-ftpd-common/pure-ftpd-wrapper.8.en.html
Um zu überprüfen, welche Option aus dem Wrapper-Script gesetzt wurden:
pure-ftpd-wrapper --show-options
Installation
Während der Installation wird nebst dem installieren des Packete auch eine Gruppe „ftpgroup“ und einen User „ftpuser“ erstellt. Das Home-Verzeichnis von „ftpuser“ wird das Root-Verzeichnis für alle virtuellen ftpuser sein. „ftpuser“ dient zukünftig als Profil für alle virtuellen User (beim erstellen eines virutellen Users wird auf diesen ftpuser verwiesen).
sudo apt-get install pure-ftpd sudo groupadd ftpgroup sudo mkdir /home/ftpuser sudo useradd -g ftpgroup -d /dev/null -s /bin/false ftpuser => useradd: Warning: missing or non-executable shell '/etc': Warnung ist ok sudo chown -R ftpuser:ftpgroup /home/ftpuser
Die Grundinstallation ist damit abgeschlossen. Nun kann sicher jeder Linux-User bereits einloggen, wobei das entsprechende Home-Verzeichnis als FTP-Root Verzeichnis verwendet wird. Das ganze ist in diesem Zustand auch noch nicht sehr sicher, da sich die User im gesamten Tree des Servers bewegen dürfen (kein chroot, etc.).
Konfiguration
Jedes File in
/etc/pure-ftpd/conf/
entspricht einem Parameter, wobei das File dem Parameter und der Inhalt des Files dem Wert des Parameters entspricht. Verwendet wird die ausgeschriebene Variante der Parameter. Die möglichen Parameter können mit
pure-ftpd --help
aufgelistet werden.
Ich verwende folgende Konfiguration
sudo bash echo yes > /etc/pure-ftpd/conf/ChrootEveryone echo yes > /etc/pure-ftpd/conf/NoAnonymous echo no > /etc/pure-ftpd/conf/PAMAuthentication echo no > /etc/pure-ftpd/conf/UnixAuthentication echo yes > /etc/pure-ftpd/conf/IPV4Only echo /etc/pure-ftpd/pureftpd.pdb > /etc/pure-ftpd/conf/PureDB
Da wir als Authentifizierung die PureDB nutzen wollen muss noch ein symbolischer Link gesetzt werden:
cd /etc/pure-ftpd/auth sudo ln -s ../conf/PureDB 50pure
Weiter mögliche Konfigurations-Varianten:
echo yes > /etc/pure-ftpd/conf/ProhibitDotFilesWrite echo yes > /etc/pure-ftpd/conf/ProhibitDotFilesRead echo 50 > /etc/pure-ftpd/conf/MaxClientsNumber echo 10 > /etc/pure-ftpd/conf/MaxClientsPerIP echo no > /etc/pure-ftpd/conf/VerboseLog echo yes > /etc/pure-ftpd/conf/DisplayDotFiles echo no > /etc/pure-ftpd/conf/AnonymousOnly echo /etc/pure-ftpd/pureftpd.pdb > /etc/pure-ftpd/conf/PureDB echo yes > /etc/pure-ftpd/conf/NoChmod echo 15 > /etc/pure-ftpd/conf/MaxIdleTime echo 2000 8 > /etc/pure-ftpd/conf/LimitRecursion echo yes > /etc/pure-ftpd/conf/AntiWarez echo no > /etc/pure-ftpd/conf/AnonymousCanCreateDirs echo 4 > /etc/pure-ftpd/conf/MaxLoad echo no > /etc/pure-ftpd/conf/AllowUserFXP echo no > /etc/pure-ftpd/conf/AllowAnonymousFXP echo no > /etc/pure-ftpd/conf/AutoRename echo yes > /etc/pure-ftpd/conf/AnonymousCantUpload echo yes > /etc/pure-ftpd/conf/BrokenClientsCompatibility echo ,21 > /etc/pure-ftpd/conf/Bind echo yes > /etc/pure-ftpd/conf/Daemonize
Virtuelle User
- Erstelle einen User-Home-Verzeichnis (Für jeden Benutzer kann ein solches Verzeichnis erstellt werden)
sudo mkdir /home/ftpuser/<username>
- Auf dem FTP-Verzeichnis die Rechte setzen:
sudo chown -R ftpuser:ftpgroup /home/ftpuser
- Den Virtuellen User beim FTP-Server anlegen
sudo pure-pw useradd $USERNAME -u ftpuser -d /home/ftpuser/$USERNAME
- Damit Pure-FTP den neuen Benutzer mitbekommt, muss die Pure-FTP DB neu erstellen werden:
sudo pure-pw mkdb
Ich verwende auf meinem FTP Server softlinks zu weiteren Verzeichnissen/Datenablagen. Normalerweise verbietet PureFTPd die Weiterleitung an „symlinks“. Man kann dies aber auch explizit erlauben. Dies aber nicht wie (von mir) erwartet über ein Konfig-File „virtualchroot“. Dafür muss man folgende Anpassung machen:
sudo vi /etc/default/pure-ftpd-common => VIRTUALCHROOT=true
Anschliessend erlaubt PureFTPd das Weiterleiten an Symlinks.
TLS / SSL
- TLS/SSL-Support aktivieren und Zertifikat erstellen:
/etc/pure-ftpd/conf# apt-get install openssl
/etc/pure-ftpd/conf# echo 1 > TLS
/etc/pure-ftpd/conf# openssl req -x509 -nodes -newkey rsa:1024 -keyout /etc/ssl/private/pure-ftpd.pem -out /etc/ssl/private/pure-ftpd.pem Generating a 1024 bit RSA private key . . .
/etc/pure-ftpd/conf# chmod 600 /etc/ssl/private/pure-ftpd.pem
pureadmin
Fuer Pure-FTP existiert ein GUI fuer die Administration. Hierfuer einfach das Packet pureadmin installieren.
User-Administration über Konsole
Siehe dazu: https://download.pureftpd.org/pub/pure-ftpd/doc/README.Virtual-Users
Wichtig: nach allen User-Änderungen immer die DB neu generieren:
sudo pure-pw mkdb
Benutzer-Management
View a User
sudo pure-pw show $USERNAME
Change a User’s Password
sudo pure-pw passwd $USERNAME -m
Update an Existing User
sudo pure-pw usermod $USERNAME $OPTIONS -m
Deleting a User
sudo pure-pw userdel $USERNAME -m
Listing All Users
sudo pure-pw list
Update the User/Password Database Manually
sudo pure-pw mkdb
Managing the Pure-FTP Server
Start Pure-FTPd Server
sudo service pure-ftpd start
Stop Pure-FTPD
Note: This does not disconnect active users.
sudo service pure-ftpd stop
Disconnect All Active Users Immediately
sudo killall pure-ftpd
Pure-FTPd Status
sudo service pure-ftpd status
Restart Pure-FTPd
sudo service pure-ftpd restart
View Server Activity
sudo pure-ftpwho
Pure-FTPd deinstallieren
sudo service pure-ftpd stop sudo apt-get autoremove pure-ftpd sudo apt-get purge pure-ftpd sudo rm -r /etc/pure-ftpd sudo userdel ftpuser sudo groupdel ftpgroup
Links
https://linux.die.net/man/8/pure-ftpd
https://www.laub-home.de/wiki/Ubuntu_%26_Debian_Linux_-_Installation_Pure-FTP
https://help.ubuntu.com/community/PureFTP
OpnSense – Geo IP Blockierung
PanelAPI
Hier habe ich beschrieben, wie man ein eigenes Panel für die Hausautomation erstellt, welches nun zufriedenstellend funktioniert. Um gewisse Funktionen auf dem Panel automatisiert ausführen zu können, habe ich ja auch bereits xdotool mit installiert. Dies möchte ich nun aktiv nutzen:
Use-Case
- Wenn jemand an der Haustüre Klingelt, soll die Kamera das Klingelevent verwenden, um das Panel automatisch einzuschalten und die entsprechende Kamera-Sicht auf dem Panel zu aktivieren.
- Da ich vom Sofa aus direkte Sicht zum Hausautomations-Panel habe, wird mir dies erlauben zukünftig zu entscheiden, ob es sich lohnt aufzustehen ;))
Umsetzung
Hier habe ich bereits beschrieben, wie man xdotool nutzen kann um bestimmte Mausklicks auf dem Panel automatisch ausführen zu können. Das Ziel ist es nun, dass die Kamera dieses Script bei einem Klingelevent aufrufen kann. Die Kamera kann sich nicht per SSH auf das Panel einloggen und ein Script aufrufen. Was sie aber kann, ist ein HTTP-GET Call ausführen. Deswegen habe ich ein sehr simples REST-API geschrieben, welches auf dem Panel HTTP-Calls entgegennehmen kann. Das REST-API nimmt damit HTTP Get Calls entgegen und führt dann das xdotool Script aus.
Sparkjava
Ich bin ein ehemaliger Java-Entwickler. Deswegen fällt die Wahl wieder auf Java. Um sowas umzusetzten, musste man früher einige Handstände vollziehen und insbesondere einen Application-Server/Container wie z.B. Tomcat betreiben.
Heute ist das zum Glück einiges einfacher. Ich nutze dafür Sparkjava. Spark ist ein leichtgewichtiges Framework, welches es erlaubt rasch WebApplikationen bzw. REST-APIs zu schreiben.
Für einen ersten Start siehe die Spark-Doku.
Ich beschreibe hier kurz, wie ich die Umsetzung gemacht habe. Achtung: Das ist nicht Best-Practice sondern ein straight-forward Ansatz, ohne spezielles exception-handling…
Maven POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ch.paket</groupId>
<artifactId>PanelAPI</artifactId>
<version>1.0</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.9.3</version>
</dependency>
</dependencies>
</project>
Die Main-Methode
Die Main Methode macht folgendes
- Starten Web-Server auf Port 8011, er hört auf get URL „/selectMobotixCamera“
- Wenn die URL aufgerufen wird, wird das Bash-Script ausgeführt. Die return-messages des Scripts werden anschliessend gelesen und zurückgegeben:
package ch.intelli;
import spark.Request;
import spark.Response;
import spark.Route;
import spark.Spark;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args){
spark.Spark.port(8011);
Spark.get("/selectMobotixCamera", new Route() {
public Object handle(final Request request, final Response response){
String message = "";
BufferedReader in;
String[] cmd = new String[]{"/bin/sh", "/home/xxx/xdotool_script.sh", "parameter1"};
Process pr = null;
try {
pr = Runtime.getRuntime().exec(cmd);
in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line = null;
line = in.readLine();
while(line != null)
{
message = message.concat(line);
System.out.println(line);
line = in.readLine();
}
} catch (IOException e) {
e.printStackTrace();
}
return message;
}
});
}
}
Jar als Service einbinden
Nachdem wir nun einen Spark-Webservice erstellt haben (jar), kann dieses als Service auf dem Raspberry Pi eingebunden werden:
Struktur und Service-File erstellen
cd ~ mkdir PanelAPI cd PanelAPI vi panelAPI.service
Inhalt panelAPI.service
[Unit] Description=Java Service for PanelAPI After=network.target [Service] ExecStart=java -jar /home/xxx/PanelAPI/PanelAPI.jar Restart=always User=ralwet [Install] WantedBy=multi-user.target
Service registrieren
sudo cp panelAPI.service /etc/systemd/system/panelAPI.service sudo systemctl enable panelAPI.service
Nach einem Reboot ist das REST-API aktiv.
Links
https://codetober.com/how-to-start-jar-file-as-service-raspberry-pi-4/
OpnSense – Reboot wenn WAN nicht erreichbar
Ich betreibe meine OpnSense Firewall hinter einer UPC Giga Connect Box. Diese ist auf Bridge-Modus gestellt, so dass alle Requests direkt an die OpnSense Firewall gelangen.
Hin und wieder scheint UPC etwas zu maintainen. In der Folge verliert OpnSense die connectivity auf dem WAN-Port. Je nachdem wie häufig die UPC Unterhalt betreibt, fliegt die connectivity 1 – 2x pro Monat raus. Einzig ein Reboot löst dann das Problem.
Um dies zu automatisieren, habe ich ein Script hier abgekupfert.
Ich überprüfe die connectivity, indem ich die DNS-Server von Switch und DigitaleGesellschaft anpinge. Die Pings werden nach /root/pingtest.log geschrieben – und NICHT gelöscht – Wenn alles sauber funktioniert, kann das logfile auch jeweils gelöscht werden.
Als erstes ein Config-File “actions_pingcheck.conf“ mit folgenden Inhalt erstellen.
[start]
command:/usr/local/etc/rc.d/ping_check.sh
parameters:
type:script
message:starting ping_check
description:ping_check
Kopiere das File nach
/usr/local/opnsense/service/conf/actions.d
Jetzt das Bash-Script „ping_check.sh“ erstellen:
#!/bin/sh
#=====================================================================
# USER SETTINGS
#
# Testing uptime to run script only xx seconds after boot
#
# Log file
LOGFILE=/root/pingtest.log
#
#=====================================================================
# Current time
curtime=$(date +%s)
# Bootime in seconds
uptime=$(sysctl kern.boottime | awk -F'sec = ' '{print $2}' | awk -F',' '{print $1}')
# Uptime in seconds
uptime=$(($curtime - $uptime))
# If boot is longer than 120 seconds ago...
if [ $uptime -gt 120 ]; then
# A message to the console (I like feedback -if you don't then comment out the echo, wall and rm lines)
echo "Testing Connection at" `date +%Y-%m-%d.%H:%M:%S` "uptime:" $uptime "seconds" >> $LOGFILE
wall $LOGFILE
#rm $LOGFILE
# Try 1 or 2 minutes worth of very short pings to googles DNS servers - In this case I am only using 10 seconds worth which is the -c 10 value. change this to suit.
# eg a value of 60 would be pne minute.
# Quit immediately if we get a single frame back.
# If neither server responds at all then reboot the firewall.
counting=$(ping -o -s 0 -c 10 185.95.218.42 | grep 'received' | awk -F',' '{ print $2 }' | awk '{ print $1 }' )
if [ $counting -eq 0 ]; then
counting=$(ping -o -s 0 -c 10 130.59.31.248 | grep 'received' | awk -F',' '{ print $2 }' | awk '{ print $1 }' )
if [ $counting -eq 0 ]; then
# trying to just restart NIC
# echo "ping_check: ping fail - trying interface down/up" >> $LOGFILE
# wall $LOGFILE
# rm $LOGFILE
# ifconfig igb0 down
# ifconfig igb0 up
sleep 20
# echo "ping_check: ping fail - Interface reset - trying pings again." >> $LOGFILE
#wall $LOGFILE
# rm $LOGFILE
counting=$(ping -o -s 0 -c 10 185.95.218.42 | grep 'received' | awk -F',' '{ print $2 }' | awk '{ print $1 }' )
if [ $counting -eq 0 ]; then
# network down
echo "Network down - restart Firewall..." >> $LOGFILE
wall $LOGFILE
# Save RRD data && clean reboot
/usr/local/etc/rc.reboot
fi
fi
fi
fi
Kopiere das Bash-Script nach /usr/local/etc/rc.d und stelle sicher, dass es über das execute-flag verfügt
chmod 755 /usr/local/etc/rc.d/ping_check.sh
Nun noch das neu erstellte Script im System als Cron-Job einrichten. Ich führe den Ping alle zwei Minuten durch:

Links
Panel mit fullpageos
Achtung – Fehlversuch
Nach einiger Testzeit hat sich folgendes gezeigt:
Fullpageos hat folgendes Problem mit HML-Streams: https://github.com/guysoft/FullPageOS/issues/291
Meine Visualisierung beinhaltet auch Video-Streams. Sobald diese aktiviert werden, crashed chromium. Das ist so natürlich nicht zu gebrauchen 🙁
Für die Steuerung meiner Hausautomation habe ich mir eine HTML5 Web-Site erstellt. Nun benötige ich ein Touch-Screen Panel, welches ausschliesslich diese Seite anzeigen soll.
Panel: https://www.welectron.com/Waveshare-156inch-HDMI-LCD_1
Beim OS bin ich bei fullpageos fündig geworden. Es ermöglicht eine Kiosk-View basierend auf einem Raspberry Pi.
fullpageos: https://github.com/guysoft/FullPageOS
Die Installation erfolgt wie bei jedem anderen Raspi-OS. Ich beschreibe hier nur die Spezialitäten, welche ich zusätzlich ausgeführt habe.
Entfernen des Maus-Cursors
Standardmässig wird der Maus-Cursor eigeblendet, wenn man den Touchscreen bedient. Ich möchte aber ein „Tablet-Feeling“. Der Maus-Cursor stört. Dieser kann komplett entfernt werden:
https://github.com/guysoft/FullPageOS/issues/15
simply edited lightdm config in/etc/lightdm/lightdm.confchanging line#xserver-command=Xtoxserver-command=X -nocursor
Fonts
Meine HTML5 Seite verwendet diverse Fonts, welche fullpageos nicht standardmässig mit installiert. Diese nachinstallieren:
sudo apt-get install ttf-mscorefonts-installer
Screensaver
fullpageos deaktiviert standardmässig den screensaver. Das macht bei einem öffentlichen Panel auch Sinn. Ich verwende das Panel aber im Haus und möchte, dass der Blank-Screensaver (schwarzer Bildschirm) nach unbenutzer Zeit einschaltet. Dafür folgende Zeile in /home/pi/scripts/start_gui auskommentieren:
# xset s off # don't activate screensaver
Hintergrundbeleuchtung des Panels
xscreensaver sendet nach 10min einen „Blank-Screen“ (also schwarzer Screen) an das Panel. Das Panel selber bleibt aber anschliessend an bzw. die Hintergrundbeleuchtung schaltet nicht ab. Zugunsten einer langen Lebendsauer möchte ich, dass das Panel die Hintergrundbeleuchtung ausschaltet und dann, wenn das Panel wieder bedient wird, wieder einschaltet.
Vi
Vi ist etwas komisch konfiguriert. Sobald man etwas kopieren will, fällt vi in den „visual“ mode. Das kann man verhindern, indem man ein File ~/.vimrc erstellt. Es kann leer sein:
touch ~/.vimrcsudo touch /root/.vimrc
Grafana/Influxdb/Telegraf/Chronograf
Installation auf einem Armbian, 21.02.3 Focal
Installation Influxdb
Installation wird auch hier beschrieben: https://docs.influxdata.com/influxdb/v1.8/introduction/install/
sudo wget -qO- https://repos.influxdata.com/influxdb.key | gpg --dearmor > /etc/apt/trusted.gpg.d/influxdb.gpg
export DISTRIB_ID=$(lsb_release -si); export DISTRIB_CODENAME=$(lsb_release -sc)
sudo echo "deb [signed-by=/etc/apt/trusted.gpg.d/influxdb.gpg] https://repos.influxdata.com/${DISTRIB_ID,,} ${DISTRIB_CODENAME} stable" > sudo /etc/apt/sources.list.d/influxdb.list
Influxdb installieren
sudo apt-get update && sudo apt-get install influxdb sudo service influxdb start
Version auf „hold“ setzen
Bei Influx scheint die Qualität nicht sehr hoch. Nach einem Update von Version 1.8.6 auf 1.8.9 lief die Influxdb nur noch sehr langsam und es hagelte „connection refused“ Fehler. Ich habe deswegen einen downgrade auf die Version 1.8.6 (Ressource) durchgeführt und diese Version nun „fixiert“
wget https://dl.influxdata.com/influxdb/releases/influxdb_1.8.6_armhf.deb sudo dpkg -i influxdb_1.8.6_armhf.deb sudo apt-mark hold influxdb
Mit Installation fortfahren
Nun kann auf die Influx-Shell zugegriffen werden
influx
Benutzer anlegen
CREATE USER "admin" WITH PASSWORD '<adminpassword>' WITH ALL PRIVILEGES CREATE USER "spacelynk" WITH PASSWORD '<userpassword>'
Datenbank anlegen und Berechtigung erteilen
CREATE DATABASE "knxdb" GRANT ALL ON "knxdb" TO "user"
Influxdb konfigurieren
Das Konfig-File der Influx-DB liegt unter /etc/influxdb/…
sudo vi /etc/influxdb/influxdb.conf
Sicherstellen, dass folgende Punkte gesetzt sind:
[http] enabled = true bind-address = ":8086" auth-enabled = true log-enabled = true write-tracing = false pprof-enabled = true https-enabled = false https-certificate = "/etc/ssl/influxdb.pem" flux-enabled = true
Service restarten
sudo service influxdb restart
Nachtrag: Installation Influxdb auf armbian 32Bit (cannot allocate memory)
Die Influxdb lief nun x Monate. Nach einiger Zeit viel auf, dass das System heiss lief (>80°C) und im /var/log/syslog folgende Fehlermeldung erschien:
Jun 1 10:40:42 odroidxu4 influxd[24423]: ts=2022-06-01T08:40:42.988192Z lvl=info msg="Error replacing new TSM files" log_id=xxxx engine=tsm1 tsm1_level=1 tsm1_strategy=level trace_id=0aobcfkW000 op_name=tsm1_compact_group db_shard_id=654 error="cannot allocate memory"
Hier handelt es sich um ein InfluxDB-ARM-32-Bit-Fehler. Influx besteht darauf, die gesamte Datenbank in den Speicher abzubilden ist, was fehlschlägt, wenn die Datenbankgröße größer als die adressierbare Speichergröße ist (2 GB auf 32-Bit-Kerneln, ~ 3,6 GB auf 64-Bit-Kerneln, mit 32-Bit-OS).
Da ich ein 32Bit OS auf einem 32Bit-Kernel betreibe, stosse ich auf diesen Fehler, der das gesamte System instabil macht. Teilweise enstanden OS-Freezes daraus.
Fix
Wie hier beschreiben, existiert ein Fix. Ablauf:
Installation go
Als erstes muss auf dem armbian go installiert werden:
- Suche auf https://golang.org/dl/ die ARMv6 Version
mkdir ~/src && cd ~/src wget https://dl.google.com/go/<version>.tar.gz
- Entpacken
sudo tar -C /usr/local -xzf <version>.tar.gz rm <version>.tar.gz
- Go konfigurieren
vi ~/.profile
folgenes hinzufügen:
PATH=$PATH:/usr/local/go/bin GOPATH=$HOME/go
- Update shell:
source ~/.profile
- Test ob alles ok ist
go version
Influxdb aus github ziehen und compilieren
Folgende Instruktionen ausführen => Achtung! Beim checkout die korrekte influx-version ziehen, also jene, die aktuell über die Packet-Installation installiert und dann auf hold gesetzt wurde. Bei mir ist das Version 1.8.6.
git clone https://github.com/simonvetter/influxdb.git cd influxdb git checkout origin/1.8.6+big_db_32bit mkdir build # target 32-bit ARM architectures, use GOARCH=386 for 32-bit Intel/AMD export GOARCH=arm go build -o build/influx_stress cmd/influx_stress/*.go go build -o build/influx_tools cmd/influx_tools/*.go go build -o build/influx_inspect cmd/influx_inspect/*.go go build -o build/influxd cmd/influxd/main.go go build -o build/influx cmd/influx/main.go
Nun befinden sich die 32-bit binaries im build-verzeichnis:
cd ~/influxdb/build
Als nächstes die „alten“ binaries backupen (sicher ist sicher)
mkdir ~/influxbackup-binaries sudo cp /usr/bin/influx* ~/influxbackup-binaries/
Nun die neuen binaries über die alten kopieren
sudo service influxdb stop cd ~/influxdb/build sudo mv * /usr/bin/ sudo chown root:root /usr/bin/influx*
Jetzt die Konfig so anpassen, dass die DB nicht mehr ins Memory gezwungen wird:
sudo vi /etc/influxdb/influxdb.conf
[data] tsm-use-seek = true # use the seek accessor (what this whole PR is about) index-version = "tsi1" # use on-disk index files instead of keeping them in-memory max-concurrent-compactions = 1 # avoid running multiple compactions at once [coordinator] query-timeout = "60s" # kill runaway queries (you may want to adjust the value depending on your hardware and query set)
Jetzt System restarten
sudo shutdown -r now
Ab sofort sollte die Influx-DB nicht mehr so Speicherhungrig sein und die Systemtemperatur hat sich bei mir auch bei rund 48° eingependelt. Der „cannot allocate memory“ Fehler ist seit dem nicht mehr aufgetaucht => check 🙂
Grafana installieren (OSS Release)
Installation
Installation wird auch hier beschrieben: https://grafana.com/docs/grafana/latest/installation/debian/
sudo apt-get install -y apt-transport-https sudo apt-get install -y software-properties-common wget wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add - echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list sudo apt-get update sudo apt-get install grafana
Konfiguration
Die Configuration von Grafana findet man hier
Ich hatte nach einem Upgrade von Version 7.5 auf Version 8 das Problem (If you’re seeing this Grafana has failed to load its application files), dass gewisse „Embedded-Browser“ nicht mehr funktionierten. Deswegen verwende ich fix Version 7.5.10. Mit dieser gings noch…Dafür musste ich aber ein Downgrade durchführen und anschliessend das Paket auf „halten“ setzen:
sudo apt-get install grafana=7.5.10 sudo apt-mark hold grafana
sudo vi /etc/grafana/grafana.ini
# Grafana soll als eingebettetes Frame angezeigt werden können: allow_embedding = true
[auth.anonymous] # enable anonymous access enabled = true # specify organization name that should be used for unauthenticated users org_name = Home # specify role for unauthenticated users org_role = Viewer # mask the Grafana version number for unauthenticated users hide_version = false
[date_formats] # For information on what formatting patterns that are supported https://momentjs.com/docs/#/displaying/ # Default system date format used in time range picker and other places where full time is displayed full_date = DD-MM-YYYY HH:mm:ss # Used by graph and other places where we only show small intervals interval_second = HH:mm:ss interval_minute = HH:mm interval_hour = DD/MM HH:mm interval_day = DD/MM interval_month = MM-YYYY interval_year = YYYY
default_timezone = Europe/Zurich
Telegraf installieren
Telegraf wird benutzt um die Modbus-Daten abzufragen und nach influxdb zu senden.
wget -qO- https://repos.influxdata.com/influxdb.key | sudo apt-key add -
source /etc/lsb-release / ODER source /etc/armbian-release
echo "deb https://repos.influxdata.com/${DISTRIB_ID,,} ${DISTRIB_CODENAME} stable" | sudo tee /etc/apt/sources.list.d/influxdb.list
sudo apt-get update && sudo apt-get install telegraf sudo service telegraf start
Damit läuft telegraf zum aktuellen Zeitpunkt mit Version 1.20.0. Diese Version scheint mit den Versionen von Grafana und Influxdb sehr gut zu funktionieren (nach rund 2 Monaten Test). Ich halte deswegen auch hier an dieser Version fest:
sudo apt-mark hold telegraf
Influxdb als output plugin konfigurieren
DB und User auf influxdb erstellen
influx -username 'admin' -password '<password>'
CREATE DATABASE "telegraf" CREATE USER "telegraf" WITH PASSWORD "<userpassword>" GRANT ALL ON "telegraf" TO "telegraf"
Konfig anpassen
sudo vi /etc/telegraf/telegraf.conf
[[outputs.influxdb]] urls = ["http://127.0.0.1:8086"] #influxdb und telegraf laufen auf dem selben server database = "telegraf" ## HTTP Basic Auth username = "telegraf" password = "<password>"
Modbus als input plugin konfigurieren
sudo vi /etc/telegraf/telegraf.conf
Alle input Plugins (CPU, etc.) deaktivieren. Anschliessend Modubs konfigrieren:
[[inputs.modbus]]
name = "SE_PowerTagLink_F21"
slave_id = 150
timeout = "5s"
controller = "tcp://<ip>:502"
holding_registers = [
{ name = "PowerTag_Garage - Current C", byte_order = "ABCD", data_type = "FLOAT32-IEEE", scale=1.0, address = [3003,3004]}
]
[[inputs.modbus]]
name = "SE_PowerTagLink_Hauszuleitung"
slave_id = 154
timeout = "5s"
controller = "tcp://<ip>:502"
holding_registers = [
{ name = "PowerTag_Hauszuleitung - Current A", byte_order = "ABCD", data_type = "FLOAT32-IEEE", scale=1.0, address = [2999,3000]},
{ name = "PowerTag_Hauszuleitung - Current B", byte_order = "ABCD", data_type = "FLOAT32-IEEE", scale=1.0, address = [3001,3002]},
{ name = "PowerTag_Hauszuleitung - Current C", byte_order = "ABCD", data_type = "FLOAT32-IEEE", scale=1.0, address = [3003,3004]},
{ name = "PowerTag_Hauszuleitung - Voltage A-N", byte_order = "ABCD", data_type = "FLOAT32-IEEE", scale=1.0, address = [3027,3028]},
{ name = "PowerTag_Hauszuleitung - Voltage B-N", byte_order = "ABCD", data_type = "FLOAT32-IEEE", scale=1.0, address = [3029,3030]},
{ name = "PowerTag_Hauszuleitung - Voltage C-N", byte_order = "ABCD", data_type = "FLOAT32-IEEE", scale=1.0, address = [3031,3032]},
{ name = "PowerTag_Hauszuleitung - Voltage A-B", byte_order = "ABCD", data_type = "FLOAT32-IEEE", scale=1.0, address = [3019,3020]},
{ name = "PowerTag_Hauszuleitung - Voltage B-C", byte_order = "ABCD", data_type = "FLOAT32-IEEE", scale=1.0, address = [3021,3022]},
{ name = "PowerTag_Hauszuleitung - Voltage C-A", byte_order = "ABCD", data_type = "FLOAT32-IEEE", scale=1.0, address = [3023,3024]},
{ name = "PowerTag_Hauszuleitung - Active Power", byte_order = "ABCD", data_type = "FLOAT32-IEEE", scale=1.0, address = [3059,3060]},
{ name = "PowerTag_Hauszuleitung - Power Factor", byte_order = "ABCD", data_type = "FLOAT32-IEEE", scale=1.0, address = [3083,3084]},
{ name = "PowerTag_Hauszuleitung - Active Energy No reset", byte_order = "ABCDEFGH", data_type = "INT64", scale=1.0, address = [3203,3204,3205,3206]},
{ name = "PowerTag_Hauszuleitung - Active Energy Resetable", byte_order = "ABCDEFGH", data_type = "INT64", scale=1.0, address = [3255,3256,3257,3258]},
{ name = "PowerTag_Hauszuleitung - Active Energy Write Value", byte_order = "ABCDEFGH", data_type = "INT64", scale=1.0, address = [3259,3260,3261,3262]}
]
Chronograf installieren
Chronograf eignet sich als Query-GUI auf die Influxdb und bietet GUI Unterstützung beim erstellen von InfluxQL und Flux Queries
sudo apt-get install chronograf
Anschliessend Browser URL von chronograf öffnen
http://grafana.home.arpa:8888/
Commands
Zeige influxdb version
influxd version
Login
influx -username <username> -password <password>
Benutzer anzeigen
show users
Zeige alle DBs
show databases
Zeitserie löschen (Beispiel)
DROP SERIES FROM "rawdata" WHERE "name" = 'XTH_U01-01 humidity'
Links
- https://community.influxdata.com/t/regular-issues-compacting-tsi-files-very-high-load-cannot-allocate-memory/22206
- https://github.com/influxdata/influxdb/pull/12362#issuecomment-953126323
- https://www.jeremymorgan.com/tutorials/raspberry-pi/install-go-raspberry-pi/

