Donnerstag, 18. Juli 2019

Infos zur Installation von Modulen und Paketen


  • Was ist auf meinem System in der Vergangenheit installiert worden?
  • Ist ein bestimmtes Modul oder Paket schon installiert?
  • Welches Debian Paket brauch ich für ein bestimmtes Perl Modul?


Ich habe etwas herum experimentiert und dabei sind ein paar Einzeiler für die Beantwortung dieser Fragen entstanden.

Historie

Die erste Frage kann man relativ leicht beantworten, das apt System loggt nämlich alle apt-get Vorgänge sogar mit der eingegeben Kommandozeile mit.
cat /var/log/apt/history.log|grep Commandline
Besser zuordnen lässt sich das noch in der Art.
cat /var/log/apt/history.log|grep -A1 Start-Date
Beide Zeilen ergeben keine Ausgabe? Das gesuchte ist nicht dabei? Die Installation liegt schon zu lange zurück! Die Logs werden mit Log Rotate archiviert. Auch dieses Archive kann man komplett, zeitlich richtig sortiert, anzeigen/durchsuchen.
zcat $(ls -tr /var/log/apt/history.log.*.gz)|grep -A1 Start-Date

Man hat Perl Module per CPAN installiert?
Wenn man das debian Paket perl-doc installiert hat (oder noch installiert) kann man mit diesem Mammut-Einzeiler eine List der mit cpan installierten Module ausgeben (Quelle):
for M in `perldoc -t perllocal|grep Module |sed -e 's/^.*" //'`; do V=`perldoc -t perllocal|awk "/$M/{y=1;next}y" |grep VERSION |head -n 1`; printf "%30s %s\n" "$M" "$V"; done |sort

Installierte Modul und Pakete finden und listen

Wie man ermitteln kann ob ein bestimmtes Perl Modul oder debian Paket schon installiert ist habe ich hier schon mal gezeigt. Die beiden folgende Zeile liefern jeweils ein Liste aller installierter Pakete, entweder zeilenweise oder eine Zeile mit Leerzeichen getrennt. Der wichtige Schlüssel in dieser Zeile ist der String "^ii", mit diesem oder vielleicht einfacher einem weiteren grep 'suchstring' kann man die Rückgabe wesentlich beeinflussen. Beide Listentypen eignen sich für die weitere Verarbeitung.
dpkg -l |grep ^ii| awk '{ print $2 }'
dpkg -l |grep ^ii| awk '{ print $2 }'|tr -d "\r"|tr "\n" " "
Will man wissen ob ein bestimmtes Perl Modul installiert ist, kann man das einfach herausfinden. Man kann aber auch herausfinden ob und durch welches debian Paket es installiert wurde. Die zweite Version sucht nur in Paketen die -perl im Namen tragen und läuft damit wesentlich schneller.
s='Device::SerialPort'
perl -M$s -e '' 2>/dev/null &&echo "Modul $s ist vorhanden"
for i in $(dpkg -l |grep ^ii| awk '{ print $2 }'|tr -d "\r"|tr "\n" " ");do if dpkg -L $i|grep $s &> /dev/null;then echo $i enthält $s;fi;done
for i in $(dpkg -l |grep ^ii|grep '\-perl'| awk '{ print $2 }'|tr -d "\r"|tr "\n" " ");do if dpkg -L $i|grep $s &> /dev/null;then echo $i enthält $s;fi;done

Debian Pakete anhand von Perl Modulnamen finden

Es gibt gute Gründe die Installation von Perl Modulen über debian Pakete der Installation über cpan zu bevorzugen. Für mich zählt die Updatefähigkeit und die Geschwindigkeit. Man kann im Internet nach den Paketen suchen, man kann aber auch einfach die Verfügbarkeit für das lokale System testen. Dazu braucht man das Tool apt-file, welches man zuerst installieren muss. Der letzte Befehl lädt den Infocache lokal und dauert etwas.
sudo apt-get update
sudo apt-get install apt-file
sudo apt-file update
Für die folgende Suche, nutze ich den Umstand, dass in der im Paket enthaltenen Liste der Dateien auch die Doku in der Form "/usr/share/man/man3/IO::File.3perl.gz" enthalten ist. Ich ergänze also den Modulstring um "/" + "." und suche exakt danach. Da die Suche ziemlich zeitaufwendig ist, kann man auch nach mehreren Modulen in einem Vorgang suchen lassen. Der search Befehl akzeptiert mehrere Modulnamen durch Zeilenumbruch getrennt. In meinem Beispiel sind die Modulnamen in einem String durch Leerzeichen getrennt, die Trennung wird in Zeilenumbruch geändert, jede Zeile ergänzt und über stdin an den search Befehl von apt-file übergeben. Die Option -l bewirkt das nur die gefunden Pakete gelistet werden, werden mehrere der abgefragten Modulnamen in einem Paket gefunden, wird es nur einmal gelistet!
s="IO::File Digest::MD5"
echo $s|tr " " "\n"|sed 's/$/./;s/^/\//'|apt-file search -l -f -

Die Config analysieren

Mit Hilfe des Installermoduls, kann man auch eine bestehende Configdatei untersuchen und fehlende Pakete nachinstallieren. 
Voraussetzung: das neue FHEM System.
Mit einem Zusatzmodul, einer Definition sowi ein paar Zeilen Scriptcode kann man so testen ob alle Vorrausetzungen installiert sind bzw. die fehlenden Pakete installieren.
Danach backup zurückspielen und fertig. 
# System mit Suchmaschinen und Hilfsscript aufrüsten
sudo apt install apt-file libperl-prereqscanner-notquitelite-perl
sudo apt-file update
wget -O fhemcl.sh https://raw.githubusercontent.com/heinz-otto/fhemcl/master/fhemcl.sh
chmod +x fhemcl.sh

# Definition zum Testen erstellen
cat <<EOF | ./fhemcl.sh 8083
attr initialUsbCheck disable 1
define installer installer
attr installer installerMode developer
save
EOF

