Dienstag, 30. Juli 2019

Definitionen in FHEM komplett umziehen

Ich habe mehrere System auf denen ich etwas teste und manchmal schleicht sich nach langer Zeit quasi "produktiver Betrieb" ein. Dann möchte ich gern die getestete Definition und alles was dazu gehört: Log, Logdateien, Plots usw. in das produktive System übernehmen. Da steht also die Aufgabe neben der eigentlichen Definition auch noch ein paar Dateien zu übernehmen. Ich habe mir dazu folgendes Vorgehen ausgedacht:
  1. Alle Dateien auf das Zielsystem kopieren oder das Quellsystem mounten
  2. Die wirklich benötigten Dateien an die richtige Stellen, mit den richtigen Berechtigungen, anhand der Definitionen in den FHEM Ordner kopieren.
  3. Die Definitionen vom Quell- auf das Zielsystem kopieren.
Dabei soll so viel wie möglich "automatisch" laufen. Damit ich wenig installieren und konfigurieren muss, hole ich alle potentiellen Dateien mit scp einfach pauschal lokal in ein temporäres Verzeichnis. Hat man große log Dateien - kann man auch einschränken.
host1='Hostname Instanz1'                        #Quell FHEM Instanz
tDir=fhem                                        #relativer Pfad der im lokalen Pfad (HomeDir des Users) angelegt und verwendet wird
mkdir -p $tDir/www
scp -r pi@$host1:/opt/fhem/log/ $tDir/           #kopiert den Remote Pfad log/ nach fhem/log/  
scp -r pi@$host1:/opt/fhem/www/gplot/ $tDir/www/ #kopiert den Remote Pfad www/gplot/ nach fhem/www/gplot/
Jetzt werden die wirklich notwendigen Dateien anhand der Definitionen ermittelt und lokal an die richtige Stelle mit den richtigen Berechtigungen kopiert. Ich mache das deshalb über FHEM.
Zu allen Schritten brauche ich meinen HTTP Client
wget -O fhemcl.sh https://raw.githubusercontent.com/heinz-otto/fhemcl/master/fhemcl.sh

Um die Einzeiler etwas übersichtlicher zu halten, definiere ich noch ein paar Variablen zu Beginn, $host1 und $tDir wurden im Befehlsblock oben schon definiert. In den Einzeilern wird einfach davon ausgegangen, dass der lokale Zugriff nur die Port Nummer 8083 erfordert.
inst1=$host1:8083                #URL Remote Instanz [http://[<user:password@>][<hostName>:]]<portNummer> 
rDir=$(pwd)/$tDir/               #absoluter Pfad für die (kopierten) Quelldateien
gDir='./www/gplot/'              #Pfad in dem die gplot Datei in FHEM liegen
devSpec='FILTER=NAME=.*Sensor.*' #wird in den Befehlen um TYPE= ergänzt
Man kann selbstverständlich die Quelldateien remote mit mount einbinden (z.B. nfs). Dann enthält $rDir den gemounteten Pfad.

Achtung: Die Einzeiler enthalten keine Fehlerbehandlung! Es kann also zu unvorhergesehenen Auswirkungen kommen!
Datensicherung!
Die Kopiervorgänge werden eventuell nicht oder falsch ausgeführt, können aber gleichnamige Dateien überschreiben! Die Änderungen in der cfg werden nicht automatisch gesichert, ein restart von FHEM stellt den alten Zustand wieder her.
Die devSpec sollte man im Zweifel immer testen!
bash fhemcl.sh $inst1 "list TYPE=.*:$devSpec"
Man sollte auch immer zunächst die Einzeiler ohne den letzten Ausführungsteil zur Probe laufen lassen!

Einzelne Schritte

