Dienstag, 24. April 2018

Smartphone aus China ...

Naja irgendwie kommt ja scheinbar unsere gesamte Technik irgendwie daher. Ich habe seit einiger Zeit ein mi A1 und ein mi 6 - und ich komme auch immer mal in die Situation für jemanden das neue Smartphone in Betrieb zu nehmen. Da sind mir in letzer Zeit ein paar Besonderheiten aufgefallen und ich habe Verschiedenes versucht zu recherchieren.
Ich muss es einfach notieren. In einem halben Jahr hat man ja wieder viel vergessen oder es ist mit der neuen Version wieder ganz anders.
Diese Dinge sind nicht unbedingt vorhersehbar, logisch oder irgendwo genauso beschrieben. Ob es Besonderheiten der Smartphones von mi sind oder dies "allgemein Android"ist, kann ich nicht sagen.

Werksreset


Das ist mit irgendeiner Android Version etwas aufwendiger geworden. Ich beziehe mit aktuell auf Version 8.
Ein vom Nutzer eingerichtetes zusätzliches Sicherheitsmerkmal (Sperrcode: Pin, Muster oder Fingerabdruck) verschlüsselt wohl übrigens das gesamte Smartphone und man kann es ohne diesen Sperrcode nicht mehr starten!
Es handelt sich neben der Funktion der Ortung um eine Sicherung gegen Missbrauch nach Diebstahl oder Verlust.

Samsung S8 

Man kann im ausgeschalteten Zustand diese Tasten drücken:
drei Tasten gleichzeitig: Lauter + Bixby + Power
Nach Erscheinen vom Samsung Logo kann man loslassen und das Smartphone bootet in einen typischen "Bootloader", dort kann man Menügeführt alles löschen und das Smartphone damit zurücksetzen.
Startet man jetzt neu wird der oben erwähnte Sicherheitscode nicht mehr abgefragt!
Man kann jetzt das Smartphone neu einrichten - aber! Man kann es nur einrichten mit dem ehemals auf diesem Smartphone verwendeten Google Account! Ohne den wird jede Einrichtung verweigert: Meines Wissen keine Chance!
(Eventuell gibt es irgendwelche Reset Funktionen mit Code vom Hersteller, ADB, 72 Stunden warten usw.)

Es ist also wichtig, den Google Account vom Smartphone sicher zu haben, obwohl man vielleicht denkt man benutzt ihn nicht! Früher waren nur die Daten weg, heute wäre das Smartphone "weg"!

mi 6

Das mi 6 kann man nicht ohne weiteres "Hart" zurücksetzen. Die Tastenkombination Power + Volume- bootet lediglich den FASTBOOT Modus. Dort kann man meines Wissen nur mit ADB weitermachen.

Werksreset geht somit nur mit der Methode aus dem angemeldeten Smartphone heraus im Menü: Einstellungen/Sichern zurücksetzen/Auf Werkszustand zurücksetzen
(bzw. Mi Oberfläche und der derzeit gemischte Sprachversion,  Version MIUI Global 9.2.3.0):
Einstellungen/System&Device/Additional settings/Backup & reset/Auf Werkszustand zurücksetzen

Achtung: dieser Vorgang geht nur, wenn man vorher die Systemsprache auf english umgestellt hat! Wahrscheinlich hat die deutsche Oberfläche einen Bug!

Laut Beschreibung könnte man danach das Smartphone völlig neu einrichten, also auch an einen Fremden geben. Doch das stimmt nicht! Wenn man jetzt das Smartphone neu einrichten will wird erstmal wieder der alte Google Account verlangt!
Den alten Account muss man eingeben und dann kann man die Einrichtung (am Besten in english) ohne jegliches Konto durchführen. Danach kann man wieder einen Werksreset machen und jetzt kann man das Smartphone wirklich mit einem neuen Konto einrichten.

Es ist offenbar ein Bug des mi 6. Ich habe den gleichen Vorgang mit einem mi A1 getestet und es klappt wie erwartet.

Aber! Um sicher zu gehen, sollte man es unbedingt immer testen, bevor man das Smartphone an Fremde weiter gibt! Ich hatte in früheren Geräten auch schon den Fall, dass Bilder nicht gelöscht wurden!

GPS Daten

Beim mi 6 und dem mi A1 ist mir noch aufgefallen: Wenn man es ohne SIM Karte startet und einrichtet, ist GPS offenbar völlig desorientiert.  Man befindet sich in Marlborough district bzw. in Blenheim in Neuseeland. Das bleibt hartnäckig so, auch mit Internet (Wlan) Verbindung, auch tagelanges warten ändert dies nicht.
Bis man einmal die SIM Karte eingesteckt hat, dann ist er bereit ordentlich zu lokalisieren. Allerdings wird dann später mal wieder ohne SIM Karte gestartet ist er wieder erstmal in Neuseeland.


Sonntag, 25. Februar 2018

Windows Server Freigabe auf dem Raspberry verbinden

Ich will hier kurz zeigen wie der Zugriff auf eine Windows (Samba) Freigabe unter Raspbian eingerichtet wird. Im Raspbian Image (Lite vom November 2018) sind alle Voraussetzungen vorhanden, man muss nichts weiter installieren. In anderen Systemen kann es sein, dass man das debian Paket cifs-utils nachinstallieren muss.  Openmediavault hat z.B. bei aktiviertem Samba nicht automatisch cifs-utils installiert.
Für den praktischen Gebrauch muss man lediglich 3 Dinge konfigurieren, für einen schnellen Test  kann man es mit einem Zweizeiler machen (siehe weiter unten):