# Zu prüfende config Datei holen
scp pi@raspib3:/opt/fhem/fhem.cfg .
ref='/home/pi/fhem.cfg'

# Abfrage starten
s=$(./fhemcl.sh 8083 "get installer checkPrereqs $ref"|grep -oE 'installPerl.*&fwcsrf'|grep -oE '\s[a-z,A-Z,:]+\s')
packages=$(echo $s|tr " " "\n"|sed 's/$/./;s/^/\//'|apt-file search -l -f -)
echo 'debian Pakete fehlen:'
echo $packages
echo 'sudo apt install $packages' 

Gibt es noch mehr?
Oh ja, nodejs Pakete oder auch python.
Mit npm kann man so die "global" installierten Pakete listen lassen:
npm list -g --depth 0
Python ist ja Bestandteil des debian System, verwendet man zusätzliche Pakete hat man meist pip (python-pip) installiert. Python gibt es auch in der Version 3 (python3) dafür gibt es natürlich separat pip3 (python3-pip). Mit der Option -l verringert sich die Liste auf das, was man selbst installiert hat.
pip list -l
Und man kann auch schauen ob sich was neues findet.
pip list -l --outdated

Dienstag, 9. Juli 2019

Neues Linux System - Nacharbeit

Generell ist es relativ einfach eine bestehende FHEM Installation auf ein neues Betriebssystem/System zu setzen:
  1. Backup FHEM
  2. Kopie der aktuellen Backupdatei -> Server | USB Stick | per scp lokal
  3. sudo halt
  4. neue SD Card mit aktuellem Image (ich behalte immer die alte SD erstmal in Reserve)
  5. setupBasic, setupFhem, testen
  6. Backupdatei verfügbar machen -> Server | USB Stick mounten | per scp - lokal -> nach /home/pi
  7. stop fhem
  8. restore des Backups
  9. start fhem

Sicherung / Backup

Bei mir ist beim obigen Plan mindestens die Anbindung an Dateiserver und die ssh Verbindung auf der Strecke geblieben. Schritt 1 und 8 muss man dafür noch etwas ausbauen.

Sicherung ssh Umgebung

Die notwendigen Dateien befinden sich in diesen Verzeichnissen:
  • /etc/ssh für den ssh Host / Server
  • /opt/fhem/.ssh für den User fhem
  • /home/pi/.ssh für den User pi. 
Ich werde zwei zusätzliche Dateien in den Backup Ordner von FHEM erstellen. Dies könnte man auch von FHEM von Zeit zu Zeit machen lassen. Neben der Datei für eine Historie mit Zeitstempel erzeuge ich noch eine ohne Zeitstempel. Damit muss man bei der Wiederherstellung nicht lang suchen.
Man kann dieses als Script auch unter FHEM ausführen, da aber Systemdateien gesichert werden, muss tar als sudo ausgeführt werden. Damit das funktioniert, muss die zuständige Datei um /bin/tar ergänzt werden.
datei=/opt/fhem/backup/ssh$(date +%Y%m%d_%H%M%S).tar.gz
sudo tar -czf $datei /etc/ssh /opt/fhem/.ssh /home/pi/.ssh
sudo cp $datei /opt/fhem/backup/ssh.tar.gz
Falls der User fhem gar kein ssh verwendet kommt ein Fehler, dann muss man die Befehle abwandeln. Da die Dateien nicht voluminös sind, kann man auf zip verzichten. Damit kann das tar Archiv leichter mit der Option -rf ergänzt werden.
sudo tar -cf $datei /etc/ssh /home/pi/.ssh
cp $datei /opt/fhem/backup/ssh.tar
Der folgende Zweizeiler wirft zwar Fehler, sichert aber die ssh Dateien für alle existierenden User.
datei=ssh$(date +%Y%m%d_%H%M%S).tar
sudo tar rf $datei /etc/ssh $(awk -F: '$3>998{print $6"/.ssh"}' /etc/passwd)
Will man einfach in FHEM die ssh Key für user fhem sichern kann man das auch dort machen: 
"datei=./backup/sshFhem$(date +%Y%m%d_%H%M%S).tar;; tar -cf $datei ./.ssh"
Und auch später wiederherstellen:
"datei=./backup/sshFhem*.tar;; tar -xf $datei ./.ssh"

Sicherung Dateiserver Umgebung

datei=/opt/fhem/backup/fsconf$(date +%Y%m%d_%H%M%S).tar.gz
sudo tar -czf $datei /etc/fstab /usr/.*credentials /etc/davfs2/secrets
cp $datei /opt/fhem/backup/fsconf.tar.gz
Hat man Scripte o.ä. zusätzlich in anderen Pfaden, kann man die natürlich einfach in dem tar Befehl ergänzen und gleich mit sichern oder eine weitere Datei nach gleichem Schema erzeugen.

Finale Sicherung des alten Systems

Damit man den finalen Status im FHEM System behält, muss man FHEM beenden und dann ein backup durchführen!
systemctl stop fhem
datei=/opt/fhem/backup/FHEM-$(date +%Y%m%d_%H%M%S).tar.gz
tar -czf $datei -C /opt/fhem --exclude ./backup ./
Wenn das Backup zu Ende ist, startet man beispielsweise das Script /opt/fhem/backupFhem.sh und kopiert alle aktuellen Dateien damit auf den Sicherungsserver.
Am Ende des Artikels habe ich noch den Hinweis auf Alternativen zum Server.

Wiederherstellung