Zunächst als "Fingerübung" die Grundlagen um aus bestimmten Definitionen, die "Sensor" im Namen haben, die Dateien zu kopieren.
  • der list Befehl erzeugt eine Tabelle aus Name und dem entsprechenden INTERNAL, von dieser wird nur die zweite Spalte benötigt,
    • für die log Datei wird mit sed alle Platzhalter %Y,%m usw. durch * ersetzt. Damit werden alle vorhandenen Log Dateien erfasst. 
    • für die gplot Datei wird mit sed noch $gDir vorangestellt und ".gplot" angehängt, 
  • der zweite sed Befehl ersetzt ./ durch den absoluten Pfad $rDir
    • Der Ausdruck ${rDir////\\/} erzeugt dabei aus dem normalen Pfadnamen einen "escaped" Pfadnamen: ersetzt also / durch \/.
  • Der tr Befehl am Ende macht aus der Zeilen- eine Leerzeichen getrennte Liste für den cp Befehl.

Die FileLog (log) Dateien

datei=$(bash fhemcl.sh $inst1 "list TYPE=FileLog:$devSpec logfile"|awk '{print $2}'|sed "s/%./*/g"|sed "s/.\//${rDir////\\/}/"|tr '\n' ' ')
bash fhemcl.sh 8083 "\"cp -n $datei ./log/\""

Die SVG (gplot) Dateien

datei=$(bash fhemcl.sh $inst1 "list TYPE=SVG:$devSpec GPLOTFILE"|awk '{print $2}'|sed "s/^/${gDir////\\/}/;s/$/.gplot/"|sed "s/.\//${rDir////\\/}/"|tr '\n' ' ')
bash fhemcl.sh 8083 "{qx(cp -n $datei ./www/gplot/)}"
Ich verwende bewusst zwei unterschiedliche Kopierbefehle. Die erste Variante blockiert das lokale FHEM nicht, allerdings hat man keine Rückmeldung wann der Kopiervorgang beendet ist. Die zweite Variante blockiert FHEM, was bei den kleinen gplot Dateien aber nicht stören sollte.

Definition

Jetzt brauchen nur noch die Definitionen auf das lokale Zielsystem kopiert werden.
bash fhemcl.sh $inst1 "list -r TYPE=FileLog:$devSpec"|bash fhemcl.sh 8083
bash fhemcl.sh $inst1 "list -r TYPE=SVG:$devSpec"|bash fhemcl.sh 8083

Verbundene Definitionen

Der list Befehl ist sehr vielseitig! Neben Gruppen von Definitionen kann man auch einzelne Geräte und deren komplette verbundenen Definitionen umziehen.
Achtung: "-R" funktioniert so richtig nur mit Device Namen ohne regExp, "-R" ist laut Doku auch "unvollkommen"!
So wird die SVG zusammen mit der zugehörigen FileLog Instanz übertragen.
bash fhemcl.sh $inst1 "list -R SVG_FileLog_SensorWG_1"|bash fhemcl.sh 8083

Abhängigkeit

Die SVG Definition und deren Funktion ist von der zugehörigen FileLog Definition abhängig. Also kann man von der SVG Definition alles notwendige ableiten. Die log Dateien anhand des SVG kopieren:
bash fhemcl.sh $inst1 "list TYPE=SVG:$devSpec LOGDEVICE"|sed 's/^.*\s/list /;s/$/ logfile/'|bash fhemcl.sh $inst1|awk '{print $2}'
Der Vorgang ist zweistufig, erst wird das LOGDEVICE aus der SVG Definition gelesen, daraus wieder ein list Befehl erzeugt und damit das log File direkt aus der Definition ausgelesen.
Nach dem obigen Schema kann man daraus die Dateiliste erstellen.
|sed "s/%./*/g"|sed "s/.\//${rDir////\\/}/"|tr '\n' ' '
Anstatt über eine Variable ($datei) kann man die Pipe auch fortführen.
|echo "\"cp -n $(cat -) ./log/\""|bash fhemcl.sh 8083
Der komplette Einzeiler ist wirklich lang.
bash fhemcl.sh $inst1 "list TYPE=SVG:$devSpec LOGDEVICE"|sed 's/^.*\s/list /;s/$/ logfile/'|bash fhemcl.sh $inst1|awk '{print $2}'|sed "s/%./*/g"|sed "s/.\//${rDir////\\/}/"|tr '\n' ' '|echo "\"cp -n $(cat -) ./log/\""|bash fhemcl.sh 8083

Um den list -R Befehl mit einer devSpec zu verwenden, muss man diese quasi erst auflösen.
Achtung: Wenn die devSpec nur eine Definition trifft, schlägt dieser einfache Einzeiler fehl!
bash fhemcl.sh $inst1 "list TYPE=SVG:$devSpec"|sed 's/^/list -R /'|bash fhemcl.sh $inst1|bash fhemcl.sh 8083

Finale

Damit hat man 3 Schritte ausgehend von einer devSpec:
  1. gplot Dateien kopieren
  2. log Dateien kopieren
  3. SVG Definitionen und die zugehörigen FileLog Definitionen übertragen.

bash fhemcl.sh $inst1 "list TYPE=SVG:$devSpec GPLOTFILE"|awk '{print $2}'|sed "s/^/${gDir////\\/}/;s/$/.gplot/"|sed "s/.\//${rDir////\\/}/"|tr '\n' ' '|echo "\"cp -n $(cat -) ./www/gplot/\""|bash fhemcl.sh 8083
bash fhemcl.sh $inst1 "list TYPE=SVG:$devSpec LOGDEVICE"|sed 's/^.*\s/list /;s/$/ logfile/'|bash fhemcl.sh $inst1|awk '{print $2}'|sed "s/%./*/g"|sed "s/.\//${rDir////\\/}/"|tr '\n' ' '|echo "\"cp -n $(cat -) ./log/\""|bash fhemcl.sh 8083
bash fhemcl.sh $inst1 "list TYPE=SVG:$devSpec"|sed 's/^/list -R /'|bash fhemcl.sh $inst1|bash fhemcl.sh 8083


Donnerstag, 25. Juli 2019

rootfs auf ein anderes Laufwerk verschieben

Der Startparameter root= legt für den Linuxkernel fest wo das root FileSystem zu finden ist.
In der dann dort gelesenen /etc/fstab wird festgelegt wohin welches Laufwerk eingehängt/gemounted wird. Das gilt auch für das rootfs.
Anhand vom SingeBoardComputer Odroid HC1 will ich zeigen wie man das rootfs vom Originalstandort: 2. Partition der SD Card auf eine über Sata angeschlossene Disc verschieben kann.

Beschreibungen dazu habe ich einige gefunden, ich habe versucht sie zu verstehen und für mich so simpel wie möglich umzusetzen. Prinzipiell wird das in der Art für jeden SBC funktionieren.

Der Systemstart ist dann wie folgt: Bootsystem von SD Card lesen, rootfs auf der zweiten Disc über Sata oder USB starten.
Es gibt auch SBCs die direkt (ohne Umweg über SD Card) von einer Sata/Usb Disc booten können!

Ich habe es der Vollständigkeit halber an zwei SBC Exemplaren getestet:
  • Odroid HC1 mit Ubuntu, Bootkonfiguration liegt in /media/boot/boot.ini
  • Raspberry Pi 2 mit raspbian, Bootkonfiguration liegt in /boot/cmdline.txt
Die Vorgehensweise und das Prinzip ist fast identisch. Folgendes ist zu tun:
  1. Disc partitionieren und formatieren
  2. Disc mounten
  3. rootfs von SD Card nach Disc kopieren
  4. fstab auf der Disc anpassen 
  5. Bootparameter auf der SD Card anpassen.
  6. Nach einem Neustart ist das rootfs auf der Disc 

Vorbereitung

Ein Tool ist eventuell noch nicht installiert: rsync
Wir müssen alles im sudo (root) Kontext ausführen.
sudo su
apt update
apt-get install rsync
lsblk
Der letzte Befehl dient dazu, den Geräte Eintrag zur Disc zu finden, meist wird das sda sein.

Die Disc muss jetzt ev. initialisiert, mit einer Partition und einem Filesystem versehen werden.
fdisk /dev/sda
Eine kurze Befehlsreferenz für fdisk
  • mit p anzeigen, erstmal anschauen und die nächsten Schritte entscheiden
  • eventuell d für löschen oder g für ganz neue GPT Partitiontable
  • n für neu, dann werden Standardwerte abgefragt, kann man einfach bestätigen
  • w für schreiben, bisher stand alles nur im Speicher, mit w wird festgeschrieben.
Der Befehl legt das Dateisystem an, es muss nichts weiter eingegeben werden. Der letzte Befehl dauert etwas, man muss nur warten und nichts drücken!
mkfs.ext4 /dev/sda1
Damit ist die Vorbereitung der Disc abgeschlossen, jetzt definiere ich für die weitere Arbeit ein paar Parameter/Variablen um weniger zu tippen und den Code universell zu halten.
sd=sda                 # siehe Ergebnis von lsblk
mmc=mmcblk1            # für den Odroid hc1, beim Raspberry Pi muss man mmcblk0 setzen.
mp=/media/systemdrive  # kann man nach persönlichem Geschmack anpassen
Kopie des rootfs
Jetzt wird das rootfs von der SD Card auf die Disc kopiert. Achtung: Damit das wirklich umfassend funktioniert, darf das System möglichst keine offenen Dateien haben! Eventuell muss man Prozesse/Dienste beenden.
mkdir -p $mp               # Mountpoint anlegen
mount /dev/${sd}1 $mp      # Disc einhängen
rsync -axv / $mp           # rootfs mit rsync kopieren - das dauert entsprechend!

Odroid HC1

Für den Odroid HC1 muss man noch diesen Befehlsblock ausführen:
cp /media/boot/boot.ini /media/boot/boot.ini.bak
UUIDo=$(blkid -o export /dev/${mmc}p2 | grep ^UUID)
UUIDn=$(blkid -o export /dev/${sd}1 | grep ^UUID)
sed -i "s/^$UUIDo/$UUIDn/" $mp/etc/fstab
sed -i "s/root=$UUIDo/root=$UUIDn/" /media/boot/boot.ini
cp /media/boot/boot.ini /media/boot/boot.ini.hdd
Bei meinem System erfolgte die Einbindung des rootfs anhand der UUID der SD Card (des Laufwerkes). Ich habe deshalb auch die Einbindung der Disc so vorgenommen.

Andere

Bei meinem Raspberry wurde die PARTUUID, also die UUID der Partition verwendet. Letztlich könnte dort auch einfach der Pfad zum Device /dev/sda1 stehen.
Für den Raspberry sieht es so aus:
cp /boot/cmdline.txt /boot/cmdline.txt.bak 
PUUIDo=$(blkid -o export /dev/${mmc}p2 | grep PARTUUID)
PUUIDn=$(blkid -o export /dev/${sd}1 | grep PARTUUID)
sed -i "s/^$PUUIDo/$PUUIDn/" $mp/etc/fstab
sed -i "s/root=$PUUIDo/root=$PUUIDn/" /boot/cmdline.txt
cp /boot/cmdline.txt /boot/cmdline.txt.hdd

Test und Neustart

Da ich jeweils die boot Konfiguration gesichert habe, kann man leicht auf die alte config gehen und wieder von SD Card starten, oder danach die geänderte Version wieder aktivieren.

Man muss vor dem Neustart den Inhalt der boot Konfiguration überprüfen! Geht einfach
diff /media/boot/boot.ini /media/boot/boot.ini.bak

Ich suche und ersetze letztlich nur die alte durch die neue ID. Ich habe es bei einem neuen System getestet. Ob es bei allen möglichen Inhalten der beiden Dateien so funktioniert ist nicht sicher!

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

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

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
cp $datei /opt/fhem/backup/ssh.tar.gz

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 mitsichern oder eine weitere Datei nach gleichem Schema erzeugen.

Finale Sicherung des alten Systems

Man stößt jetzt noch ein backup in FHEM an (oder fährt fhem herunter und stößt dann ein backup an)
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

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:*.tar.gz .
scp *.tar.gz pi@raspberrypi:
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.

ToDo
Ich brauche noch die nodejs Anbindung für das Schaf.
codebox

codebox

Freitag, 14. Juni 2019

Rockrobo - root und gut?

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

Vorbereitung

Am Einfachsten erschien es mir, einen Raspberry Pi mit Wlan zu nehmen und mit einem neuen raspbian Image zu beginnen. Für spätere Arbeiten ist es sicher am einfachsten, man beschriftet die SD Card und hebt sie auf.
Der Linuxrechners und der Roboter müssen mit dem gleichen Netzwerksegment verbunden sein!
Der Roboter muss für den Flashvorgang in der Ladestation stehen!
Hinweis:
Für den einfachen "root Vorgang" (wenn der Roboter schon im Netz integriert und der Token bekannt ist) braucht man kein Wlan, dann geht auch jeder Linuxrechner im Lan. Will man einen neuen Roboter sofort rooten und ihn erst dann ins Netzwerk einbinden, braucht man Wlan (und Monitor und Tastatur). Man muss in dem Fall den Computer mit dem offenen Wlan des RockRobo verbinden.

Software bauen und flashen

Was hier eigentlich passiert ist keine Magie: die Originale Firmware wird entpackt/entschlüsselt, der ssh Zugang wird freigeschaltet und anschließend wird das Firmware Paket wieder zusammengebaut und auf die Sauger geflashed. Dazu wird das Tool mirobo und ein flasher Script verwendet, man muss also selbst nicht viel tun.
Den gesamten Vorgang schreib ich mal ein einem Block mit ein paar Kommentaren. Achtung: Ich starte aus dem Login des normalen User Pi, ohne sudo su!
# Software installieren
sudo apt-get update
sudo apt-get install ccrypt python3-pip dos2unix
sudo pip3 install python-miio
#ip Adresse und token ablegen um sich Tipparbeit zu sparen
ip="<ip adresse - kein name>"
token="<32 stelliger token>"
#Verbindung testen wenn man den Robo schon eingebunden hat
mirobo --ip $ip --token $token status
# ssh Key erzeugen, File bestätigen, Frage nach passphrase zweimal bestätigen (keine Passphrase!)
ssh-keygen -t rsa -b 4096 -C "RockRobo"
#Arbeitspfad erzeugen
mkdir dc && cd dc
#nur die drei Dateien laden und nicht das ganze Repository
wget https://raw.githubusercontent.com/dgiese/dustcloud/master/devices/xiaomi.vacuum/firmwarebuilder/imagebuilder.sh
wget https://raw.githubusercontent.com/dgiese/dustcloud/master/devices/xiaomi.vacuum/firmwarebuilder/flasher.py
wget https://raw.githubusercontent.com/dgiese/dustcloud/master/devices/xiaomi.vacuum/firmwarebuilder/adbd
# den Key ins Verzeichnis kopieren
cp ~/.ssh/id_rsa.pub .

#Firmware holen. Ab diesem Schritt muss man den Vorgang für jede zukünftige Firmware wiederholen 

#Bei mir ging dieser Link
wget https://cdn.awsde0.fds.api.mi-img.com/updpkg/v11_003468.fullos.pkg
#oder der
#wget https://dustbuilder.xvm.mit.edu/pkg/v1/3.3.9_003468/v11_003468.fullos.pkg
#Image erzeugen - der Vorgang läuft ein Weilchen...
sudo bash ./imagebuilder.sh -f v11_003468.fullos.pkg  -k id_rsa.pub -t Europe/Berlin
#Wenn alles Fehlerfrei lief kann man jetzt das Image flashen:
sudo python3 flasher.py -a $ip -t $token -f output/v11_003468.fullos.pkg
Jetzt wird der Staubsauger automatisch neu starten und meldet sich mit seiner Melodie zurück. Danach kann man sich per ssh einloggen. Das geht beim ersten Mal nur mit dem Account (und dem Key) der das Kommando ssh-keygen (siehe oben) ausgeführt hat!
ssh root@rockrobo
# Nach dem ersten Login kann man für die weitere Arbeit ein neues root passwort setzen.
passwd
Der Sauger ist weiterhin in der App und in FHEM verfügbar. Was man sich dank des Tools mirobo noch gönnen kann, ist eine deutsche Sprachdatei, das wäre aber wohl auch ohne root gegangen!?
wget https://dustbuilder.xvm.mit.edu/pkg/voice/de.pkg
mirobo --ip $ip --token $token de.pkg

Was geht jetzt mit root?

Wie schon gesagt: ssh Login.
Token auslesen.
printf $(cat /mnt/data/miio/device.token) | xxd -p
Wlan ohne reset ändern. Der Token bleibt dabei erhalten!
Der Inhalt der Datei wifi.conf entspricht ein bisschen dem Inhalt der Datei wpa_supplicant.conf. Quelle Ich arbeite gern mit nano, vi ist vorhanden und braucht nicht installiert zu werden.
apt-get update
apt-get install nano
nano /mnt/data/miio/wifi.conf
reboot
Neue Firmware darf man nur noch nach dieser Methode einspielen! Keine Updates mit einer App machen!
Man kann zur Sicherheit die Updates erstmal verhindern.
mv /usr/bin/ccrypt /usr/bin/ccrypt_
touch /usr/bin/ccrypt
chmod +x /usr/bin/ccrypt
Die Palette der weiteren Möglichkeiten ist groß: Den Rockrobo aus der Cloud aussperren, Software installieren, die Karten sichern ...

Kleines Zwischenspiel

Mir ist aus keiner der Beschreibungen im Internet so richtig klar geworden wie es "weitergeht"!
Was ist mit neuer Firmware? Es gibt eine Liste getesteter Firmware, aber welche ist gut, aktuell, neu?
Die Mi Home App hat mir ein Update angeboten, die Flole App hat andere Updates angeboten, was bedeutet denn fullos.pkg oder app.pkg? Das Update der Mi Home App (v11_003476.app.pkg) war nur 29 MB groß. Die Aufbereitung mit dem imagebuilder schlug fehl. Die Versionsnummer hatte einen "Sprung" 3.5.0 statt 3.3.9 - was soll man tun?
Ich war so mutig, habe die Updates wieder aktiviert und versucht: Damit war mein Root Zugang weg. Und nun? Es bleibt nur Factory Reset!
Es gibt drei Arten von Reset (neben einfach aus und wieder einschalten)
  1. WiFi Reset: beide Tasten auf der Oberseite (Home und Ein/Aus) drücken und Nachricht abwarten. Danach ist WiFi gelöscht und man kann den Sauger mit der Mi Home App neu anlernen.
  2. Reset: Taster unter dem Deckel mit Stift o.ä. drücken. Danach wird das System neu gestartet und WiFi ist gelöscht.
  3. Factory Reset: Home drücken und halten, Reset Taster mit Stift/Büroklammer drücken, Home weiterhin halten bis die Nachricht für Factory Reset ertönt. Danach ist softwaretechnisch der Auslieferungszustand erreicht. Die Logs über Verbrauch usw. scheinen erhalten zu bleiben.
Diesen Tipp habe ich gefunden aber nicht getestet: Man kann auch das Factory Image analysieren und rooten.

Rooten nach dem Auspacken/Factory Reset

Das ist eigentlich zu empfehlen, damit kommt man unkompliziert an den Token und kann das Wlan leicht verwalten. Das Anlernen an die App (falls man das will) macht man erst nach dem rooten.
Dafür braucht man jetzt einen Linux Rechner, den man mit dem offenen Wlan des Rockrobo verbinden kann. Und irgendwo stand: man darf kein zweites Netzwerkinterface haben. Also hab ich einfach Monitor und Tastatur an meinen schon vorbereiteten Raspberry Zero angesteckt.

Achtung! Der Rockrobo hat im AP Mode nicht all zuviel Leistung! Zum Flashen muss der Linux Rechner und der Roboter im gleichen Raum im Umkreis weniger Meter und in der Ladestation stehen!

Ich bin gewohnt Wlanverbindungen über die Datei /etc/wpa_supplicant/wpa_supplicant.conf einzurichten. Nach kurzem Test war klar: Geht universell und auch ohne WPA. Man muss die exakte ssid mit dem Befehl sudo iwlist scan scannen und dann die Datei so abändern.
country=DE
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
        ssid="rockrobo-vacuum-v1_miapF0C8"
        key_mgmt=NONE
}
Ich musste den Raspberry neu starten um die Verbindung mit dem offenen Wlan herzustellen.
In diesem Stadium gibt der Rockrobo seinen Token einfach so her. Der Befehl zum Test:
mirobo discover --handshake true
Auch der Flash Befehl geht etwas "einfacher":
sudo python3 flasher.py -f output/v11_003468.fullos.pkg
Nach dem Neustart und erfolgreichem ssh Login kann man entweder den Rockrobo direkt mit dem Wlan verbinden oder falls man die Mi Home App nutzen will, den Rockrobo mit der App einrichten.

