Mittwoch, 18. Januar 2017

Ein Remote Taster in FHEM mit Rückmeldung

HowTo

Einfacher Taster

Zielstellung

Ein Dummy mit klickbarem Symbol für die Weboberfläche als "Taster" für verschiedenen Aktionen.

Als erste Komponente stattet man einen dummy mit dem Attribute devStateIcon aus:
define testdummy dummy
attr testdummy devStateIcon _start:on:stop _stop:off:start
attr testdummy event-on-change-reading state
set testdummy _stop

Als Zweites braucht man ein notify welches nur auf die Events start und stop vom testdummy reagiert:
define nty_test notify testdummy:(start|stop) set $NAME _$EVENT

Diese Konstruktion wirkt wie ein toggle Schalter, das Symbol beim dummy ist klickbar und bei jedem Klick schaltet es sichtbar on und off.

Die Rückmeldung des Schalters ist damit vorhanden nur er tut nicht wirklich etwas. Zur Demonstration lassen wir "noch etwas tun":
defmod nty_test notify testdummy:(start|stop) sleep 2;;set $NAME _$EVENT

Jetzt erfolgt die Reaktion auf den Klick mit kurzer Pause, stattdessen kann man natürlich auch etwas sinnvolles tun.

Remote Taster mit Rückmeldung

Zielstellung

Ein "Taster" in der Weboberfläche, der auf einem Remote System z.B. einen Dienst startet oder beendet. Mein Taster soll erst reagieren, wenn der Befehl vom Remote System ausgeführt wurde.

Die System sind mit ssh "gekoppelt", wie das geht steht in meinem vorherigen Beitrag.

Achtung! Seit  März 2017 funktioniert die hier beschriebene Steuerung von FHEM über die Webschnittstelle nicht mehr so einfach. Bitte meinen Beitrag im März beachten.

Demo Script

Auf dem Remote System wird ein Script im Home Verzeichnis des verwendeten Remote Benutzers erzeugt/abgelegt und mit chmod +x test.sh ausführbar gemacht:
#!/bin/sh
# Parameter Übergabe
host=$1
name=$2
event=$3
# Kontrollausgabe zum Test aktivieren
# echo $host $name $event
# Zur Demo ein Sleep
sleep 3
# Abfrage und Verzweigung
case "$event" in
    start)
 # hier kann etwas spezifisches bei Start passieren
    ;;

    stop)
 # hier kann etwas spezifisches bei Stop passieren
    ;;
    *)
       exit 1
    ;;

esac
# Web Kommando an FHEM absetzen
h=$host':8083'; c='set '$name' '$status; curl --data "fwcsrf=$(curl -s -D - http://$h/fhem?XHR=1 | awk '/X-FHEM-csrfToken/{print $2}')" http://$h/fhem?cmd=$(echo $c|sed 's/ /%20/g')

exit 0

Zum Test kann man dieses Script mit ./test.sh <FHEM hostname> testdummy start aufrufen. Dabei muss sich der Status unseres Dummy ändern.

Funktioniert dieser Test, wird das notify geändert, die hostnamen müssen angepasst werden:
defmod nty_test notify testdummy:(start|stop) "ssh pi@<remote hostname> ./test.sh <FHEM hostname>  $NAME $EVENT"

An der Reaktion des Dummy hat sich nicht viel geändert, da ich im Script sleep 3 gesetzt habe dauert es jetzt 1 Sekunde länger. Dafür passiert aber etwas auf einem anderen System!

Praktische Verwendung

Das Demo Script kann so als Grundgerüst verwendet werden. Im einfachsten Fall fügt man an den entsprechende Stellen einfach nur Befehle ein. Komplizierter wird es, wenn man z.B. vor Rückkehr (absetzen des Befehls an FHEM) wirklich überprüfen will/muss ob die gewünschet Aktion auch gelaufen ist.
Das notify kann für mehrere dummy verwendet werden.

Dienst steuern

Um einen Dienst zu starten und zu stoppen muss das Script und der dummy etwas angepasst werden. Zum Testen habe ich meinen Dienst aus diesem Beitrag genommen. Der Name muss entsprechend angepasst werden. Man könnte den Dienstnamen auch im notify übergeben.
Der Steuerbefehl (event) wird nochmal überprüft und übergeben. Nach kurzer Wartezeit wird der Status abgefragt und dieser direkt an FHEM übergeben. Der Status ist also direkt im dummy sichtbar
#!/bin/sh
# Parameter Übergabe
host=$1
name=$2
event=$3
service=<Dienst Name>
# Abfrage und Verzweigung
case "$event" in
    start|stop)
   # Sicherstellen das nur zulässige Events verwendet werden
   sudo systemctl $event $service 
   sleep 2
          status=$(systemctl is-active $service)
   # Web Kommando an FHEM absetzen (neu mit csrfToken)
   h=$host':8083'; c='set '$name' '$status; curl --data "fwcsrf=$(curl -s -D - http://$h/fhem?XHR=1 | awk '/X-FHEM-csrfToken/{print $2}')" http://$h/fhem?cmd=$(echo $c|sed 's/ /%20/g')

    ;;

    *)
      exit 1
    ;;

esac

exit 0

Wenn der Dienst läuft wird er als active erkannt, wenn er gestoppt ist liefert er unknown zurück. Das Mapping des devStateIcon wird einfach angepasst.

attr testdummy devStateIcon active:on:stop unknown:off:start

Montag, 16. Januar 2017

Per ssh Remote Befehle direkt ausführen

Die Secure Shell (ssh) ist auf den meisten Linux System aktiviert. Bedienung und Administration sind ohne ssh kaum vorstellbar. Was da alles so geht zeigt dieser nette Artikel.
Oft will man Dinge Remote per Befehl ausführen, ohne interactive Anmeldung. Einfach Befehl absetzen und fertig, dabei aber sicher und ohne "alle Tore aufzureißen". Glücklicherweise ermöglicht ssh nicht einfach die Übergabe der Benutzerpasswortes im Klartext.
Alle Beschreibungen die ich bisher fand, waren ziemlich kompliziert und ich habe sie am Ende nicht verstanden. Eigentlich ist es ganz einfach, vielleicht schreibt das deswegen kaum jemand auf. Ich beschreibe hier das Verfahren mit rsa Schlüsselaustausch ohne "passphrase". Damit ist sichergestellt, dass ein Benutzer auf einem lokalen System einen anderen Benutzeraccount auf einem Remote System ohne Abfrage eines Passwortes verwenden kann und dort Befehle ausführen kann, da er vorher mit den Schlüssel dazu autorisiert wurde.

Beispiel Scenario

Lokaler Host:
System: Raspbian jessie-lite; Benutzer: Pi - im Terminal angemeldet

Remote Host:
System: Raspbian jessie-lite; Benutzer: Pi - nicht angemeldet

Einrichtung