Nachdem das neue System grundlegend installiert und getestet ist (Ergänzung Schritt 5. optional: setupDavfs) wird die Sicherung zurückgespielt.
Die Verbindung zu meinem Windows Server geht relativ simpel. Ohne Angabe des Usernamens wird der momentane User (root) verwendet. Ohne Angabe des Passwortes wird es abgefragt:
sudo su
mount -t cifs //ServerName/Freigabe /mnt
mount -t cifs -o username=UserName //ServerName/Freigabe /mnt
mount -t cifs -o username=UserName,password=Passwort //ServerName/Freigabe /mnt
Ist das Laufwerk verbunden, kann auch ohne lokale Kopie sofort mit der Wiederherstellung begonnen werden.
datei=/mnt/fhem/$(hostname)/backup/FHEM-$(date +%Y%m%d_%H%M%S).tar.gz
tar -xzf $datei -C /opt/fhem
Querverweis: Falls die Module im alten System nicht gut dokumentiert waren, hilft eventuell dieser Beitrag.

Wiederherstellung ssh

Bei meinen Systemen wurde immer nur der ecsda Key verwendet. Ich möchte nicht die neue ssh Server Gesamtkonfiguration zerstören (da ändert sich immer mal was, ich habe nicht untersucht was genau) sondern nur das wiederherstellen was gebraucht wird. Unter der Annahme: es gibt nur eine aktuelle Datei im Verzeichnis, wird damit der ecdsa Key in /etc/ssh wieder hergestellt:
datei=/mnt/fhem/$(hostname)/backup/ssh.tar.gz
tar -xzf $datei -C / --wildcards etc/ssh/ssh_host_ecdsa_*
Um die User .ssh Verzeichnisse wieder herzustellen, sollte dieser Befehl gut sein
tar -xzf $datei -C / home/pi/.ssh/ opt/fhem/.ssh/
Damit steht die ssh Umgebung wieder.

Wiederherstellung Verbindungen zum Dateiserver

Die für die Verbindung verantwortlichen Scripte sollten im /opt/fhem Verzeichnis liegen und sind damit schon Teile der Wiederherstellung. Die Datei /etc/fstab und die jeweiligen Credential Dateien liegen aber unter Umständen "verstreut" im System und sind jetzt entweder nicht vorhanden oder neu gemacht.
Zunächst die credential Datei(en) in /usr/
datei=/mnt/fhem/$(hostname)/backup/fsconf.tar.gz
tar -xzf $datei -C / --wildcards usr/.*credentials
Die davfs2/secrets will ich nur ergänzen, davfs muss schon installiert sein!
tar -xzf $datei etc/davfs2/secrets -O|grep magentacloud >> /etc/davfs2/secrets
Ich möchte gern die fstab nicht überbügeln sondern die neue Datei einfach um meine Einträge ergänzen. Existieren z.B. mehrere Mountpoints in /media/ - kann das in einer Zeile erledigt werden:
tar -xzf $datei etc/fstab -O|grep /media/ >> /etc/fstab
Jetzt müssen noch die Mountpoint erzeugt werden:
mkdir $(tar -xzf $datei etc/fstab -O|grep -o '/media/[a-Z,0-9]*'|tr '\n' ' ')

Jetzt kann man das Sicherungslaufwerk wieder trennen.
umount /mnt
Die Verbindung zu davfs2 erfordert auch noch die Gruppenmitgliedschaft in der Gruppe davfs2
usermod -aG davfs2 fhem
Die Gruppenmitgliedschaft greift erst nach erneutem Login! Also mindestens FHEM neu starten!

Alternativen zum Sicherungsserver

USB Stick
Man könnte einen USB Stick verwenden, der Raspberry Pi 3 verkraftet das Stecken im laufenden Betrieb. Bei allen anderen Typen und "zur Vorsicht" ist aber vom Stecken eines USB Sticks im laufenden Betrieb abzuraten. Zuerst schauen welches Device der Stick geworden ist und dann einfach temporär mounten:
lsblk
mount /dev/sda1 /mnt

SCP - lokale Kopie
Mit scp ist es recht simpel sich eine Kopie der Dateien lokal zum holen und diese später zurück zu spielen. Geht auch unter Windows 10 ab 1809 einfach so!
scp pi@hostname:dateiname .
scp dateiname pi@hostname:
Die Restore Befehle muss man natürlich etwas abwandeln, entweder die Variable $datei wird einfach auf die lokale Datei Homedir von pi gesetzt, oder im tar Befehl die Datei direkt angeben.

Installation nodejs, pm2 und pip

Die Installation von nodejs hatte ich ja hier schon erläutert.
Zusätzlich brauche ich "global" noch den Nodejs Prozessmanager pm2.
sudo su
curl -sL https://deb.nodesource.com/setup_10.x | bash -
apt-get install nodejs
npm install pm2 -g
Trotz der Sicherung des gesamten Ordners installiere ich Landroid neu. Wie so oft gibt es mittlerweile neue Versionen.

Python Pakete werden mit Hilfe von pip installiert. Beispiel: die fhem API
apt-get install python-pip
pip install fhem


ToDo
Andere Applikationen unterhalb von /opt sichern

codebox

Freitag, 14. Juni 2019

Rockrobo - root und gut?

Es ist einige Zeit vergangen und ich habe im Mai 2021 den Artikel leicht überarbeitet.

Der Staubsauger ist in der Cloud und mein Typ Xiaomi Mi Robot Vacuum (rockrobo.vacuum.v1) wird auch noch von höchster Instanz (CCC) genau analysiert!
Was bedeutet es einen Staubsauger mit Root Zugriff zu haben?!
Markus hat gesagt: Es ist nur der ssh Zugriff - und irgendwann geht es vielleicht nicht mehr.
WLAN Zugang ändern und danach den Token neu auslesen - ist mit dem normalen Gerät ein Graus, aber mit ssh Zugang ganz einfach!?
Tobias hat mir mit seinem Beitrag die Hemmschwelle genommen - also los und Test!
Wie so oft: Meine Beschreibung wird auch irgendwann nicht mehr aktuell sein. 
Die Grundlage steht hier https://github.com/dgiese/dustcloud

Stand Mai 2021 - gibt es einige weitere Entwicklungen und als aktuelle Quelle kann dieser Link dienen:
Das mirobo Tool gibt es auch für Windows, ich habe ursprünglich die Linux Version verwendet.
Ich habe auch Valetudo getestet und in diesem Artikel beschrieben.