Pfad

Unter Linux braucht man einen Ort wo man ein Laufwerk "hin" mounten kann, dabei wird
\\Servername\Sharename auf den lokalen Pfad /DirName/DirName gemappt.
Man erzeugt einen Pfad, am Besten mit einer "Wurzel", einem Verzeichnis unter dem alle Netzlaufwerke eingehängt werden:
mp='/mnt/Sicherung'
sudo mkdir -p ${mp}
Die Option -p erzeugt alle notwendigen Ordner falls sie noch nicht existieren.

Benutzerkonto

Da ein Windows Server nicht ohne weiteres einen Zugriff ohne Login ermöglicht und wir username und password nicht immer eintippen wollen, werden die Informationen entsprechend abgelegt.
Dabei gibt es drei Möglichkeiten. Ja nach Vorliebe verwendet man einen Editor (nano) oder direkte Shellbefehle
1. persönliche Datei (notwendiger Inhalt siehe nächster Codeblock):
fcred='.smbcredentials'
nano $fcred
chmod 600 $fcred
Die Datei ist damit nur vom Eigentümer lesbar!

2. allgemeine Datei:
Wenn keine Domain verwendet wird, kann der Eintrag domain entfallen oder freibleiben.
fcred='.smbcredentials'
export datei="/usr/${fcred}" 
sudo bash -c "cat >${datei}" <<'EOF'
username=UserName
password=Userpassword
domain=
EOF
Man braucht pro Konto eine credentials Datei. Diese Datei muss von allen Usern lesbar sein, die mounten wollen. Die gerade angelegte Datei ist aber auch von "Jedem" lesbar, will man das eingrenzen, kann man das so machen:
sudo -s <<EOI
  addgroup cifs
  usermod -aG cifs fhem
  usermod -aG cifs pi
  chown root:cifs ${datei}
  chmod 640 ${datei}
EOI
Hinweis: Die Änderung der Gruppenmitgliedschaft wirkt erst nach Neuanmeldung!

3. anstatt extra Datei (credentials=Datei) schreibt man die Kontodaten direkt in die fstab Zeile, dort ohne Zeilentrennung!
username=ano,password=nym

fstab

Nun fehlt noch der mount Eintrag in der fstab. In meinem Beispiel wird nicht automatisch gemountet, alle User dürfen mounten und das Laufwerk ist beschreibbar.
sudo bash -c "echo //ServerName/daten ${mp} cifs noauto,users,credentials=/usr/.smbcredentials 0 0 >> /etc/fstab"

Verwendung

Jetzt können wir das Laufwerk einbinden, den erfolgreichen mount anzeigen und den Inhalt anzeigen. Das funktioniert ohne sudo, der Benutzer braucht Leserechte auf die credentials Datei.
mount ${mp}
df
ls -l ${mp}
umount ${mp}

Hinweis

Das Windows Laufwerk wird auf diese Art nicht automatisch beim Start angebunden. Das Netzwerk ist zu diesem Zeitpunkt noch nicht verfügbar und der automount über die fstab würde nicht funktionieren. Ist für mich kein Nachteil, weil es jederzeit in einem Script per mount Befehl angebunden werden kann.

Nachtrag

Man kann auch jederzeit  mit einem simplen "Zweizeiler" ein Windows Laufwerk als sudo mounten, password= kann man weglassen, dann wird es abgefragt.

sudo mkdir -p /mnt/daten
sudo mount -t cifs -o username=UserName,password=Passwort //ServerName/Freigabe /mnt/daten
# Bei smb1 Servern und ab debian stretch
sudo mount -t cifs -o username='UserName',password='Passwort',vers=1.0 //ServerName/Freigabe /mnt/daten

Bei Problemen kann man sich die verwendeten Dateisysteme bzw. die Unterstützung des Kernels  anzeigen lassen.
cat /proc/filesystems
ls /lib/modules/$(uname -r)/kernel/fs

Zum nachlesen: Ubuntu Wiki

SMB Protokoll

smb Version 1 wird mittlerweile als extrem unsicher eingestuft. Deswegen wird es aus modernen Systemen "entfernt".
Allerdings ist es in vielen Geräten nach wie Standard und eine Unterstützung von smb 2 oder 3 nicht implementiert (Fritzbox NAS, Sonos ...)
Windows hat ab Version 1709 das Protokoll entfernt, man muss es bei Bedarf mit "Windows Apps und Features" nachinstallieren (Neustart erforderlich)
debian stretch hat es offenbar als default aus der Aushandlung herausgenommen, mann muss es mit der cifs Option "vers=1.0" beim mount Befehl explizit hinzufügen, wenn der Server nur smb1 unterstützt.

Donnerstag, 8. Februar 2018

In FHEM externe Programme aufrufen

Es gibt viele Möglichkeiten ein externes Programm aufzurufen. Ich habe Einiges ausprobiert und hier sind meine Erkenntnisse. Es kann sein, dass sich Dinge ändern oder ich etwas nicht richtig verstanden habe. Meine Ausführungen sind mit Sicherheit nicht vollständig!
Dieser Beitrag endet mit konkreten Beispielen, die kann man exakt so übernehmen. Dabei sind die Anführungszeichen in den Codefenstern richtig und wichtig!
Empfehlung: Komplizierte und lange Codezeilen immer in ein Script oder in eine Perl Sub schreiben! Mit Sonderzeichen, doppelten und einfachen Anführungszeichen kommt man schnell in sehr unübersichtliche, beinahe unlösbare Situationen. Immer die mögliche Blockade von FHEM im Hinterkopf haben!