Alle Aktionen finden im Terminal des "Lokalen Hosts" statt.
# Die Frage nach der passphrase wird zweimal mit enter quittiert, also die passphrase bleibt leer
ssh-keygen -t rsa 
# passwort des remote users wird abgefragt
ssh-copy-id -i ~/.ssh/id_rsa pi@<remote-system>
Achtung!
Es kann sein, dass ssh-copy-id auf dem System nicht verfügbar ist! 
Das Tool ssh-copy-id unterstützt nur .ssh auf dem Zielsystem! Bei OpenWrt z.B. schlägt es sowohl als Quelle als auch Ziel fehl.
In beiden Fällen geht der Einzeiler aus diesem Artikel.

Verwendung

Das war es schon! Jetzt kann man remote z.B. den Status eines Dienstes abfragen, die Ausgabe kommt ins lokale Terminal!
ssh pi@<remote-system> 'sudo systemctl status myservice'

Dienst Benutzer verwenden

Serviceuser sind meist mit passwortlosem Login ausgestattet und die interaktive Anmeldung ist verhindert (z.B. Benutzer fhem). Um für diese Benutzer eine ssh remote Anmeldung zu erstellen sind noch zusätzliche Schritte nötig. Zunächst mal das Login ermöglichen und ein passwort erstellen:
sudo cp /etc/passwd /etc/passwd.sav
sudo nano /etc/passwd
# in der Zeile: fhem:x:999:20::/opt/fhem:/bin/false 
# von /bin/false auf /bin/bash ändern und speichern

Dann für den Benutzer fhem ein Kennwort eingeben
sudo passwd fhem

Nach dem Erstellen des rsa Schlüssels und Test wieder den alten Zustand herstellen
sudo cp /etc/passwd.sav /etc/passwd

Hier noch alle Schritte für den Benutzer fhem in effizienter Form. Ich habe dabei den manuellen Vorgang mit dem Editor nano durch den nicht interaktiven Stream Editor (sed) ersetzt!
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            # Speichert automatisch in /opt/fhem/
# Achtung ssh-copy-id funktioniert nicht immer! Alternative siehe oben
ssh-copy-id -i ~/.ssh/id_rsa <user>@<remote-system> # gleich den angebotenen Test machen
ssh <user>@<remote-system>   # 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
Wenn man es für einen anderen Benutzer (z.B. Pi) schon gemacht hat, geht es eventuell auch einfacher: Artikel im Forum Ich habe das noch nicht getestet!

OpenSSH (Cygwin) für Windows

Mittlerweile ist dieser Abschnitt überholt, ich lasse ihn aber stehen. Am Ende habe ich die Deinstallation ergänzt. Es gibt als zukunftsorientierte Alternative, eine funktionsfähige Anleitung in meinem "Windows hat jetzt ssh" Artikel
Es gibt mehrere OpenSSH Implementierungen für Windows. Die einzige die wirklich wie gewollt funktioniert war für mich Cygwin. Die Installation läuft mehrstufig ab, hier habe ich eine gute Anleitung gefunden.

Installation

Zunächst lädt man nur eine kleine setup-x86_64.exe herunter, diese führt eine Installation mit nachladen aus dem Internet durch. Im ersten Schritt wird der Pfad für die Installation selbst bestimmt, von dort aus könnten weitere Installationen vorgenommen werden.
Dann werden die zu installierenden Pakete ausgewählt, per default ist gar nichts ausgewählt. Man kann mit search und "ssh" die Auswahl erleichtern.

Da ich kein komplettes System brauche wähle ich nur ssh aus. Die dazu notwendigen Pakete wählt das Setup Programm automatisch. Die Installation des Programmes selbst erfolgte bei mir in c:\cygwin64.

Nach der Installation hat man ein Icon "Cygwin64 Terminal" auf dem Desktop, der wird gestartet und ein "vertrautes" Terminalfenster öffnet sich. Dort wird mit ssh-host-config der ssh Daemon installiert.
Es werden eine Reihe Fragen gestellt, die ich so beantwortet habe:
*** Query: Should StrictModes be used? (yes/no) yes
*** Query: Should privilege separation be used? (yes/no) yes
*** Query: new local account 'sshd'? (yes/no) yes
*** Query: Do you want to install sshd as a service?
*** Query: (Say "no" if it is already installed as a service) (yes/no) yes
*** Query: Enter the value of CYGWIN for the daemon: []
...
*** Info: This script plans to use 'cyg_server'.
*** Info: 'cyg_server' will only be used by registered services.
*** Query: Do you want to use a different name? (yes/no) no
*** Query: Create new privileged user account '<host>\cyg_server' (Cygwin name: 'cyg_server')? (yes/no) yes
*** Query: Please enter the password:
*** Query: Reenter:

Jetzt muss der Dienst gestartet werden: 
$ net start sshd
CYGWIN sshd wird gestartet.
CYGWIN sshd wurde erfolgreich gestartet.

Damit der ssh Server nicht durch die Firewall ausgebremst wird, kann man mit folgendem Powershell Befehl noch die entsprechende Ausnahme definieren:
New-NetFirewallRule -Protocol TCP -LocalPort 22 -Direction Inbound -Action Allow -DisplayName SSH
Damit ist die Installation beendet.

Besonderheiten:
  • Der Benutzer Name wird Case Sensitiv verarbeitet, Administrator muss also groß geschrieben werden. 
  • Alle Pfadnamen in Befehlen müssen mit doppelten Backslash geschrieben werden.

Und siehe da, man kann  mit "powershell C:\\Tools\\Scripts\\SendeEmailV2.ps1" auch Powershell Befehle ausführen.
Und natürlich geht der folgende Befehl direkt aus der FHEM Kommandozeile.
"ssh @ 'powershell C:\\Tools\\Scripts\\SendeEmailV2.ps1'"

Die Pfade von Windows müssen aber innerhalb von ' ' stehen! Will man noch Variablen übergeben dürfen die nicht innerhalb ' ' stehen.
"ssh @ 'powershell C:\\Tools\\Scripts\\SendeEmailV2.ps1' $NAME $EVENT"

Deinstallation

das Setup erzeugt leider keine Deinstallation, man muss es manuell bewerkstelligen. Die Grundlage für den folgenden Code habe ich aus dem Cygwin Wiki.
# Den Service anhalten und entfernen
# Remove-Service existiert erst ab Powershell 6
Get-Service -DisplayName CYGWIN*|Stop-Service
C:\cygwin64\bin\cygrunsrv -E sshd
C:\cygwin64\bin\cygrunsrv -R sshd
# Prüfen ob der Service entfernt ist
Get-Service -DisplayName CYGWIN*

# cygwin Benutzer löschen
Get-LocalUser sshd|Remove-LocalUser
Get-LocalUser cyg*|Remove-LocalUser

# Registry Key löschen und prüfen
Test-Path HKLM:\Software\Cygwin
gci HKLM:\Software\Cygwin
Remove-Item HKLM:\Software\Cygwin

# Firewall Regel löschen
get-NetFirewallRule -DisplayName ssh*|Remove-NetFirewallRule

# Noch ein paar Pfade/Dateien löschen, einfach mit dem explorer
# C:\cygwin64, User profil von sshd und cyg*, Verknüpfungen auf dem Desktop 

Public Key für die Windows Anmeldung einrichten