Mittwoch, 8. Mai 2019

Worx Landroid m500

Ich habe mir nach kurzer Überlegung und Klärung der Unterstützung in FHEM einen Mähroboter zugelegt. Nachdem ich die Installation und Einbindung in FHEM geschafft habe, will ich die mal hier festhalten. Als Grundlage gibt es einen kurzen Wikibeitrag. Dort sind zumindest mal die wichtigsten Links abgelegt. Ich habe die Installation etwas nach meinem Geschmack modifiziert, die Grundlage bildet aber diese Anleitung https://github.com/axelmohnen/fhem-landroid-s
Man sollte sich immer erst auf dieser Seite davon überzeugen, ob es Änderungen gibt!

Anmerkung: Im Herbst 2019 gab es mehrere Änderungen, sowohl im iobroker Modul als auch Modul LandroidSrv.js. Stand April 2020 habe ich die Beschreibung der Neuinstallation angepasst.

Die Voraussetzungen:
  • Cloudzugang eingerichtet und Mäher registriert. App funktioniert!
  • Installation Node.js, dieses Setup habe ich schon in einem extra Artikel beschrieben.

Setup Schritt für Schritt

Man sollte die Zeilen Schritt für Schritt ausführen und nicht einfach den Block als Script übernehmen.
sudo apt-get install libjson-pp-perl
sudo mkdir -p /opt/landroid/fhem-landroid-s
sudo chown -R pi /opt/landroid
sudo chmod -R 777 /opt/landroid
cd /opt/landroid/fhem-landroid-s
# Ich verzichte auf git und lade die beiden Datei einfach herunter
wget -O LandroidConf.json https://raw.githubusercontent.com/axelmohnen/fhem-landroid-s/master/LandroidConf.json
wget -O LandroidSrv.js https://raw.githubusercontent.com/axelmohnen/fhem-landroid-s/master/LandroidSrv.js
# bei der folgenden Installation gibt es ein paar Warnmeldungen, offenbar ohne Auswirkung
sudo npm install iobroker.worx
sudo npm install pm2 -g
# Nur in der alten Version: Ich korrigiere einen aktuellen kleinen Schönheitsfehler fürs Logging
# sed -i -e 's/self.mqtt)/self.mqtt_endpoint)/' node_modules/iobroker.landroid-s/lib/mqttCloud.js
# Jetzt den Cloudzugang eintragen und mit ctrl+o speichern und mit ctrl+x schließen
nano LandroidConf.json
Wenn man alles richtig gemacht hat, kann man jetzt schon mal auf zwei Arten testen:
node /opt/landroid/fhem-landroid-s/LandroidSrv.js mower1
# im Browser kann man sich den aktuellen Datensatz anzeigen lassen
http://ip-adresse-landroidsrv:8001/getMessage
Die Logausgaben sind selbsterklärend. Mit ctrl+c kann man den Testlauf abbrechen.

Automatischer Start

Auch mit der Node Prozess Steuerung kann man die Funktion testen
pm2 start /opt/landroid/fhem-landroid-s/LandroidSrv.js -f -- mower1
pm2 monit                           # zeigt Status
pm2 list                            # zeigt Prozesse
pm2 logs LandroidSrv [--lines 1000] # zeigt das Log
Sieht alles gut aus, kann man jetzt den Autostart aktivieren.
Diese Einrichtung war mir zunächst etwas schleierhaft. Aber - pm2 redet mit einem, und man muss genau lesen was er sagt.
Durch Eingabe von pm2 startup erhält man nach einer Analyse des Systems eine Zeile die man selbst noch einmal kopieren und in der Eingabezeile ausführen muss.
pm2 startup
[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u pi --hp /home/pi
Hat man die Zeile ausgeführt muss man die pm2 Konfiguration noch speichern.
pm2 save
Nach einem Neustart des Servers kann man sich davon überzeugen ob alles geklappt hat.
Achtung!
Ich habe mich mehrfach aus der AWS Cloud ausgesperrt! Offenbar ist es mir unbewusst gelungen, den LandroidSrv mehrfach zu starten und dies auch in pm2 zu verankern. Hast Du nicht gesehen, lief er 1x unter User pi und 2x unter User root. Wie ich das geschafft habe und was da genau abgeht weiß ich noch nicht. Mit ps
ps -aux|grep pm2
kann man schauen wie oft der Prozess läuft. Weiter unten habe ich geschrieben wie man alles wieder löschen kann.
pm2 legt für den angemeldeten User jeweils Prozesse an! Also nicht einmal als sudo und einmal als pi einrichten (hatte ich offenbar gemacht).

Setup FHEM

Zunächst brauchen wir das (derzeit nicht offizielle) Modul. Das laden wir direkt von GitHub an Ort und Stelle. Das notwendige Perl Modul haben wir oben als ersten Schritt schon installiert. Der Code ist entweder Zeilenweise für die FHEM Kommandozeile oder komplett für die Raw Definition.
"wget -nv -O FHEM/74_LANDROID.pm https://raw.githubusercontent.com/axelmohnen/fhem-landroid-s/master/74_LANDROID.pm"
reload 74_LANDROID.pm
define robbi LANDROID localhost
attr robbi event-on-change-reading .*
define FileLog_robbi FileLog ./log/robbi-%Y.log robbi
attr FileLog_robbi logtype text
Die ersten Reading sollten nach 180 sec erscheinen.

Noch Dies und Das

Zunächst die Installation aus der Readme vom GitHub in kurzer Zusammenfassung
sudo apt-get install git
cd /opt
sudo mkdir landroid
sudo chown pi landroid
sudo chmod 777 landroid
cd landroid
git clone https://github.com/axelmohnen/fhem-landroid-s.git
cd fhem-landroid-s
sudo npm install iobroker.worx
# bei der Installation gibt es ein paar Warnungen und eine
# npm WARN saveError ENOENT: no such file or directory, open '/opt/landroid/fhem-landroid-s/package.json'
# npm notice created a lockfile as package-lock.json. You should commit this file.
# Jetzt account eintragen
nano LandroidConf.json
#Teststart
node LandroidSrv.js mower1

Fehler beim Start

Wenn man sich im Argument vertippt hat (mover statt mower) kommt dieser Fehler
/opt/landroid/fhem-landroid-s/node_modules/iobroker.landroid-s/lib/mqttCloud.js:24
    this.email = adapter.config.email;
                                ^

TypeError: Cannot read property 'email' of undefined
    at new mqttCloud (/opt/landroid/fhem-landroid-s/node_modules/iobroker.landroid-s/lib/mqttCloud.js:24:33)
    at main (/opt/landroid/fhem-landroid-s/LandroidSrv.js:420:14)
    at Object. (/opt/landroid/fhem-landroid-s/LandroidSrv.js:458:3)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)
    at startup (internal/bootstrap/node.js:283:19)