Aufruf

Es gibt drei FHEM Kommandotypen, sie unterscheiden sich in der Verwendung der "Klammer"
  • FHEM Befehl - keine Klammer
  • "Shell Befehl" - doppelte Anführungszeichen (blockiert FHEM nicht)
  • {Perl Befehl} - geschweifte Klammer (kann FHEM blockieren)
Für externe Programmaufrufe eignen sich die beiden letzeren.
Perl kennt in sich wieder drei Funktionsaufrufe für externe (nicht Perl) Programme.
  • system() - liefert in FHEM immer "-1" zurück, Ausgaben landen im Logfile
  • qx() - liefert die Ausgabe zurück, bei Aufruf in der FHEM Oberfläche landet diese im Browserfenster
  • exec() - in FHEM nicht sinnvoll! Beendet FHEM und das aufgerufene Programm wird ausgeführt.

Kurze Fingerübung

Der Code ist für die FHEM Kommandozeile!
"echo test"
Liefert nichts im Browserfenster, schreibt test ins Logfile.
Innerhalb von Perlcode kann man das auch so verwenden:
{fhem("\"echo test\"")}
Perl system() liefert -1 im Browserfenster und schreibt test ins Logfile.
{system("echo test")}
Variante von system() mit anderer Schreibweise: {system("programm","Arg1","Arg2")} und man bekommt das gleiche Ergebnis.
{system("echo","test")}
Perl qx() liefert test im Browserfenster und schreibt nichts ins Logfile.
{qx(echo test)}
Tipp: Diese Version verwende ich gern, um in der FHEM Oberfläche mal schnell etwas im System abzufragen. Man muss dazu nicht immer ins Terminal wechseln.

Achtung: Die Pipeline (> |) der Standardausgabe funktioniert nur bei {system("echo system > test.txt")} und {qx(echo qx > test.txt)}, bei "echo kommando > test.txt" versagt sie aber!

Zwischenspiel

Wie bekomme ich Text in eine Datei? Am Besten mit der Perlfunktion FileWrite
{FileWrite("test.txt","Inhalt")}
Das Ergebnis anschauen:
{qx(cat test.txt)}

Beispiel mit Wertübergabe von FHEM

Dieses mehrzeilige Beispiel ist für die Raw Definition!
Mit dem Code Block erzeugt man:
  • ein Shellprogramm (echo $(($1*$2))) welches beide Übergabewerte multipliziert.
  • ein Dummy mit dem Reading Wert,
  • ein notify welches den Wert und state an das Shell Programm übergibt und die Rückgabe wieder den Wert schreibt.
{FileWrite("ext_Script.sh","echo \$((\$1*\$2))")}

define ext_dummy dummy
attr ext_dummy readingList Wert
attr ext_dummy room extern
attr ext_dummy setList 0 1 2 3 4 5 6 7 8 9
setreading ext_dummy Wert 1

define ext_notify notify ext_dummy:[0-9] {\
 my $a = ReadingsVal($NAME,"Wert","2");;\
 my $b = qx(bash ext_Script.sh $EVENT $a);;\
 fhem("set $NAME Wert $b")\
}
attr ext_notify room extern
Diese Beispiel ist sicher etwas konstruiert, es zeigt aber verschiedenen Ebenen (FHEM, Perl, Shell) und auch die Übergabe von Werten über Variablen. Dabei gibt es einiges zu beachten:
Sonderzeichen in Textketten werden innerhalb einfacher und doppelter Anführungszeichen je nach Ebene unterschiedlich behandelt! Bei doppelten Anführungszeichen gilt:
  • Text der mit $ oder @ beginnt wird als Perl Variable/Array aufgelöst/ersetzt. Man kann/muss die Auflösung mit dem vorangestellten \ verhindern/schützen: "\$a , name\@domain.de". 
  • Ist das Anführungszeichen selbst nur Text: \".
  • Den \ muss man selbst schützen: \\.
  • Mit \ werden auch Steuerzeichen eingeleitet. z.B. \n ist ein Zeilenumbruch.
Immer dran denken: Den Befehlstrenner ; müssen wir in der FHEM Eingabezeile auch verdoppeln/schützen!

Beispiele zur Verwendung von Variablen

Zwei Perlzeilen und zwei Ebenen. Die Ausgabe ist gleich, die Variablen unterschiedlich.
  1. $a ist eine Perl Variable und der Inhalt wird von Perl zur Shell übergeben.
  2. $a ist eine Shell Variable und wird erst in der Shell erzeugt. Es wird nichts übergeben.
{my $a = "test";;qx "echo $a"}
{qx 'a=test;;echo $a'}
Der Syntax von qx ist sehr variabel, alle Zeilen bewirken das Gleiche: den letzten Fehlercode der Shell ausgeben
{qx "echo \$?"}
{qx 'echo $?'}
{qx /echo \$?/}
{qx (echo \$?)}
{`echo \$?`}
Mit einer Ausnahme könnte auch eine Perl Variablen übergeben werden (anstatt \$? $a).
Achtung: Die Verwendung von qx("") führt zu einer Fehlermeldung, da ist offenbar ein String Terminator zu viel.