Die Sache mit dem Public Key funktioniert nicht ganz so einfach wie unter Linux.
Aber ich war nicht der erste und habe hier ein gute Anleitung gefunden. Diese ist ziemlich umfangreich, deshalb habe ich diese Schritte herausgepickt:

Homedirectory auf Windows vorbereiten. 

Am einfachsten mit Putty am neuen Windows Server ssh anmelden. Dann steht man gleich im Anmelde Fenster im Homedirectory des Benutzers.
ssh <user>@<remote-system>
mkdir .ssh
cd .ssh
mkdir otherkeys

Public Key kopieren

Jetzt vom Raspberry: Achtung! Die Datei authorized_keys wird mit dem Befehl neu erzeugt/überschrieben:
su fhem
scp ~/.ssh/id_rsa.pub <user>@<remote-system>:.ssh/authorized_keys

Das wars, die ssh Anmeldung ohne Passwort sollte funktionieren.

Ärger mit known_hosts

Hat man den Ziel Host unter altem Namen oder gleicher IP neu installiert, funktioniert der alte Eintrag in der Datei .ssh/known_hosts nicht mehr. Der lässt sich nicht einfach überschreiben, man muss ihn vorher löschen. Hat man Hostname und IP-Adresse verwendet, existieren mehrere Einträge!
ssh-keygen -R <Hostname>
ssh-keygen -R <IP Adresse>

Hat man den Namen oder die IP Adresse geändert, muss ein neuer Eintrag geschrieben werden. Dazu muss man nicht zwingend wieder unter anderem Namen (fhem) angemeldet sein.
Diese Methode eignet sich auch, wenn man den Eintrag in der known_host ohne Benutzer-Interaktion vornehmen will/muss.
sudo su
ssh-keyscan -H <Hostname/IP-Adresse> >> /opt/fhem/.ssh/known_hosts

Die Einträge lassen sich mit ssh-keygen auch auflisten, im Beispiel vom aktiven User
ssh-keygen -l -f ~/.ssh/known_hosts

Sicherheit

Wie sicher ist das Ganze?

Per default erzeugt ssh-keygen 2048 bit Schlüssel, diese gelten als sicher. Die Dateien sind im Benutzerverzeichnis gesichert. Nur der öffentliche Schlüssel ist von anderen Benutzern lesbar. Der Remotehost ist verschlüsselt abgelegt.
-rw------- 1 pi pi 1679 Jan 16 14:06 id_rsa
-rw-r--r-- 1 pi pi  392 Jan 16 14:06 id_rsa.pub
-rw-r--r-- 1 pi pi  444 Jan  8 19:21 known_hosts

Lässt sich die Sicherheit erhöhen?

ssh-keygen -t rsa -b 4096
Private key in pkcs8 wandeln. -> https://www.mittwald.de/blog/mittwald/howtos/ssh-key-erstellen
Schlüssel mit passphrase erzeugen und ssh-agent verwenden oder hier.

In dem Artikel  ist auch beschrieben, wie man den ssh  Zugang zu Windows für Passwort Abfragen sperren kann, dann ist nur noch Anmeldung per Public Key möglich.

Falsche Rechte im Home Directory

Das Home Directory hat per default die Rechte Maske 755. Die obige Procedure setzt zwar die Rechte auf die .ssh Dateien, ist aber die Ordner Struktur darüber mit falschen Berechtigungen ausgestattet, wird eine Verwendung der Key Dateien vom System offenbar als "Unsicher" verhindert. Falls etwas nicht funktioniert, überprüfen:
/home/pi/.ssh:

drwx------ 2 pi pi 4096 Nov 24 17:50 .
drwxr-xr-x 3 pi pi 4096 Oct 25 14:32 ..
-rw------- 1 pi pi 1679 Jan 16  2017 id_rsa
-rw-r--r-- 1 pi pi  392 Jan 16  2017 id_rsa.pub
-rw------- 1 pi pi 1552 Nov 24 17:49 known_hosts
Siehe Beitrag im Forum.

Sudo und Passwortabfrage

Beim Benutzer pi wird das sudo Passwort nicht abgefragt, bei anderen Benutzern schon!? Ganz einfach: Die Datei /etc/sudoers enthält am Ende die Zeile #includedir /etc/sudoers.d obwohl auch in dieser Datei das Doppelkreuz für auskommentiert steht, ist es in dieser Zeile nicht so! Diese Zeile bewirkt, dass alle weiteren Dateien im Verzeichnis /etc/sudoers.d importiert werden. Unter raspbian gibt es dort eine Datei /etc/sudoers.d/010_pi-nopasswd diese enthält genau die eine Zeile, womit typischerweise die Passwortabfrage für sudo "für alles" ausgeschaltet wird.

Dienst unter Raspbian einrichten

Wahrscheinlich passt das Thema unter jedem debian System, ich hab es aber auf dem Raspberry unter Jessie getestet.
Mein Ziel war es, selbst einen Dienst einzurichten und dabei die Unterschiede zwischen wheezy (SysVinit) und Jessie (SystemD) zu lernen.
Eine gute Beschreibung für meinen Start habe ich hier gefunden. Python ist wie Perl als Grundlage im Debian System schon vorhanden, man braucht also keine weitere Installation. Das Python Script aus dem genannten Artikel ist eine gute Grundlage und ich habe es etwas modifiziert.
Alle Scripte müssen im Unix Format (nur lf als Zeilenwechsel) gespeichert werden!

Das Demo-Script

Es schreibt kontinuierlich in eine "Tages"-Logdatei im /tmp Verzeichnis und kann bei normalen Start entweder mit ctrl-c oder im Hintergrund einfach mit kill beendet werden. Das Script demonstriert ein paar nützliche Techniken, ich habe lediglich den Abbruch am Ende entfernt und das Intervall auf eine Minute heraufgesetzt. So läuft das Script "ewig". Im Script selbst ist das Wichtigste dokumentiert.

#!/usr/bin/env python

import logging
import logging.handlers
import argparse
import sys
import time  # this is only being used as part of the example

# Defaults
LOG_FILENAME = "/tmp/myservice.log"
LOG_LEVEL = logging.INFO  # Could be e.g. "DEBUG" or "WARNING"

# Define and parse command line arguments
parser = argparse.ArgumentParser(description="My simple Python service")
parser.add_argument("-l", "--log", help="file to write log to (default '" + LOG_FILENAME + "')")

# If the log file is specified on the command line then override the default
args = parser.parse_args()
if args.log:
        LOG_FILENAME = args.log

# Configure logging to log to a file, making a new file at midnight and keeping the last 3 day's data
# Give the logger a unique name (good practice)
logger = logging.getLogger(__name__)
# Set the log level to LOG_LEVEL
logger.setLevel(LOG_LEVEL)
# Make a handler that writes to a file, making a new file at midnight and keeping 3 backups
handler = logging.handlers.TimedRotatingFileHandler(LOG_FILENAME, when="midnight", backupCount=3)
# Format each log message like this
formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s')
# Attach the formatter to the handler
handler.setFormatter(formatter)
# Attach the handler to the logger
logger.addHandler(handler)