Ein paar Zusatzinfos 

Ich habe auch mal probiert den Token selbst zu setzen, weil man vielleicht zu faul ist den in FHEM zu ändern. Dafür muss man ihn ins interne Format wandeln.
echo "44446e74695a4445713547644a79444d" |xxd -r -p
Man kann auch das interne root Passwort auslesen. Ich habe die Richtigkeit von diesem Code nicht überprüft.
perl -e 'print(join("", (map { chr(ord($_) ^ 0x37) } split(//, $ARGV[0]))), "\n");' `cat /mnt/default/vinda`

Für die Zukunft

Keine Updates über irgend eine App!
Auf der Webseite schauen welche Firmware getestet ist!

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!

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 Installation gibt es ein paar Warnmeldungen
sudo npm install iobroker.landroid-s
sudo npm install pm2 -g
# 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.landroid-s
# 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 iobroker.landroid-s wird unterhalb des aktuellen Pfades bei der Installation unter node_modules abgelegt.
Wenn man alles wieder loswerden will:
pm2 unstartup
pm2 stop /opt/landroid/fhem-landroid-s/LandroidSrv.js
pm2 delete /opt/landroid/fhem-landroid-s/LandroidSrv.js
sudo npm uninstall iobroker.landroid-s
cd /opt
sudo rm -R landroid/

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 ist der OpenSSH Server enthalten und kann einfach installiert werden.
Get-WindowsCapability -Online | where name -match '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.
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.

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

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. Der folgende Dreizeiler ist nicht perfekt aber funktioniert.
Voraussetzung: Benutzer hat schon einen RSA Key.