Ich hatte einen hartnäckigen Fehler, weil mich die Amazon Cloud offenbar gesperrt hatte (ich hatte durch einen Fehler eine Art Attacke gefahren). Abhilfe war: DSL neu verbinden.
undefined:1
<html>
^

SyntaxError: Unexpected token < in JSON at position 0
    at JSON.parse (<anonymous>)
    at IncomingMessage.<anonymous> (/opt/landroid/fhem-landroid-s/node_modules/iobroker.landroid-s/lib/mqttCloud.js:275:21)
    at IncomingMessage.emit (events.js:194:15)
    at endReadableNT (_stream_readable.js:1125:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)

Alles löschen

Der Abschnitt ist ein bisschen unsortiert. So einfach war ein Update bzw. Entfernen der Software nicht. Der iobroker.landroid-s / iobroker.worx wird unterhalb des aktuellen Pfades bei der Installation unter node_modules abgelegt.
Will man nur den Versuch mit pm2 beenden.
pm2 stop /opt/landroid/fhem-landroid-s/LandroidSrv.js
pm2 delete /opt/landroid/fhem-landroid-s/LandroidSrv.js
Wenn man alles wieder loswerden will:
pm2 unstartup
#alte Version
sudo npm uninstall iobroker.landroid-s
#neue Version
sudo npm uninstall iobroker.worx
#Nur Alte Version löschen
sudo rm -R node_modules/
sudo rm package-lock.json
#Alles löschen
cd /opt
sudo rm -R landroid/
#Auch nodejs löschen
sudo pm2 kill
sudo npm remove pm2 -g
sudo apt-get remove nodejs

Dienstag, 7. Mai 2019

Windows von FHEM über ssh steuern

Windows OpenSSH Server installieren

Als ersten Schritt sollte man zunächst unabhängig von der Windows Version prüfen ob ein entsprechender Dienst schon läuft oder existiert:
Get-Service -Name *ssh*

Windows 10 + Server 2019

In den aktuellen Windows Versionen (ab dem Jahr 2019) ist der OpenSSH Server enthalten und kann einfach installiert werden.
Get-WindowsCapability -Online -Name OpenSSH.Server* | Add-WindowsCapability -Online
Get-Service -Name sshd | Set-Service -StartupType Automatic
Get-Service -Name sshd | Start-Service

Windows Server 2016, 2012 R2 und 2012

In früheren Windows Versionen kann der OpenSSH Server nur über ein extra download/Setup installiert werden.
Als Voraussetzung für die Installation muss die Ausführung von Powershellscripten erlaubt sein.
Set-Executionpolicy Remotesigned
Ich habe für die Installation ein komplettes Script auf GitHub  zur Verfügung gestellt.
Man kann es einfach herunterladen und starten.
Ergänzung 2021:  TLS1 kann nicht mehr verwendet werden, es kommt unter Umständen zur Fehlermeldung. Hier habe ich Abhilfe gefunden und eine zusätzliche Zeile eingebaut. Eventuell schafft ein .net Update Abhilfe.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]'Tls11,Tls12'
invoke-webrequest https://raw.githubusercontent.com/heinz-otto/Powershell/master/InstallLatestSshd64.ps1 -OutFile InstallLatestSshd64.ps1
.\InstallLatestSshd64.ps1
Das Script überprüft die Windows Server Version und installiert ein fehlendes
Windows Management Framework 5.1 (dann ist zwischendurch ein Reboot erforderlich). Es wird die aktuellste sshd Version heruntergeladen und die Anmeldung für die Administratoren Gruppe freigeschaltet.
Um bei dieser Installationsart anschließend die Programme wie ssh oder ssh-keygen einfach verwenden zu können, kann der Pfad erweitert werden. Hier die Powershell und die cmd Variante für die aktuelle Sitzung:
$Env:Path += "C:\Program Files\OpenSSH-Win64\;"
set PATH=C:\Program Files\OpenSSH-Win64\;%PATH%
Die Verwendung von Parametern in der Powershell kann fehlerhaft sein. Im Zweifel die CMD verwenden!
Das CMD Fenster unter Windows Server 2012 liefert für ssh nicht das richtige Terminal (conpty), eine interaktive Arbeit ist damit nicht wirklich möglich. Scripte können aber abgearbeitet werden.

Anmeldung am Windows OpenSSH Server

Man kann sich wie gewohnt von jedem System (Windows 10 Version 1803 hat den ssh Client aktiv) mit ssh user@host am SSH Server anmelden!
Der ssh Server akzeptiert nur den "Kurznamen". Windows kürzt den Anmeldenamen ein (z.B. bei einem Onlinekonto).
Man kann den Namen leicht in der Powershell Konsole ermitteln:
whoami

SSH Zugang mit Public Key einrichten

Achtung: Auch in Windows darf die Datei %USERPROFILE%\.ssh\authorized_keys nicht für jedermann zugreifbar sein. Nur DER Benutzer (Eigentümer), Administratoren und System darf Zugriff haben, sonst wird der Public Key abgelehnt!
Bitte den Hinweis am Ende des Artikels für die Gruppe der Administratoren beachten!
Bitte alle Schritte (Befehlszeilen) einzeln kopieren und ausführen!