# Make a class we can use to capture stdout and sterr in the log
class MyLogger(object):
        def __init__(self, logger, level):
                """Needs a logger and a logger level."""
                self.logger = logger
                self.level = level

        def write(self, message):
                # Only log if there is a message (not just a new line)
                if message.rstrip() != "":
                        self.logger.log(self.level, message.rstrip())

# Replace stdout with logging to file at INFO level
sys.stdout = MyLogger(logger, logging.INFO)
# Replace stderr with logging to file at ERROR level
sys.stderr = MyLogger(logger, logging.ERROR)

i = 0

# Loop forever, doing something useful hopefully:
while True:
        logger.info("The counter is now " + str(i))
        print "This is a print"
        i += 1
        time.sleep(60)

SysVinit konfigurieren 

Init-Script

Ich möchte den Dienst unter einem normalen User laufen lassen und nicht als root (default). Im Pfad /etc/init.d/ befinden sich die Scripte welche zur Dienste Steuerung verwendet werden. Dort gibt es auch ein Script Namens skeleton, welches als Template verwendet werden kann. Also zunächst mal das Steuerungs Script, wiederum aus dem eingangs erwähnten Artikel, leicht modifiziert. Wie zu sehen ist, soll der Dienst unter dem User pi ($DAEMON_USER) und im Homedirectory ($DIR) vom User laufen.

#!/bin/sh

### BEGIN INIT INFO
# Provides:          myservice
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Put a short description of the service here
# Description:       Put a long description of the service here
### END INIT INFO

# Change the next 3 lines to suit where you install your script and what you want to call it
DIR=/home/pi
DAEMON=$DIR/myservice.py
DAEMON_NAME=myservice

# Add any command line options for your daemon here
DAEMON_OPTS=""

# This next line determines what user the script runs as.
# Root generally not recommended but necessary if you are using the Raspberry Pi GPIO from Python.
DAEMON_USER=pi

# The process ID of the script when it runs is stored here:
PIDFILE=/var/run/$DAEMON_NAME.pid

. /lib/lsb/init-functions

do_start () {
    log_daemon_msg "Starting system $DAEMON_NAME daemon"
    start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --chuid $DAEMON_USER --startas $DAEMON -- $DAEMON_OPTS
    log_end_msg $?
}
do_stop () {
    log_daemon_msg "Stopping system $DAEMON_NAME daemon"
    start-stop-daemon --stop --pidfile $PIDFILE --retry 10
    log_end_msg $?
}

case "$1" in

    start|stop)
        do_${1}
        ;;

    restart|reload|force-reload)
        do_stop
        do_start
        ;;

    status)
        status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $?
        ;;

    *)
        echo "Usage: /etc/init.d/$DAEMON_NAME {start|stop|restart|status}"
        exit 1
        ;;

esac
exit 0

Scripte kopieren und einrichten

Mit winscp werden die Scripte ins Home Verzeichnis von pi kopiert. Dann mit putty ein ssh Terminal öffnen und das Init-Script an Ort und Stelle kopieren, Rechte setzen und den Dienst einrichten.
sudo cp myservice.sh /etc/init.d/
chmod +x myservice.py
chmod +x /etc/init.d/myservice.sh
sudo update-rc.d myservice.sh defaults
Jetzt kann man mit den üblichen Befehlen oder durch direkten Script Aufruf den Dienst starten, abfragen und beenden.
sudo /etc/init.d/myservice.sh start
service myservice status
sudo service myservice stop
Will man den Dienst wieder entfernen, hilft uns update-rc.d mit den Optionen disable und remove.

SystemD

SystemD wird unter jessie mit installiert und läuft kompatibel und transparent. Man kann also sofort den Dienst auch mit systemctl <start|status|stop> myservice kontrollieren. Ich will aber nun die "alte" Einrichtung deaktivieren und den Dienst unter SystemD einrichten.
Ein Dienst in SystemD wird mit sogenannten Unit Files eingerichtet.

1. Variante: einfach das init.d Script verwenden

Im FHEM Forum gibt es ein HowTo wie man den existierenden Service in einen SystemD Service umwandelt. Die folgende Datei wird als myservice.service gespeichert und mit winscp wieder nach /home/pi übertragen.
Wie man sieht, wird dabei gleich das alte SysVinit Script recycelt.

[Unit]
Description=Test myservice

[Service]
Type=forking
ExecStart=/etc/init.d/myservice.sh start
ExecStop=/etc/init.d/myservice.sh stop

[Install]
WantedBy=multi-user.target

Zunächst also den Dienst wieder entfernen, die Datei nach /etc/systemd/system kopieren und systemd über die Änderung informieren.
sudo update-rc.d myservice.sh disable
sudo cp myservice.service /etc/systemd/system/
sudo systemctl --system daemon-reload
Jetzt kann man zur Probe den Dienst mit systemctl <start|status|stop> myservice starten. Wenn alles funktioniert muss er noch aktiviert werden.
sudo systemctl enable myservice

2. Variante: extra Startscript verwenden 

Hierauf basierend habe ich mir ein universelles Startscript erstellt. Zumindest mit meinem Pythonscript funktioniert das einwandfrei. Im Endeffekt ist es aber in der Funktion dem SysVinit adäquat. Die Funktion ist anders realisiert, ich finde es besser lesbar und der SysVinit Abschnitt am Anfang fehlt. Letztendlich könnte man sogar den Scriptaufruf als Parameter übergeben.
#!/bin/bash

PID=""
script="python myservice.py"

function get_pid {
   PID=`pidof $script`
}

function stop {
   get_pid
   if [ -z $PID ]; then
      echo "server is not running."
      exit 1
   else
      echo -n "Stopping server.."
      kill -9 $PID
      sleep 1
      echo ".. Done."
   fi
}


function start {
   get_pid
   if [ -z $PID ]; then
      echo  "Starting server.."
      $script &
      get_pid
      echo "Done. PID=$PID"
   else
      echo "server is already running, PID=$PID"
   fi
}

function restart {
   echo  "Restarting server.."
   get_pid
   if [ -z $PID ]; then
      start
   else
      stop
      sleep 5
      start
   fi
}


function status {
   get_pid
   if [ -z  $PID ]; then
      echo "Server is not running."
      exit 1
   else
      echo "Server is running, PID=$PID"
   fi
}

case "$1" in
   start)
      start
   ;;
   stop)
      stop
   ;;
   restart)
      restart
   ;;
   status)
      status
   ;;
   *)
      echo "Usage: $0 {start|stop|restart|status}"
esac

Praktisch gesehen ist der Unit Teil bei Systemd vom Startscript getrennt. Basierend auf dieser Dokumentation  habe ich  mal eine ziemlich "aufwändige" Variante erstellt. Hierbei wird start|stop|restart durch das obige Script gesteuert.

[Unit]
Description=Test myservice
After=network.target

[Service]
Type=forking
User=pi
WorkingDirectory=/home/pi
ExecStart=/home/pi/server.sh start
ExecStop=/home/pi/server.sh stop
ExecReload=/home/pi/server.sh restart
KillMode=none

[Install]
WantedBy=multi-user.target

3. Variante: Kurz und knapp einfach ein Unitfile erstellt