Linux Shell
ziel=user@host
scp ~/.ssh/id_rsa.pub $ziel:key.tmp
ssh $ziel "mkdir .ssh&type key.tmp >>.ssh\\authorized_keys&del key.tmp"
Windows CMD
set ziel=user@host
scp %userprofile%\.ssh\id_rsa.pub %ziel%:key.tmp
ssh %ziel% "mkdir .ssh&type key.tmp >>.ssh\\authorized_keys&del key.tmp"
Hinweis: Die Befehle nach ssh werden in der CMD von Windows abgearbeitet! "&" dient hier als Befehlstrenner. Mir ist es bisher nicht gelungen nur mit ssh und ohne scp zu arbeiten.

Ersteinrichtung
Alle Schritte in Kurzform für den Public Key Zugang für den User fhem zu einem Windows SSH-Remotesystem, in der Linux Shell auf FHEM Server:
sudo cp /etc/passwd /etc/passwd.sav
sudo  sed -i -e 's/fhem:.*/fhem:x:999:20::\/opt\/fhem:\/bin\/bash/' /etc/passwd
sudo passwd fhem             # Passwort vergeben und bestätigen
su fhem                      # Als fhem einloggen, es startet eine neue session!
ssh-keygen -t rsa            # optional falls noch kein Key existiert. Speichert automatisch in /opt/fhem/. Keine passphrase vergeben! 2x enter 
ziel=user@host               # Benutzer und Host einmal eintragen
scp ~/.ssh/id_rsa.pub $ziel:key.tmp
ssh $ziel "mkdir .ssh&type key.tmp >>.ssh\\authorized_keys&del key.tmp"
ssh $ziel                    # nur zum Test - es startet eine neue session!
exit                         # aus der ssh Test session vom Remotehost!
exit                         # aus der Anmeldung von fhem!  
sudo cp /etc/passwd.sav /etc/passwd
Ein ganz schneller Funktionstest für die FHEM Kommandozeile.
{qx(ssh user\@host dir)}
Hinweis: Innerhalb von Perl muss das @ schützen!

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 Windows Server 2012?

Symptom:
Ein Mitglied der Gruppe administrators kann offenbar keine Anmeldung mit Public Key machen. Obwohl alles eingerichtet ist, wird das Passwort abgefragt. Ich habe das nur in der Version 2012 und nicht bei 2012 R2 und 2016 beobachtet.
Lösung:
Ich habe mir die Sache näher angeschaut und dabei festgestellt, 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:
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

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