Problem: Bei Windows als SSH Server versagt leider das Tool ssh-copy-id. Hier drei Szenarien für die Einrichtung des ssh Zuganges mit public key zu einem Windows Server.

Voraussetzung: Benutzer hat schon einen RSA Key. Wenn nicht muss er vorher erzeugt werden!
(ssh-keygen -f ~/.ssh/id_rsa -P "" -t rsa oder ssh-keygen -f %USERPROFILE%\.ssh/id_rsa -P "" -t rsa)

Linux Shell
ziel=user@host
pkey=$(cat ~/.ssh/id_rsa.pub)
ssh $ziel "findstr /c:\"$pkey\" .ssh\authorized_keys ||mkdir .ssh ||echo $pkey >>.ssh\authorized_keys"
Windows CMD
set ziel=user@host
set /p pkey=< %userprofile%\.ssh\id_rsa.pub
ssh %ziel% "findstr /c:""%pkey%"" .ssh\authorized_keys ||mkdir .ssh ||echo %pkey% >>.ssh\authorized_keys"
Windows Powershell
$ziel='user@host'
$pkey = $(type $env:userprofile\.ssh\id_rsa.pub)
ssh $ziel "findstr /c:`"`"$pkey`"`" .ssh\authorized_keys ||mkdir .ssh ||echo $pkey >>.ssh\authorized_keys"

Hinweis: Die Befehle nach ssh werden in der CMD von Windows abgearbeitet! Der Public Key wird direkt durch Variablen "Auflösung" mitgegeben. Der Trenner || ist eine bedingte Abarbeitung der folgenden Befehle. 

Ersteinrichtung
Alle Schritte in Kurzform für den Public Key Zugang für den User fhem zu einem Windows SSH-Remotesystem habe ich hier ausführlich gezeigt.

Nur mit Public Key
Man kann den Zugang sehr sicher machen und nur public key zulassen. Dazu muss man die Passwort Authentisierung abschalten indem in der Datei C:\ProgramData\ssh\sshd_config diese Zeile eingefügt wird:
PasswordAuthentication no
Hinweis: Die Config Datei enthält alle Optionen mit ihren Standardwerten als Kommentarzeilen. Jede Änderung in der Datei muss durch einen restart des sshd Services aktiviert werden.

Powershellscript von FHEM aus starten

Bei der Ausführung von Befehlen vom Linux System aus muss man beachten, dass der Backslash verdoppelt (geschützt) werden muss. Ansonsten kann man wie gewohnt Befehle absetzen und sogar Powershell Scripts mit Argumenten ausführen.
"ssh user\@host 'powershell C:\\Tools\\Scripts\\TestPsFhem.ps1' 'http://host:8083' 'DummyName'"
Oder auch mittels powershell cmdlets direkt starten
"ssh user\@host powershell -command stop-vm vmName"
{qx 'ssh user@host powershell -command get-service' }

Innerhalb von Powershell kann man auch mit einem Powershellscript über HTTP auf FHEM zugreifen.
Powershellbeispiel:
Fragt einen Dienst ab und schreibt Status und Displayname nach FHEM zurück in einen Dummy
<#
.SYNOPSIS
    This Script is for testing the FHEM Client for HTTP
.DESCRIPTION
    Give FHEM Server url and Dummy 
.NOTES
    Will give a State and Displayname of Service back
#>
#region Params
param(
    [Parameter(Mandatory=$true,Position=0,HelpMessage="-first 'Portnumber or URL'")]
    [String]$first,
    [Parameter(ValueFromPipeline=$true,ValueFromRemainingArguments=$true)]
    [String[]]$sec
)
#endregion 
$serv="wuauserv"

if (!(Test-Path .\fhemcl.ps1)) {
    Write-Output "fhemcl.ps1 fehlt"
    invoke-webrequest "https://raw.githubusercontent.com/heinz-otto/fhemcl/master/fhemcl.ps1" -OutFile "fhemcl.ps1"
}

$state=get-service $serv
.\fhemcl.ps1 $first "set $sec $($state.status)"
.\fhemcl.ps1 $first "setreading $sec Displayname $($state.DisplayName)"


Eigenheiten für Administratoren in einigen Windows Versionen?

Symptom:
Ein Mitglied der Gruppe administrators kann offenbar keine Anmeldung mit Public Key machen. Obwohl alles eingerichtet ist, wird das Passwort abgefragt. 
Das trifft zu für Windows Server Version 2012 und Windows 10 ab Version 2004.
Bei Windows Server 2012 R2, 2016 und 2019 war es bisher nicht so.

Neue Erkenntnis: Ist eventuell so gewollt und teilweise fehlerhaft implementiert: Link.

Eine Lösung:
Ich habe mir die Sache näher angeschaut und ich habe bei einigen Installationen Unterschiede in der aktiven sshd Konfigurationsdatei C:\ProgramData\ssh\sshd_config gefunden.
Kommentiert man dort am Ende der Datei den folgenden Eintrag mit einem # aus,
Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
funktioniert auch die Anmeldung für Mitglieder der Administratoren. Der Dienst ssd (OpenSSH SSH Server) muss dafür neu gestartet werden!
Hintergrund:
Es gibt zwei Erklärungen für diese Verhalten
  1. Es werden unterschiedliche Inhalte der Datei ausgeliefert - mit und ohne den beiden oben gezeigten Zeilen am Dateiende. 
  2. Der sshd vergleicht dabei die Klarnamen der Gruppenbezeichnung. Ich installiere gern für den Server EN Systeme und gebe Ihnen eine DE mui.
    • Ein 2012 EN System mit DE mui hat administrators - > match!
    • Alle späteren EN Systeme (2012 R2, 2016) mit DE mui haben Administratoren -> kein match!