Hier übernimmt systemd die komplette Steuerung. Überraschenderweise funktioniert dies auch mit meinem Endlosscript. Ich habe die Anregung dazu von hier. Dort ist noch ein besseres Beispiel mit einem kleinem Webserver als Testscript dargestellt. Lässt man den User= Eintrag weg startet der Dienst als root.

[Unit]
Description=Test systemd myservice

[Service]
User=pi
ExecStart=/home/pi/myservice.py
StandardOutput=null

[Install]
WantedBy=multi-user.target

Sonntag, 15. Januar 2017

Code Blöcke formatieren und hervorheben

Der Editor von Blogger.com ist für mich für die meisten Dinge völlig ausreichend, allerdings möchte ich die Codeblöcke in meinem Blog gut lesbar formatieren.
Ich habe mehrere Möglichkeiten gefunden dies zu tun, leider ist so etwas ganz einfaches nicht dabei. Quasi als meinen Notizzettel, habe ich die Möglichkeiten, die ich so gefunden habe mal aufgeschrieben.
Generell unschön finde ich, dass man für alle Varianten vom "Verfassen" Modus in den "HTML" Modus wechseln muss, aber nur so kann man den für die Formatierung notwendigen HTML Code direkt eingeben. Eine andere Möglichkeit habe ich nicht gefunden.

Copy & Paste

Zunächst mal gibt es ein paar Seiten, die bieten einen "Code Formatierer" an.
Man kopiert seine Code Zeilen in die Zwischenablage, wechsel auf die Seite mit dem Formatierer und fügt sie in ein spezielles Fenster wieder ein. Man kann hier meist ein paar Optionen einstellen und beim Drücken eine Knopfes wird in einem weiteren Fenster die Formatierung gezeigt und in einem Dritten kann man den HTML Code kopieren und die Formatierten Codezeilen so einfach in seine Blog an die gewünschte Stelle einfügen.
Das geht eigentlich alles sehr simpel und benötigt überhaupt keine Vorbereitung.

Eine relative schlichte Optik kann man auf dieser Seite erzeugen:
http://codeformatter.blogspot.de/2009/06/how-to-format-my-source-code-for.html

 Codezeile eins 
 Codezeile zwei

Sehr auffällig und bunt geht es auf dieser Seite:
http://hilite.me/

1
print 'hello world!'

Template oder Vorlage editieren

Etwas aufwendiger ist es die Stylesheets zu editieren. Dabei wird ein Stück HTML Code in der Vorlage zum Blog (die austauschbar ist und die Optik des Blogs wesentlich bestimmt) eingebaut und an entsprechender Stelle wird dann lediglich noch ein HTML-Tag eingefügt. Der Code zur Formatierung wird zentral abgelegt und der Code Block bloß mit einem Kurzen Tag gekennzeichnet. Das hat noch den Vorteil, man kann das Aussehen der Formatierung an einer Stelle für den gesamten Blog ändern. Dazu ein einfaches Beispiel, welches auf diesen Artikel basiert.

Mit Hilfe von dem Tag textarea kann man eine kleine Box einfügen:
Einfach folgenden Code in der HTML Ansicht einfügen
<textarea name="textarea" cols="40" rows="4" wrap="VIRTUAL">
YOUR CODE GOES HERE
</textarea>
Das Ergebnis sieht so aus:



Der Vorteil dieses kleinen Textrahmens ist, das man ihn in der normalen Editor Ansicht sieht. Er hat in der Editor Ansicht auch "editierende" Eigenschaften:
Man kann an der kleinen Ecke unten rechts ziehen und den Rahmen optisch anpassen. Es wird dabei automatisch dieser HTML Code zwiswchen rows= und wrap eingefügt:
style="height: 64px; margin: 0px; width: 301px;"
Man kann hier eine definierte Höhe und Breite eintragen, oder anstatt mit Pixeln(px) auch mit auto oder 100% arbeiten.

Um eine Codebox als CSS in den Blog einzufügen, muss man folgendes tun:

  1. Am Dashboard anmelden und links auf Vorlage navigieren.
  2. Unter der Vorlage auf Anpassen klicken
  3. Links oben auf Erweitert und daneben nach unten scrollen und auf Add CSS klicken
  4. In dem Fenster Benutzerspezifisches CSS hinzufügen gibt man den unten stehenden Code Block ein
  5. Anschließend oben rechts auf "Auf Blog anwenden" drücken.

Jetzt kann man Seinen Code Block in der HTML Ansicht einfach mit diesen Tags "einrahmen":



Großer Nachteil: Den Erfolg sieht man erst in der Vorschau, in der normalen Editor Ansicht sieht man leider nichts und man muss verdammt aufpassen wenn man mal was korrigiert. Zwei Parameter sorgen für wichtige Eigenschaften:
  • overflow: auto - bewirkt, dass Scrollbalken angezeigt werden, sobald die max-height überschritten wurde. 
  • white-space: nowrap - sorgt dafür, dass kein automatischer Textumbruch stattfindet.

Code Block

Java Script einbetten

Eine relativ elegante Methode ist die Formatierung mit dem Javascript Prettify, der Quellcode und Beschreibung findet man hier: https://github.com/google/code-prettify
Als erstes muss man den Script Code im Blog verfügbar machen. Dazu muss man nicht die Vorlage editieren, man kann es einfach im Layout einbetten. Dazu fügt man im Layout (Dashboard/Layout) einfach an unauffälliger Stelle ein Gadget hinzu. Man wählt das Gadget "HTML/JavaScript konfigurieren" aus der Liste aus, gibt den Titel PrettyPrint ein und im Content wird folgender Code eingefügt:
<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>

Die Code Blöcke werden in der HTML Ansicht einfach in



eingepackt. Jetzt wird abhängig von der Programmiersprache auch entsprechend hervorgehoben.

Feintuning

Kombination aus Prettify und Codeformatter

Damit der Text gut lesbar bleibt, sollten Code Passagen nicht allzu lang sein, bzw. sollte man sie im Text in Scrollboxen optisch einkürzen. Dazu verwende ich einfach noch die style Eigenschaft aus dem Codeformatter. Das style Attribute height:auto passt das Fenster der Anzahl Zeilen automatisch an, das Attribute max-height:300px; begrenzt die Box und fügt Scrollbalken ein.
<pre class="prettyprint" style="height: auto; max-height: 300px; overflow: auto; width: auto;">
Code Block
</pre>
Der style Teil kann mit in das beschriebene Gadget eingefügt werden:
<style>
pre {
  height: auto;
  max-height: 300px;
  overflow: auto;
  width: auto;
}
</style>
Damit der Code einfach markiert werden kann wird noch ein spezieller Code tag eingefügt:
<pre class="prettyprint"><code contenteditable="true">Code Block
</code></pre>

Quelle


Hier ein Beispiel, dies ist kein funktionierender Code!:

#!/bin/bash

# Laufzeit des Scripts messen 
# Zeitmessung Start.
REAL_STARTTIME=$(date +%s) #(($STARTTIME - $PRE_NETWORK_DURATION))
echo ""
echo "Installation started at $(date --date="@$REAL_STARTTIME" --utc)."