Damit es nicht zu leicht wird, kann man die String Terminatoren natürlich auch schachteln. Für die Auflösung von Perl Variablen ist dabei die äußere Klammer bestimmend!
Das erste Beispiel gibt Hallo Welt aus, das zweite nur Hallo. Die Variable $a wird im zweiten Fall nicht aufgelöst, sondern als Shell Variable interpretiert.
{my $a = "Welt";;qx "echo 'Hallo $a'"}
{my $a = "Welt";;qx 'a=FHEM;;echo "Hallo $a"'}
Ausnahmen? Verwirrung?
Im folgenden Beispiel muss der Name der Variable im Shellscript auch geschützt werden.
Im Zweifelsfall hilft nur probieren!
{system('echo "wget --quiet - \"http://192.168.178.65/esp8266?max=Aussentemperatur+\$1+C\"" > ext_Script2.sh')}

Empfehlung: Befehle kapseln

Die Verwendung von Trennzeichen im String und die bisher genannten Interpretationen von Variablen Namen in den Umgebungen führt mich zu den unbedingten Empfehlung Befehle zu kapseln! Entweder in Stringvariablen in Perl oder in Scriptdateien für andere Sprachen. Es spart jede Menge Zeit und Nerven!

Verkettung / concatenation

Perl kennt noch die String Verkettung mit Punkten.
Im ersten Fall ist die Ausgabe identisch zur Version oben, im zweiten Fall wird der Inhalt der Variablen noch in Anführungszeichen ausgegeben:
{my $a = "test";;qx "echo ".$a}
{my $a = "test";;qx "echo ".'"'.$a.'"'}
Welche Methode man verwendet ist häufig Geschmacksache, manchmal aber auch vom Inhalt der Strings und dem gewünschten Ergebnis abhängig und damit das Mittel der Wahl.

Achtung blockierend

Die Ausführung von externen Programmen mit Perl Aufrufen wird FHEM für die Laufzeit dieses Programmes unterbrechen/anhalten. Das kann unvorhersehbare Folgen haben.
Der kurzer Perl Test erzeugt für 5 sec "Warten" und dann eine Ausschrift.
{sleep 5;; return "Das war eine Pause"}
{qx "echo Das war;;sleep 5;;echo eine Pause"}
Der zweite Test führt auf Shell Ebene ein sleep aus, beide echo Befehle werden aber erst am Ende über qx an den Browser zurück gegeben.
Für einen weiteren Test erzeugen wir uns wieder ein Shell Script.
{FileWrite("ext_Pause.sh","sleep \$1\necho \$1 sec Pause")}
Dies erwartet eine Zahl und macht dann eine entsprechende Pause. Mit einem qx() Aufruf können wir das Script testen.
{qx "echo Das war;;bash ext_Pause.sh 4"}
Nach meinen Informationen, lässt sich das Verhalten mit qx() nicht ändern. Die Befehle werden immer seriell ausgeführt, Perl wartet auf die Rückgabe!
Der system() Aufruf hat andere Möglichkeiten. Bei ihm kann man mit dem & Zeichen am Ende (für die Shell typisch) die Ausführung im Hintergrund starten. Die Ausgabe im Script landet damit nach der Pause im Logfile von FHEM.
{system ("bash ext_Pause.sh 5 &")}

Aufräumen

Um die hier beim Testen erzeugten Geräte und Dateien wieder zu entfernen, kann man die beiden Zeilen einzeln in der Kommandozeile oder zusammen in der Raw Definition ausführen.
delete ext_.*
{system ("rm ext_*.sh >/dev/null")}

Ganz zum Schluss

Mal noch als "Merker" der Tipp aus dem Forum. Den baue ich bei Gelegenheit mal noch aus.
Code Block

Donnerstag, 1. Februar 2018

Setup FHEM

Es gibt einen aktuellen Artikel. Detail werden aber weitestgehend hier erklärt.

FHEM installieren ist eigentlich ziemlich einfach. Bevor meiner folgenden Anleitung gefolgt wird, sollte man sich unbedingt hier über den aktuellen Stand informieren. Mit minimalem Aufwand kann man das Setup von hier durchführen.
Alle meine Setup Schritte erfordern erhöhte Rechte. Also bitte alles in einer "sudo su" Session ausführen!
Und so setze ich diese Aufgabe praktisch in einem Script um:
# von debian.fhem.de installieren - siehe aktuelle Anleitung dort https://debian.fhem.de/
wget -qO - http://debian.fhem.de/archive.key | apt-key add -
echo "deb http://debian.fhem.de/nightly/ /" >> /etc/apt/sources.list
apt-get update
apt-get install fhem

Den zusätzlichen Eintrag in der sources.list entfernt das Setup Programm von FHEM. Alle benötigten und sinnvollen debian Pakete werden automatisch mit installiert. Ist ein systemd System vorhanden wird auch der Dienst für FHEM entsprechend installiert.

Damit ist man grundlegend fertig! Aber ein paar Dinge fehlen noch!