Der folgende Code kommentiert die verantwortlichen Zeilen in der config aus. In meinem Setupscript für die älteren Serversysteme ist dieser Code bereits enthalten.
# Patch sshd config to allow administrators Group public Key logon
$Quelle="${Env:ProgramData}\ssh\sshd_config"
write-output "patch the sshd config on $Quelle"
Stop-Service -Name sshd
$Inhalt = Get-Content $Quelle
#search 2 lines contains administrators and insert commment sign
$Inhalt|foreach {if ($_ -match "administrators") {$Inhalt[$_.readcount-1]=$_.Insert(0,"#")}}
set-Content $Quelle $Inhalt
Start-Service -Name sshd
Alternative Lösung:
Die Schlüssel der entsprechenden User wirklich in die Datei c:\ProgramData\ssh\administrators_authorized_keys eintragen. Wie hier beschrieben, müssen dazu noch weitere Änderungen (Rechte an Datei und Inhalt C:\ProgramData\ssh\sshd_config) durchgeführt werden.

Den OpenSSH Server wieder loswerden

Stop-Service -Name sshd 
pushd
cd "${Env:ProgramFiles}\OpenSSH-Win64\" 
.\uninstall-sshd.ps1
popd
rm -recurse "${Env:ProgramFiles}\OpenSSH-Win64"
rm -recurse "${Env:ProgramData}\ssh"
Remove-NetFirewallRule -Name sshd

Zum Nachlesen

Ziel des Artikels war es, kurz und knapp alle Schritte zusammenzufassen.
Ausführlicher kann man in folgenden Artikeln nachlesen:
https://heinz-otto.blogspot.com/2018/06/windows-hat-jetzt-ssh.html
https://heinz-otto.blogspot.com/2017/01/per-ssh-remote-befehle-direkt-ausfuhren.html
https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_server_configuration



Montag, 6. Mai 2019

Setup Raspberry Pi 2019

Mal wieder ist ein Jahr um und ich habe ein bisschen dazu gelernt. Ich stelle jetzt meine Setup Scripts über GitHub zur Verfügung, das macht es leicht sie einfach beim Setup zu laden.
Am grundlegenden Setup vom System und von FHEM hat sich nicht soviel geändert, deswegen verzichte ich hier auf Detailbeschreibungen, soweit die vom vorigen Jahr noch gelten.

Mein Setup basiert auf einem aktuellem raspbian Lite Image, welches von raspberrypi.org herunter geladen wird und mit einem Imagetool (Windows z.B. win32DiskImager) auf die SD Card geschrieben wird. Für die Headless-Installation braucht man den ssh Zugang und darf die Datei ssh im Bootlaufwerk nicht vergessen! Vor dem Kopieren den Laufwerksbuchstaben richtig setzen (meine Codeboxen sind editierbar) ctrl+a um alles zu kopieren, Windows+r um die Ausführen-Box zu erhalten und die Zeile dort "einwerfen".
cmd /c echo " " >e:\ssh

Beim Setup braucht man erweiterte Rechte, deshalb alles im Context "root" - sudo su ausführen! Man kann die Scripts entweder mit chmod +x ausführbar machen oder einfach mit bash Scriptname starten. Bitte beachten:
Alle meine Scripts sind für "einmaligen" Gebrauch bestimmt! Ich habe praktisch keine Fehlerbehandlung für wiederholte Ausführung und Bereinigung drin. Sollte also während der Installation etwas schief gehen, kann man völlig neu beginnen oder muss die Installation Schritt für Schritt manuell ausführen!

Die Basis

Die Grundeinstellung:

  • Zeitzone Berlin, 
  • alles auf "deutsch" :
    • Land, 
    • Locale, 
    • Consolen Keyboard 
    • und WiFi, 
  • Hostname. 

Das müsste eigentlich noch um die Abfrage des Passwortes für Pi ergänzt werden.
Das Setup Script startet mit einem Upgrade des aktuellen Raspbian Standes, je nach nach aktuellen Zeitpunkt "zwischen den Images" kann das aktuelle Image schon ein paar Monate alt sein und könnte offene Lücken haben.
Wesentliche Schritte sind im Script kommentiert, das wird auch aktuell gehalten.
wget https://raw.githubusercontent.com/heinz-otto/raspberry/master/setupBasic.sh
Jetzt hat man ein aktuelles raspbian, das restliche Setup ist Anwendungsspezifisch.
Update Juni 2019: Mir ist erst jetzt aufgefallen, das hostnamectl den Namen in der /etc/hosts nicht anpasst. Das muss man also zusätzlich mit sed (Meine Version von September 2016) tun.

Für Pi mit Bluetooth Modul

Als nächstes kann man für Zusatzmodule auf der GPIO-UART Schnittstelle beim Pi3 und P3+ diese Schnittstelle aktivieren.
Bei den Modellen B, B+, B2 wird lediglich die uart aktiviert, da sie per default deaktiviert ist. Link
Nach diesem Script wäre ein Neustart fällig, aber nicht an dieser Stelle notwendig und deshalb nicht integriert. Den reboot kann man jederzeit später einbauen.
wget https://raw.githubusercontent.com/heinz-otto/raspberry/master/setupUart.sh

Samba Server

Für die Sprachausgabe brauche ich einen SMB Server. Das folgende Script installiert den Dienst und ein SMB Share, welches ohne Anmeldung frei beschreibbar ist!
wget https://raw.githubusercontent.com/heinz-otto/raspberry/master/setupSamba.sh

FHEM

Auch das Script für die grundlegende FHEM Installation habe ich angepasst. Ich verwende jetzt zwei Textdateien in denen meine aktuell zusätzlich verwendeten deb Pakete und Perl Module (cpan) enthalten sind. Wer das lokal anpassen möchte erstellt einfach im aktuellen Pfad (/home/pi) beide Dateien mit entsprechendem Inhalt (Vorlage auf GitHub). Die vorhanden Dateien werden vom Script genutzt und nicht überschrieben.
Das Script arbeitet folgende Schritt ab:

  • Vorbereitung FHEM Setup gemäß https://debian.fhem.de/
  • Hole Textdateien mit zusätzlichen deb Paketen und Perl Modulen
    • und Installiere ...
  • Installation FHEM
  • Basiskonfiguration FHEM 