#Grundlage für FHEM installieren
apt-get update && apt-get -y install libdevice-serialport-perl libwww-perl libio-socket-ssl-perl
#Meine Pakete installieren
apt-get -y install bluez libcrypt-rijndael-perl libdigest-sha-perl libgd-graph-perl libgd-text-perl libimage-info-perl libimage-librsvg-perl libjson-perl libjson-xs-perl libmime-base64-perl libnet-ssleay-perl libnet-telnet-perl libnet-telnet-perl libnet-upnp-perl libsoap-lite-perl libsoap-lite-perl libxml-parser-lite-perl mplayer msttcorefonts samba samba-common-bin sendEmail telnet

# Manuelle Installation
# wget https://debian.fhem.de/fhem.deb
# dpkg -i fhem.deb

# von debian.fhem.de installieren 
# Erstmal https für apt nachinstallieren
# https Transport installieren und Sourcellisten sichern
apt-get -y install apt-transport-https
wget -qO - https://debian.fhem.de/archive.key | apt-key add -
cp /etc/apt/sources.list /etc/apt/sources.list.bak
# Manuelle Installation
# wget https://debian.fhem.de/fhem.deb
# dpkg -i fhem.deb

# von debian.fhem.de installieren 
# Erstmal https für apt nachinstallieren
# https Transport installieren und Sourcellisten sichern
apt-get -y install apt-transport-https
wget -qO - https://debian.fhem.de/archive.key | apt-key add -
cp /etc/apt/sources.list /etc/apt/sources.list.bak
# Manuelle Installation
# wget https://debian.fhem.de/fhem.deb
# dpkg -i fhem.deb

# von debian.fhem.de installieren 
# Erstmal https für apt nachinstallieren
# https Transport installieren und Sourcellisten sichern
apt-get -y install apt-transport-https
wget -qO - https://debian.fhem.de/archive.key | apt-key add -
cp /etc/apt/sources.list /etc/apt/sources.list.bak

# reboot

Oder mit Zeilenummer:
<pre class="prettyprint linenums" style="height: auto; max-height: 300px; overflow: auto; width: auto;">
Code Block
</pre>

Formatierung über Gist und GitHub

Für Powershell funktioniert prettyprint leider nicht sehr gut. Ich habe eine einfache Möglichkeit hier gefunden https://gist.github.com/ Die ist hier kurz beschrieben.
Leider ist die Hervorhebung von Powershell auch nicht optimal. Größter Nachteil ist: Beim Erstellen des Blogbeitrages sieht man vom Code gar nichts.

Um die Höhe der Scriptfenster etwas zu begrenzen kann man im css Bereich noch etwas konfigurieren (Blogbeitrag):

.gist .blob-wrapper.data {
   max-height:300px;
   overflow:auto;
}


Ob man das Alles noch eleganter machen kann, weiß ich derzeit noch nicht.

Zeilenumbruch

Manchmal ist es nützlich in HTML Ansicht Zeilenumbrüche einzufügen um an einer definierten Stellen Leerräume in der Normalen Ansicht zu haben. Einfach diesen Tag einfügen
<br />


Freitag, 6. Januar 2017

Umzug von FHEM

Die alte Hardware ist zu schwach, defekt oder warum auch immer - das System soll neu gemacht werden!?
Ausgangszustand:
  • Raspberry Pi2, 
  • Raspbian Wheezy, 
  • Probleme mit der SSL Lib beim https Zugriff (SSL Version SSLv2 not supported), ist mit jessie behoben.
Zielzustand:
  • Raspberry Pi3
  • Raspbian Jessie Lite

Geht relativ einfach, wenn man einige Vorbereitungen trifft. Der grobe Fahrplan sieht so aus:
  1. Auf neuer Hardware ein neues System installieren.
  2. Alle benötigten Tools und Module (debian Pakete) nachinstallieren.
  3. FHEM als Grundlage installieren, eventuell Details testen (z.B. SSL).
  4. Backup und shutdown aktuelles FHEM System auf Pi2
  5. Transfer der Backupdatei auf Pi3
  6. Restore und Start von FHEM auf dem Pi3
  7. Test ob System einwandfrei läuft, wenn ja alles gut, wenn nein eventuell erstmal Restart FHEM auf Pi2 und in Ruhe untersuchen -> nochmal ab Schritt 4 bis alles läuft.

Schritt 1-3 

habe ich hier ausführlich beschrieben, das dauert je nach dem was man im Schritt 2 alles benötigt alles in allem keine 20 min. Dieser Artikel wird von mir laufend aktualisiert. Zu dem Wissen zu gelangen was man alles benötigt, kann allerdings wesentlich länger dauern, wenn man sich nichts aufgeschrieben hat. Im Zweifelsfall sollte man ein Paket/Tool mehr als eines zu wenig installieren. Die empfohlene Liste auf debian.fhem.de ist sicher ein guter Kompromiss.  Ich habe angefangen eine Liste zu erstellen, welches FHEM Modul welche cpan Module bzw. debian Pakete benötigt. Die werde ich noch veröffentlichen.

Schritt 4 und 6 

kann man nach seinen persönlichen Vorlieben gestalten. Normalerweise sollte das in wenigen Minuten abgeschlossen sein.
In der Regel sollte alles was FHEM betrifft in diesem Pfad liegen /opt/fhem/. Dieser Pfad muss auf das neue System und muss die richtigen Berechtigungen erhalten. Ich habe das hier schon mal im Detail beschrieben und es genauso gemacht:

Pi2 in der FHEM Oberfläche 
backup
warten bis backup fertig -> Log oder Eventmonitor
shutdown
  • mit winscp die aktuelle Sicherung ins zentrale Sicherungs-Share auf den Server kopieren
  • und in  einer zweiten Sitzung gleich wieder auf den Pi3 ins /home/pi/ Verzeichnis kopieren
Pi3 als User Pi im putty Terminal
sudo systemctl stop fhem
sudo tar -xvzf /home/pi/FHEM-201xxxxx_xxxxxx.tar.gz -C /opt/fhem/
sudo systemctl start fhem

Schritt 7

  • FHEM Web erreichbar?
  • Log File kontrollieren!!!

Wenn bis hier grobe Fehler vorhanden sind am Besten erstmal den Pi3 wieder beenden und alles auf dem Pi2 wieder starten. In Ruhe Fehler suchen.

  • Schalter betätigen
  • Sonderfunktionen kontrollieren (Sound und Sprachausgabe usw)

Nützliche Hinweise und Befehle

Umfangreiche Manipulation müssen nicht zeileweise mit sudo gemacht werden, sudo su schaltet den sudo Modus ein bis zum exit.