Das aus meiner Sicht wichtigste aktuelle Feintuning des frischen FHEM ist die Deaktivierung der USB Stick Erkennung. Dieser kleine direkte Patch auf diese Art ist nur unmittelbar nach der Installation zulässig! Später muss man diese Attribute bitte über die FHEM Oberfläche setzen.
# Den USB Check besser abschalten
/opt/fhem/fhem.pl 7072 "attr initialUsbCheck disable 1"
/opt/fhem/fhem.pl 7072 "save"

Weitere Attribute die man irgendwie braucht, kann man einfach über die Raw definition setzen. Die findet man in jeder Detail Ansicht von Definitionen ganz unten in der Mitte als Link.
attr global backup_before_update 1
attr global commandref modular
attr global title FHEM-Name
attr global sendStatistics onUpdate
attr global latitude 51.xxxxxxxxxxxxx
attr global longitude 12.xxxxxxxxxxxxx
attr global language de
attr WEB JavaScripts codemirror/fhem_codemirror.js
attr WEB codemirrorParam { "theme":"blackboard", "lineNumbers":true }
attr WEB plotfork 1
attr WEB longpoll websocket

Fast fertig - allowed

ToDo

Speziell - Mplayer Ersatz

Ich arbeite viel mit Ansagen unter anderem mit Text2Speech.
Nachtrag: Mittlerweile ist der Aufruf für play direkt mit Parametern im MplayerCall eingebaut. Das Script ist also überflüssig.
Aktuell verwende ich dieses Script um mplayer zu ersetzen. In der Quelle gibt es auch noch eine Variante mit setzen des AUDIODEV.
#!/bin/sh
# die Kommentarezeichen vor echo  fuer den Test entfernen
# echo Parameteranzahl $# > /tmp/mplay.txt