wget https://raw.githubusercontent.com/heinz-otto/raspberry/master/setupFhem.sh
Nach dem Download ist es sicher sinnvoll, gerade die Basiskonfiguration von FHEM noch anzupassen und zu erweitern. Z.B. die Ortsabhängigen Koordinaten attr global l...
Ein automatisches Save am Schluss der Konfiguration ist in meinem Script nicht drin!

Backup

Wer möchte kümmert sich auch jetzt sofort ums Backup. Ich hatte dazu schon etwas geschrieben
Das Script muss nach dem download mit den Informationen zum Server und Account angepasst werden.
wget https://raw.githubusercontent.com/heinz-otto/raspberry/master/setupBackupFhem2Cifs.sh

Nodejs

Einige Applikationen erfordern die Anbindung mit Node Server. Die Installation habe ich hier beschrieben und ein simples Script dazu gemacht.
wget https://raw.githubusercontent.com/heinz-otto/raspberry/master/setupNodejs.sh

Tipp

Will man alle hier erwähnten Scripts herunterladen, geht das mit "Brace Expansion" in diesem Einzeiler.
wget https://raw.githubusercontent.com/heinz-otto/raspberry/master/setup{Basic.sh,Uart.sh,Samba.sh,Fhem.sh,BackupFhem2Cifs.sh,Nodejs.sh}

Sound

Tobias hat irgendwann in seinem Text2Speech Modul den Aufruf MplayerCall so erweitert, dass man den Aufruf z.B. für play ohne mein früheres Wrapper Script verwenden kann. Der Volume Level wird bei mplayer quasi in Prozent, bei play eher als Faktor angegeben. Deshalb teile ich den vom Modul übergebenen Level einfach durch 100. Zusätzlich muss man den leicht anderen Syntax des Alsa Devices bei der Definition beachten! (Bei mplayer hw=0.0)
Mit aplay -l kann man sich die Geräte anzeigen lassen. Die Subgeräte kann man bei der Definition weglassen! Zeigt aplay -l die Soundkarte als Device 1 braucht in der Definition nur hw:1 stehen.
Leider kann die Shell nur ganze Zahlen rechnen. Man könnte Perl nehmen oder die Nachkommastellen mit Modulo rechnen. Ich habe mal beide Varianten aufgeschrieben. Funktionieren tun beide.
define MyTTS Text2Speech hw:0,0
attr MyTTS TTS_MplayerCall AUDIODEV={device} play -q -v $(perl -e 'print {volume}*{volumeadjust} / 10000;') {file}
attr MyTTS TTS_MplayerCall AUDIODEV={device} play -q -v $(({volume}*{volumeadjust}/10000)).$(({volume}*{volumeadjust}%10000)) {file}
Es gibt eventuell eine Fehlermeldung (WARN alsa: can't encode 0-bit Unknown or not applicable) und es wird trotzdem Sound wieder gegeben. Das ist offenbar ein Bug, diese Meldung kann man mit &>/dev/null am Ende des Befehls unterdrücken.

Update

Ein vorhandenes System aktuell halten, wie macht man es richtig? So einfach wie unter Windows ist es leider nicht.Bei Windows wird es uns mittlerweile zwangsweise ziemlich einfach gemacht, das System macht einfach ein Update. Bei Linux muss man irgendwie wissen was in welcher Reihenfolge man tun muss. Mal schauen was ich da noch so herausfinde.
Hier gibt es einen Ausgangspunkt für  mein ToDo
https://forum.fhem.de/index.php/topic,101232.0.html#lastPost

Freitag, 3. Mai 2019

Installation Node.js

Ein neues Gerät ist im Haus, und die Anbindung an FHEM erfordert Node.js.
Als asynchrone, Event-basierte Laufzeitumgebung wurde Node speziell für die Entwicklung von skalierbaren Netzwerkanwendungen entworfen.
Das js steht für Javascript.
Ich habe immer das Gefühl, die meisten Anleitungen sind in einer eigenen, mir nur sehr schwer verständlichen Sprache geschrieben. Manche treiben meinen Puls in die Höhe und es tritt Angstschweiß auf die Stirn.
Deswegen versuche ich es mal für meine Umgebung, denn komischerweise ist auch die Originalseite so geschrieben, dass man sich tar Pakete aussucht, herunterlädt und irgendwie entpackt. Aber ganz versteckt findet man auch die Variante für Debian.
Auf der Nodejs.org Seite steht aktuell, dass die Version 10.15.3 derzeit die Active LTS Version ist.

Bitte vor der Installation die aktuelle Version nachschauen, oder die von der Anwendung geforderter Version installieren! Meist steht dort aber neuer als x.x.x

Nur um sudo erweitert sind diese Zeilen von der oben verlinkten Seite kopiert. Der Start einer separaten shell (bash) ist notwendig damit die Umleitung (pipe) funktioniert.
# Using Debian, as root
sudo bash -c "curl -sL https://deb.nodesource.com/setup_10.x | bash -"
sudo apt-get install nodejs
Von der Webseite wird quasi ein Script heruntergeladen und der bash als Standardinput übergeben. Anschließend ist nodejs im Paketmanager verfügbar.
Mit diesen Befehlen kann man die installierte Version abfragen.
node -v
npm -v
npm ist für die Installation von node Paketen zuständig und wird für die weitere Installation benötigt.
Damit ist die Installation der offiziellen Nodejs Softwareversion abgeschlossen. Und das System ist bereit für die eigentliche Installation der Anwendungssoftware.
Da man eventuell das Eine oder Andere automatisch starten will, empfiehlt sich auch noch gleich die Prozesssteuerung von nodejs.
sudo npm install pm2 -g
Ich habe für alles auch ein Script gebaut, welches aktuell gehalten wird.