Es kann immer mal passieren, dass die Rechte im fhem Verzeichnis falsch sind. Dies kann man relativ einfach beheben in dem man den Eigentümer aller Dateien setzt:
sudo chown -R fhem:dialout /opt/fhem/
Manchmal muss die Rechte einzelner Dateien setzen, z.B. ausführbar machen:
sudo chmod +x /home/pi/shutdown.py
In besonderen Fällen muss das UID Bit gesetzt werden:
chmod u+s /usr/bin/dfu-programmer
Oder ganz brutal, einfach Rechte auf Alles:
sudo chmod 777 /etc/systemd/system/pishutdown.service
Ein paar Beispiele für User und Gruppen Mitgliedschaften:
useradd -m test
passwd test
gpasswd -a test users
gpasswd -a pi pulse-access
gpasswd -d pi audio
gpasswd -d test audio
groups test
getent group test
cat /etc/group
Samba Freigabe für Sonos einrichten:
sudo mkdir /mnt/SonosSpeak
sudo chmod 777 /mnt/SonosSpeak/
sudo nano /etc/samba/smb.conf
am Ende folgendes einfügen:
[SonosSpeak] comment = Audio-Files for SonosPlayer to Speak
read only = false
path = /mnt/SonosSpeak
guest ok = yes
anschließen den Service neu starten
sudo systemctl restart smbd.service
Zusatzinfo

Das Verhalten/der Syntax in der smb.conf hat sich offenbar bei Jessie etwas geändert! Nutzt man die Originale smb.conf von Raspbian muss man nur den Abschnitt des Shares (siehe oben) einfügen.
Die Anonyme Zugriff auf Shares wird durch die Standard Einstellung im Abschnitt
   [global]
   security = user
   map to guest = bad user
ermöglicht. Die erste Zeile ist die Standardeinstellung und ist in der smb.conf nicht extra gesetzt. Die zweite Zeile steht so in der Original smb.conf schon drin.

Donnerstag, 5. Januar 2017

Kalender auswerten

Am Abend vor einem Termin eine Ansage bekommen? Wie das mit FHEM geht will ich hier kurz zeigen.

Beispiel: Abholungen der Abfalltonnen

Ich habe den Abfallkalender einfach in einem neuen Googlekalender angelegt. Das ist schnell gemacht, man braucht nur drei Terminserien und muss ein paar Tage im Jahr modifizieren. Der von der Abfallwirtschaft angebotene ICAL zum download geht nur hart bis zum Jahresende, hat eine falsche Zeitzone und besteht nicht aus Serien- sondern Einzelterminen.

Anlegen eines Kalenders in FHEM

Für die weitere Arbeit brauchen wir die URL vom Kalender. Diese erhalten wir beim Googlekalender unter Einstellungen/Kalender/<Kalendername>/Privatadresse (der grüne Ical Button) oder Kalenderadresse wenn der Kalender öffentlich ist.

Ein define Befehl in FHEM reicht:
define AbfallKalender Calendar ical url <URL>

Diese Gerät liest jetzt erstmal mal nur den Kalender. Man "sieht" nicht viel, maximal das diese Modul irgendetwas tut. Mit get Befehlen können wir Termine aus dem Kalender abfragen.

Auswertung des Kalenders in FHEM

Für die Ermittlung der Termine für die Abfallentsorgung benutzen wir ein weiteres Modul -> Abfall. Da es sich um ein "Entwicklungsmodul" handelt müssen wir es zuerst in FHEM verfügbar machen. Man kann es gleich installieren, ohne komplettes Update:

update all https://raw.githubusercontent.com/uniqueck/fhem-abfall/master/controls_fhemabfall.txt
Damit es in Zukunft per Update kommt:
update add https://raw.githubusercontent.com/uniqueck/fhem-abfall/master/controls_fhemabfall.txt
Jetzt läuft das einzelne Update und wir müssen es abschließen:
save 
shutdown restart

Mit der folgenden Definiton in FHEM bekommen die heutigen, morgigen und nächsten Termine in entsprechenden Readings.
define Abfall ABFALL AbfallKalender

Hinweis Stand August 2017 
Sollte es mit der aktuelle Version des Moduls Probleme geben, diese hier verwenden.

Erinnerung per Ansage

Eine freundliche Ansage am Abend vor dem Termin und am Morgen des Termins weist uns auf den Abholtermin hin.
define di_AbholungAnsage1 DOIF ([?17:00 - 20:00] and [PIR1:"motion: on"] and [Abfall:next_tage] == 1) ( set MyTTS volume 30, set MyTTS tts Morgen wird [Abfall:next_text] abgeholt)
define di_AbholungAnsage2 DOIF ([?06:00 - 10:00] and [PIR1:"motion: on"] and [Abfall:now_text] ne "" and [Abfall:now_text] ne "0") ( set MyTTS volume 30, set MyTTS tts Heute wird [Abfall:now_text] abgeholt)
attr di_AbholungAnsage.* cmdpause 1800
Hinweis: Derzeit gibt es noch einen temporären Zustand wo nur now_text mit einer 0 gefüllt wird. Deswegen habe ich diesen Zustand extra abgefragt.

Feintuning

Das Standard Intervall zur Abfrage des Kalenders beträgt 1 h (3600 sec). Für diese Anwendung reicht eigentlich ein größeres Intervall (z.B. 4 h=14400). Mit einem zusätzlichen Parameter hinter der URL kann man dies verändern. Einfach die DEF editieren.
Die Ansage wird alle halbe Stunde in dem Zeitraum wiederholt. Das kann man beliebig anpassen.

Montag, 2. Januar 2017

ESP8266 in FHEM

Der ESP8266 Baustein kann ziemlich einfach an FHEM angebunden werden. Das FHEM Modul wird zur Zeit in einem Entwicklerthread vorgestellt.

Vorbereitung

Das Modul braucht das debian Paket libjson-perl.

sudo apt-get update && sudo apt-get install libjson-perl

Seit März 2017 ist ESPEasy offiziell in FHEM enthalten, der folgende Befehl ist nicht mehr nötig.
 Es handelt sich um ein "Entwicklungsmodul" ist also nicht normaler Bestandteil der FHEM Installation. Es lässt sich aber einfach in unsere Installation einbinden, anstatt es nur einmal als Datei herunterzuladen und umständlich in den FHEM Ordner zu kopieren:
update add https://raw.githubusercontent.com/ddtlabs/ESPEasy/master/controls_ESPEasy.txt
update all https://raw.githubusercontent.com/ddtlabs/ESPEasy/master/controls_ESPEasy.txt
shutdown restart

In FHEM wird quasi ein kleiner Web Agent/Empfänger - die Bridge - auf Port 8383 bereitgestellt. Das Port ist natürlich "frei" wählbar.

define espBridge ESPEasy bridge 8383

Damit ist die das Modul empfangsbereit, alles weitere passiert weitestgehend automatisch. Die Bridge erzeugt die eigentlichen Geräte entsprechend der Konfiguration im ESP automatisch. Man braucht nur ein Bridge für mehrere ESP Module.
Das Modul enthält die Dokumentation, sie ist in der lokalen commandref zu finden. Das Modul wird durch diese Installation beim normalen update aktualisiert.

Installation ESP8266

Zunächst muss man auf dem Modul ESPEasy installieren/flashen. Die aktuelle Firmware findet man bei www.letscontrolit.com über diesen Link. Unbedingt den aktuelle release candidate nehmen, derzeit R147_RC8!

Update 07.03.2018
Mittlerweile gibt es eine ESP-Easy Version 2.0.0 und 3
In der Zip Datei ist jetzt das Tool FlashESP8266.exe, dort kann man COM Port und bin Datei (im gleichen Pfad) einfach per Drop Down auswählen. Das Konfigurationsnetzwerk meldet sich jetzt ESP_Easy_0. Die Weboberfläche ist leicht verändert.