# falls volume nicht vorhanden = 1
volume=1
# Alsa Device, Volume und Dateinamen ermitteln
while [ $# -gt 0 ]
do
# echo $1 >> /tmp/mplay.txt
 if [ $1 = -ao ]
 then
  shift
#   echo $1 >> /tmp/mplay.txt
  device=$(echo $1|cut -d= -f2)
#   echo $device >> /tmp/mplay.txt
 elif [ $1 = -volume ]
 then
  shift
#  echo $1 >> /tmp/mplay.txt
   if [ $1 -lt 100 ]
   then
    volume=0.$(($1))
   fi
 elif [ -e $1 ]
 then
  file=$1
 fi
 shift
done
#echo $volume $file >> /tmp/mplay.txt
play -q -v $volume $file
exit 0

Dieses Script muss für FHEM ausführbar sein. Wenn man es im aktuellen Homdedir liegen hat (User pi) dann kann man es wie folgt als User fhem an Ort und Stelle kopieren. Automatisch mit den richtigen Rechten und Besitz.
sudo -u fhem cp mplayer.sh /opt/fhem/
chmod +x /opt/fhem/mplayer.sh
Zur Vorbereitung sind zwei Pakete erforderlich.
sudo apt-get install libdigest-sha-perl mp3wrap
In Text2Speech kann man einfach den Aufruf durch dieses Script ersetzen. Minimal kann man Text2Speech so definieren:
define MyTTS Text2Speech default
attr MyTTS TTS_MplayerCall /opt/fhem/mplayer.sh

Weitere Software Pakete installieren

Viele der Module in FHEM erfordern zusätzliche Software auf System Ebene.
Aus meiner Liste sind bisher folgende debian Pakete noch nicht installiert
sudo apt-get install avrdude libcrypt-cbc-perl libcrypt-ecb-perl libcrypt-rijndael-perl libdigest-md5-perl libimage-info-perl liblwp-useragent-determined-perl libmime-base64-perl libnet-telnet-perl libnet-upnp-perl libsoap-lite-perl libxml-parser-lite-perl libxml-parser-perl sendemail
Diese Pakete müssen mit cpan installiert werden, es gibt kein debian Paket.
sudo cpan install Crypt::Rijndael_PP

Das folgende Script ermittelt ob die Pakete schon installiert sind und gibt eine Liste der noch nicht installierten Pakete aus. Der Aufruf erfolgt mit Übergabe der zu ermittelnden Pakete.
bash software.sh paket1 paket2 paket3
Script software.sh
# Eine von beiden Zeilen auskommentieren
#echo -n "cpan install " >notinstalled.sh
echo -n "apt-get install " >notinstalled.sh
while [ $# -gt 0 ]
do
# eine von beiden Zeilen auskommentieren
#perl -M$1 -e '' 2>/dev/null
dpkg -s $1 &> /dev/null

if [ $? -eq 0 ]; then
    echo $1" is installed!"
else
    echo $1" is not installed!"
    echo -n $1" " >>notinstalled.sh
fi
shift
done

Man kann auch nur die Perl Module ermitteln, die im System installiert sind.
Aus diesem Beitrag mal abgeleitet könnte man alle Module ausgeben, die in einem System vollständig installiert sind:
dpkg -l |grep ^ii| awk '{ print $2 }'
Oder nur die Perl Module
dpkg -l |grep -i '\-perl'| awk '{ print $2 }'

Diese List könnte man von Zeilenumbrüchen befreien:
|tr -d "\r"|tr "\n" " "

...und in ein ähnliches Script wie oben einspeisen. Damit hätte man alle Pakete die nicht installiert sind. Das geht auch gleich remote von der "Quell Maschine". (Alle Pakete außer die mit "raspberry" in der Zeile)
bash software.sh $(ssh pi@remotehost "dpkg -l " |grep ^ii|grep -vi raspberry | awk '{ print $2 }' |tr -d "\r"|tr "\n" " ")
Das abgewandelte software.sh Script mit Loggingfunktion
LOG=DiffInstall.log
{
date
while [ $# -gt 0 ]
do
   if dpkg -s $1 &> /dev/null
     then
        echo $1" is installed!"
     else
        apt-get -y install $1
   fi
   shift
done
} >> $LOG 2>&1

Mittwoch, 31. Januar 2018

Installation Raspberry Pi

Es ist immer wieder ein gefragtes Thema, es ist einige Zeit ins Land gegangen, ich halte eigentlich meinen Artikel vom September 2016 aktuell - aber jetzt ist Zeit für neues! Kurz knackig und ohne Prosa soll es werden.
Achtung: Es gibt seit 2021 die Möglichkeit mit dem Raspberry Pi Imager die Konfiguration des Images vor dem ersten Start vorzunehmen. Dabei ensteht eine Datei firstrun.sh in der Boot Partition, die man einfach kopieren und für die Zukunft aufbewahren könnte.
  1. Download raspbian-lite, aktuell die Version 2017-11-29 immer wieder von hier.
  2. Mit windisk32imager auf die SD Card schreiben, es entstehen zwei Laufwerke nur das Erste ist unter Windows lesbar.
  3. Eine leere Datei mit dem Namen ssh in diesem Laufwerk erstellen, sonst geht kein ssh nach dem Start. 
  4. Bei Modellen mit Wlan die Datei wpa_supplicant.conf in dieses Laufwerk kopieren um mit Wlan starten zu können. 
  5. SD Karte auswerfen.
  6. SD Karte in Raspberry Pi stecken und booten.
  7. Monitor und Tastatur braucht man nicht. Mit Putty auf Host raspberrypi verbinden und anmelden. User pi, Passwort raspberry
  8. Dem Sicherheitshinweis folgen und passwd eingeben -> Passwort ändern!

Vorbemerkung

Alle folgende Code Blöcke benötigen root Rechte. Deshalb bitte immer am Besten per sudo su ausführen. Man kann auch einzelne Befehle mit sudo davor ausführen, allerdings wird das bei Pipe Befehlen nicht durchgereicht. Ich empfehle die benötigten Abschnitte vorher in ein oder zwei  Scriptdateien zu packen und diese gleich mit auf die SD Karte zu kopieren.
Alle Dateien müssen im Linux Format (nur lf als Zeilenende) erzeugt/editiert werden! Unbedingt einen geeigneten Editor verwenden und auf das Format beim speichern achten!

Wlan 

Eine Text Datei mit Namen wpa_supplicant.conf und diesem Inhalt bereitstellen: Entweder in die /boot Partition vorm ersten Start oder später ins Verzeichnis /etc/wpa_supplicant/ kopieren.
country=DE
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
        ssid="FRITZ!Box 7490"
        psk="12345678901234567890"
}

Meine Grundeinstellung

Zeitzone, Sprache und  Hostname ändern. Entweder Menügeführt mit
sudo raspi-config
oder per Script / Shell Befehle
# Zeitzone
timedatectl set-timezone Europe/Berlin

# Konfigurieren lokale Sprache deutsch
localedef -f UTF-8 -i de_DE de_DE.UTF-8
localectl set-locale LANG=de_DE.UTF-8 LANGUAGE=de_DE
localectl set-keymap de
setupcon

# Hostname 
hostnamectl set-hostname mymachine

#Neustart
reboot

Das war es erstmal, Damit funktioniert bei allen Pi Versionen die eingebaute Hardware, inklusive Wlan und BT beim Pi3 oder Pi Zero W.

UART

Wer für Zusatz Module die serielle Schnittstelle am GPIO braucht, muss etwas zusätzlich konfigurieren.

Bei allen Pi Modellen muss dafür der Dienst serial-getty@ttyAMA0 deaktiviert werden.
# serial-getty@ttyAMA0.service deaktivieren
systemctl stop serial-getty@ttyAMA0.service
systemctl disable serial-getty@ttyAMA0.service
systemctl mask serial-getty@ttyAMA0.service
Bei den Modellen ohne BT ist die UART per default aktiviert.
Beim den Modellen mit BT muss die UART aktiviert und BT umkonfiguriert werden.
# serielle Schnittstelle aktivieren und mit BT Schnittstelle tauschen
echo "enable_uart=1" >> /boot/config.txt 
echo "dtoverlay=pi3-miniuart-bt" >> /boot/config.txt 
echo "core_freq=250" >> /boot/config.txt 
Für diesen Abschnitt ist ein Neustart erforderlich!
# Neustart erforderlich 
reboot

BT

Die Funktion von Bluetooth kann mit hcitool überprüft werden
hcitool dev
hcitool scan
hcitool lescan


Kamera aktivieren

# Kamera aktivieren
echo "start_x=1" >> /boot/config.txt
echo "gpu_mem=128" >> /boot/config.txt
echo "disable_camera_led=1" >> /boot/config.txt
# Neustart erforderlich
reboot

Sound 


Sound ist normal aktiviert (dtparam=audio=on)
Sollen andere User Audio ausgeben dürfen, müssen sie in der Gruppe audio sein (Beispiel)
sudo gpasswd -a fhem audio

Braucht man eine Möglichkeit um mp3 Dateien und ähnliches abzuspielen wird häufig mplayer empfohlen. Eine gute Alternative ist play.
sudo apt-get update
sudo apt-get install sox libsox-fmt-all


Dateifreigabe einrichten

Braucht man eine Freigabe für Dateien auf dem Pi, ist das mit Samba schnell erledigt. Achtung diese Freigabe ist völlig offen und ohne jede Anmeldung!
apt-get install samba
# Pfad erstellen
mkdir /var/SonosSpeak
chmod 777 /var/SonosSpeak/

# Share Definition in /etc/samba/smb.conf
echo '[SonosSpeak]' >> /etc/samba/smb.conf
echo '  comment = Audio-Files for SonosPlayer to Speak' >> /etc/samba/smb.conf
echo '  path = /var/SonosSpeak' >> /etc/samba/smb.conf
echo '  browsable = yes' >> /etc/samba/smb.conf
echo '  guest ok = yes' >> /etc/samba/smb.conf
echo '  read only = no' >> /etc/samba/smb.conf

# restart Service
systemctl restart smbd
Mit dieser Installation hat man auch die Befehle net rpc usw. zur Verfügung.
Wer einen smbclient braucht muss diesen noch installieren.
apt-get install smbclient

Sudoers

Will man einem bestimmten Benutzer Möglichkeiten geben für die man "root" Rechte braucht, geht das ganz einfach.
Das folgende Beispiel gibt dem Benutzer fhem die Möglichkeit das System herunterzufahren bzw. neu zu starten.
#!/bin/bash
# ergänze eine Datei zum sudoers Script Verzeichnis /etc/sudoers.d/
File="011_fhem-nopasswd"
echo "fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt" >/etc/sudoers.d/$File
chmod 0440 /etc/sudoers.d/$File

Dienstag, 23. Januar 2018

NAS automatisch mit PC starten

Die Geräte sollte ja nur laufen wenn Sie wirklich gebraucht werden. Vom Windows PC aus ein Gerät per WOL starten geht ohne fremde Hilfsmittel.

Hauptscript

Die eigentliche Aufgabe erledigt das Script StarteNAS.ps1
Dies sendet ein magic Packet zur NAS, geht dann in eine Prüfschleife und wartet darauf, dass die IP Adresse der NAS erreichbar ist. Bei Erfolg oder Misserfolg wird der passende Balloon-Tip ausgegeben.
Die Zahl $x muss man seiner realen Umgebung anpassen, bei mir ist die NAS nach ca. 10 Schleifen Durchläufen gestartet, nach 15 Durchläufen ist irgendetwas schief gelaufen.

Hilfsmittel aus der Sammlung

Die Function Send-WOL habe ich im Scriptcenter der Technet gefunden. Ich habe diese im Script SendWOLPacket.ps1 noch mit der Variante kombiniert, einen oder mehrere PC aus einem vorhandenen Array zu starten.
Für etwas Benutzerinformation verwende ich noch das Script BalloonTipp.ps1 welches nur die Function Show-BalloonTip liefert. Wie der Name sagt, kann man damit Nachrichten im BalloonTipp Area von Windows erzeugen.
Beides sind nur allgemein verwendbare Scripts aus der Sammlung.

Installation

Alle 3 Scripts kopiert man in einen passenden Pfad, z.B. c:\Tools\Scripts
Es gibt viele Möglichkeiten ein Script bei der Anmeldung einen Benutzers zu starten, die allereinfachste ist immer noch der Autostartordner, auch wenn MS den immer weiter versteckt hat. So findet man ihn schnell:
Windows+r (Ausführen) und dort ins Fenster shell:startup eintragen und enter drücken. Schon wird der persönliche Autostartordner geöffnet.
Hier erzeugt man jetzt eine Verknüpfung mit folgendem Ziel:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -WindowStyle Hidden -ExecutionPolicy Bypass &'C:\Tools\Scripts\StarteNAS.ps1'

Tipp: Der Parameter ExecutionPolicy ignoriert die gleichnamige Einstellung im System.
Wer gerne den Link mit einem Script erzeugen möchte -> ShortCutFileErzeugen.ps1

NAS nach der Arbeit herunterfahren

Meine NAS kann eine oder mehrere IP Adressen überwachen und sich automatisch herunterfahren wenn diese IP Adressen im Netz nicht mehr aktiv sind. (Openmediavault Plugin autoshutdown)

Anmerkung: Ich habe festgestellt, dass wenn man die Scripte über Gist komplett als Zip Datei herunterlädt, sind die Inhalte beschädigt. Warum das so ist, weiß ich nicht. Also am Besten über die Raw Ansicht den Inhalt kopieren.

Donnerstag, 4. Januar 2018

WebDAV unter Windows

Auf jedem Windows Client System ist ein WebDAV Client implementiert. Damit ist der Zugriff auf WebDAV basierte Cloudspeicher ziemlich einfach. Der Client muss gestartet werden! In der Powershell relativ leicht zu kontrollieren:
get-service WebClient|Start-Service
Man kann entweder im Explorer unter "Dieser PC / Netzwerkadresse hinzufügen" einfach die WebDAV Adresse des Cloudspeichers (z.B. https://webdav.magentacloud.de) eingeben und wird nach dem Benutzerkonto gefragt.

Verbinden per Script

Man kann in der cmd Box ein Laufwerk mit dem guten alten net use Befehl verbinden:
net use Z: https://webdav.magentacloud.de /user:<user> <passwort>
Man beachte die Ausgabe, wenn man sich das Ergebnis dann mit net use anschaut :
Status       Lokal     Remote                    Netzwerk

-------------------------------------------------------------------------------
             Z:        \\webdav.magentacloud.de@SSL\DavWWWRoot
                                                Web Client Network

Die Webadresse wird anders dargestellt, das ist wichtig, wenn man die Verbindung mit Powershell erstellen will. Das cmdlet New-PSDrive braucht genau diese Schreibweise und akzeptiert die übliche https:// Darstellung nicht!
New-PSDrive -Name Z -Root \\webdav.magentacloud.de@SSL\DavWWWRoot -PSProvider FileSystem -Credential <user>
Das cmd-let akzeptiert auch kein Klartext Passwort als Übergabe, hier muss man zum PSCredential object greifen.
Vorteil: Man kann das Passwort verschlüsselt auf dem Computer speichern. Es ist nur auf diesem Computer lesbar und nicht kopierbar.

Hürden & Tücken

Laufwerk verbunden und einfach so beliebige Dateien kopieren - nicht bei Microsoft!?! Ist die Datei mal größer erhält man die Ausschrift: "Die Dateigröße überschreitet die maximal zulässige Größe" Und wie das so ist mit den Fehlermeldungen, man liest die Datei aus dem Netz und man bekommt aber die Ausschrift: "kann nicht gespeichert werden".

Größenbeschränkung

Microsoft hat die Dateigröße für den WebDAV Client auf 50000000 Byte dezimal beschränkt. Die maximale Dateigröße für WebDAV liegt bei 4 GByte ( 4.294.967.295 Byte dezimal).
Diesen Wert kann man in Powershell anzeigen bzw. setzen. Nach der Anpassung in der Registry muss der WebClient Dienst neu gestartet werden - ich habe alle notwendigen Befehle gleich in ein kleines Script gepackt.
# WebClient FileSizeLimitInBytes ueberpruefen und setzen
$Reg="HKLM:\SYSTEM\CurrentControlSet\Services\WebClient\Parameters"
$RegItem="FileSizeLimitInBytes"
$Value="4294967295"

$WebClient = get-Item -path $Reg|get-ItemProperty
Write-Verbose ("Die maximale FileSize WebDav ist derzeit: " + $WebClient.FileSizeLimitInBytes + " byte")

if (-not ($WebClient.FileSizeLimitInBytes -eq $Value)){
  Set-ItemProperty -Type DWord -Path $Reg -Name $RegItem -value $Value
  Write-Verbose ("FileSize WebDav auf $Value gesetzt")
  Restart-Service WebClient
  Write-Verbose "WebClient neu gestartet"
}

Windows Server 

Der WebDAV Client ist auf der Server Version nicht installiert. Man bekommt ihn für Windows Server 2008/2012 mit der Installation des Features desktop experience.
Install-WindowsFeature Desktop-Experience

Achtung: Leider behindert seit März 2019 das installierte Feature Desktop-Experience ganz massiv Windows Update unter Windows Server 2012. Damit ist das dort eigentlich nicht mehr verwendbar!

Beim Windows Server 2016 gibt es einen separaten Client.(das muss ich noch untersuchen) Quelle
Install-WindowsFeature WebDAV-Redirector –Restart

Etwas mehr Code

Noch ein Beispiel für den Umgang mit der WebDAV Schnittstelle. Das Script fragt beim ersten Aufruf das Passwort des Benutzer Kontos ab und speichert dieses. Wenn der Laufwerksbuchstabe schon existiert wird das Laufwerk gelöscht und das Script sofort beendet. Ansonsten wird das Laufwerk einfach verbunden. Man kann das Script also einfach zum Verbinden oder zum Löschen aufrufen.
Set-Location $PSScriptRoot
$UserName= "User Name"
$PWDFile=".\PASSWORD.txt"
$Drive="t"
$Share="\\sd2dav.1und1.de@SSL\DavWWWRootd"

#Testen ob Laufwerk schon existiert
If (test-path $Drive":\") {
    #Netzlaufwerk löschen
    Remove-PSDrive -name $Drive
    Write-verbose "Laufwerk $Drive entfernt"
    exit
    }

#Wenn Passwort nicht gespeichert vorhanden passwort abfragen und File erzeugen
If (-not (test-path $PWDFile)) { 
    $credential = Get-Credential -Credential $UserName
    $credential.Password | ConvertFrom-SecureString | Set-Content $PWDFile
    Write-Verbose "fehlendes PWD File fuer User $UserName erzeugt"
    }

#Credential aus Passwort Datei und Username erzeugen
$encrypted = Get-Content $PWDFile | ConvertTo-SecureString
$credential = New-Object System.Management.Automation.PsCredential($UserName, $encrypted)

#Netzlaufwerk verbinden
New-PSDrive -Name $Drive -Root $Share -PSProvider FileSystem -Credential $credential
Write-Verbose "Laufwerk $Drive zu Share $Share verbunden"

WebDAV als Transportmedium

So ein Cloud Speicher lässt sich ganz gut als Transportmedium verwenden. Man kopiert an einer Lokation Daten "in die Cloud" und an einer anderen Lokation holt man sie wieder "heraus". Ich habe hier ein gutes Script gefunden um Daten mit Powershell in Ordnern zu synchronisieren.