Die zip Datei enthält ein paar Dateien und das Flash Programm.
Nach dem Anschluss des Moduls an den USB Anschluss müssen wir im Gerätemanager den COM Port herausfinden (Anschlüsse (COM & LPT) Bei mir COM5.
Es darf ab jetzt kein "serieller Monitor" auf die COM Schnittstelle zugreifen!
Jetzt wird die Datei flash.cmd gestartet, diese fragt zunächst die Parameter ab:

Comport -> nur die Zahl eingeben -> 5
Size - je nach Modul in kByte eingeben -> ESP12F -> 4096
Buildnummer -> R147_RC8 -> 147

Achtung: gern wird die Flashsize auch in kbit angegeben. Ein ESP01 hat 4096 kbit= 512 kByte. Ein ESP12F hat 4096 kByte=4 MByte.

Das Programm erwartet die Datei ESPEasy_R147_4096.bin im gleichen Pfad und startet mit dem esptool.exe den Flashvorgang. Hektisches Blinkern der blauen LED auf dem Modul zeigt die Datenübertragung an. Beim ersten Flashen mit ESPEasy wird nach dem Neustart zunächst der gesamte Flashspeicher gelöscht, dieser Vorgang dauert etwas. Also nicht unruhig werden wenn das Wlan ESP_0 nicht gleich sichtbar wird.
Dieser Flashvorgang löscht nicht jedesmal den kompletten Speicher, das Modul kann auf eine neue Version geflashed werden und die Konfiguration bleibt erhalten! (Der NodeMCU Flasher formatiert den Flashspeicher nach dem Neustart immer komplett.)

Einrichtung des ESP8266

Man sollte nach dem Flashen etwa eine Minute warten und dann den Reset Knopf am Modul drücken. Während dieser taucht ein offenes Wlan ESP_0xxxxx auf. Damit kann man m.M. nichts anfangen.
Es dauert ein paar Sekunden bis sich das Modul nach dem Start  mit einem eigenen verschlüsselten WLAN ESP_0 meldet. Hier findet man die Beschreibung.
Man verbindet sich am einfachsten mit dem Smartphone zu diesem WLAN, das WPA Kennwort ist configesp.
Normalerweise wird man nach der Verbindung sofort auf die Konfigseite des Moduls geleitet.

Dort trägt man seine WLAN Konfiguration in die Weboberfläche ein.

Falls es nicht automatisch passiert löst man die WLAN Verbindung mit dem Smartphone.
Es kann sein, dass das Wlan ESP_0 nach kurzer Unterbrechung wieder verbunden erscheint und man aufgefordert wird sich wieder anzumelden. Diese Anmeldung erfolgt nur für eine Sekunde und das Wlan ESP_0 verschwindet. Ich habe im seriellen Monitor beobachtet, dass man dies auch tun sollte. Erst dann wird er Flash geschrieben und der Baustein neu gestartet. Dies dauert wenige Sekunden.








Nach einem Neustart kann man sich nach kurzer Zeit zu http://newdevice verbinden.
Auf der config Seite konfiguriert man mindestens folgende Felder.

Name: <Eindeutiger Name> damit es im eigenen Netzwerk auffindbar ist.
Protocol: FHEM HTTP
Locate Controller: Auswahl entweder Name oder IP Adresse
Controller IP: <IPAdresse des FHEM Servers>
Controller Port:8383 (Das Gleiche wie beim define der Bridge)

Mit submit speichern!

Die blauen Fragezeichen verlinken ins Wiki, meist mit nützlichen Informationen.

Wenn man jetzt auf der Devices Seite ein Gerät konfiguriert sieht man das Ergebnis nach kurzer Zeit in FHEM.
Als Beispiel kann man dort System Info auswählen. Egal was man dort in der weiteren Klappleiste auswählt man sollte zumindest die Felder Name IDX und Value Name ausfüllen um sinnvolle Einträge zu bekommen.


Hier als Beispiel die RSSI Werte des WiFi Moduls:


Und so sieht es dann nach kurzer Zeit in FHEM aus ->







Tipps

Um die flash.cmd Datei gleich im richtigen Pfad zu öffnen, geht man in Windows auf den Ordner in dem die Datei liegt und drückt die Umschalttaste und gleichzeitig mit der rechten Maustaste das Context Menü - hier kann man den Punkt Eingabeaufforderung hier öffnen auswählen. Bei Windows 10 ab Version 1703 wird hier die Powershell angeboten. In dieser läuft die flash.cmd nicht -> einfach cmd & enter eintippen um die alte commandshell zu starten! Für häufigere Flashvorgänge sollte man sich eine angepasste Batchdatei erstellen.

Auf der Seite Tools kann man den Befehl reset absetzen, der löscht alle Einstellungen und versetzt das Modul wieder in den AP Modus - ohne das man neu flashen muss. Danach bootet das Modul von selbst wieder. Der Löschvorgang dauert etwa 1:40 min. Also nicht unruhig werden, wenn man darauf wartet, dass ESP_0 wieder erscheint.
Das funktioniert auch im Browser: http://<ESP Name>/tools?cmd=reset. Achtung wenn man diesen Befehl abgesetzt hat, bleibt das Fenster so stehen, wechselt man wieder in dieses Fenster oder drückt Refresh wird der Befehl sofort erneut gesendet.
Man kann "Factory Reset" auch per Hardware machen: Einfach RX und TX verbinden und neu starten. Den Trick habe ich hier  als Ausweg aus dem Deep Sleep gefunden.

Auf der Seite tools kann man auch die gesamte Konfiguration speichern und wiederherstellen. Der Dateiname endet zwar per default auf txt, es ist aber keine Textdatei. Man kann damit also nur die komplette Konfiguration übertragen, inklusive Gerätenamen usw. und leider nicht zwischendurch editieren.

Stromversorgung

Der verbreitete FTDI Chip darf laut Datenblatt 50 mA liefern, das ESP Modul kann bis zu 300 mA Spitzenstrom ziehen und verbraucht schon im normalen Modus ca. 50-70 mA. Die handelsüblichen FTDI Adapter ohne separaten Spannungsregler sind damit ohne externe 3,3 Volt Versorgung ungeeignet. Alle Developerboards haben separate Spannungsregler!

Fehlerquellen

Die Stromversorgung des ESP Bausteines ist nicht unkritisch. Häufig sieht alles gut aus, der Flashvorgang läuft durch aber anschließend funktioniert nicht alles -> Der Flashinhalt ist korrupt!
Ein billiger FTDI Adapter z.B. liefert nicht genügend Strom um den ESP zu betreiben. Ein zu langes mehrfach gestecktes USB Kabel kann sich als Fehlerquelle entpuppen.

Wenn sich der Baustein eigenartig verhält, ESP_0 nicht erscheint sondern ein anderes Wlan ESP_xxxx oder der Baustein nach korrektem Eintrag der SSID und Passwort und der Anmeldung im Wlan nicht als http://newdevice erreichbar ist -> unbedingt Stromversorgung des Bausteins prüfen!