Leben, Essen, Schlafen

Schnipsel, Anregungen, Haltbares

Projekte, Aufgaben, Einfaches

Autor: Ole

Backup erstellen Plex Server auf Raspberry Pi

Backup erstellen Plex Server auf Raspberry Pi

Backup, Restore oder Klon vom Plex Server

Backing up your PMS data involves the same steps you’ll need if you were to clone your PMS and take to a new computer, reinstall the operating system, or just want a backup for safe keeping.

Ein Backup machen:

  • Plex Server stoppen
  • als root in der Shell anmelden
  • Backup Image erstellen
  • Das Backup Image kopieren

Ein Backup wieder einspielen:

  • Plex Server neu aufsetzen
  • Den Plex Server einmal starten und stoppen
  • Das Backup einspielen
  • Plex Server starten

Das Backup Image erstellen:

Auf dem System folgendes durchführen:

[chuck@lizum ~.74]$ sudo sh
sh-4.4# cd /var/lib/plexmediaserver
sh-4.4# tar cfz /nas/tmp/PlexBackup.tar.gz ./Library
sh-4.4# ls -la /nas/tmp/PlexBackup.tar.gz 
-rw-r--r--. 1 root root 864050144 Oct 29 15:29 /nas/tmp/PlexBackup.tar.gz
sh-4.4# 

Das Backup Image einspielen:

sh-4.4# sudo sh
sh-4.4# systemctl start plexmediaserver
sh-4.4# systemctl stop plexmediaserver
sh-4.4# cd /var/lib/plexmediaserver
sh-4.4# rm -rf Library
sh-4.4# tar xf /nas/tmp/PlexBackup.tar.gz
sh-4.4# chown -R plex:plex ./Library
sh-4.4# systemctl start plexmediaserver

Ein System klonen:

  • Ein Backup Image erstellen
  • Auf das neue System kopieren
  • Das Backup Image einspielen
  • Die alte Preferences.xml löschen, ansonsten existieren zwei identische Server

Quelle: https://forums.plex.tv/t/linux-tips/276247/7

TRÅDFRI mit openHAB nach Update auf 1.8.25

TRÅDFRI mit openHAB nach Update auf 1.8.25

Ikea hat dem TRÅDFRI  System ein umfangreiches Update verpasst. Dadurch ist leider die bisherige Konfiguration hinfällig, da jetzt eine Identifikation nicht mehr nur über den Sicherheitscode auf der Rückseite des TRÅDFRI Gateways erfolgt. Um dennoch wieder lauffähig zu sein und das ganze als .things im System zu integrieren ist folgendes zu tun.

  1. Aktuelles Thing des Gateways in der PaperUI löschen.
  2. Neustart von openHAB (sudo systemctl restart openhab2.service)
  3. Über die Inbox in der PaperUI das Gateway wieder hinzufügen, eventuell ist die Suche nach TRÅDFRI Geräten nochmal anzuschubsen.
  4. In der PaperUI: Configuration->Things wird der Code von der Rückseite des Gateways beim Thing eingetragen und gespeichert. Die Verbindung ist aufgebaut.
  5. Die neuen Parameter identity und preSharedKey findet man über die Rest API <IP_openHAB_Server>:<Port>/rest/things
  6. Dort einmal nach preSharedKey suchen und die beiden Werte in die tradfri.things mit folgendem neuen Format kopieren:
Bridge tradfri:gateway:gwb07xxxxxxxx [ host=“xxx.xxx.xxx.xxx”, identity=“xxxxxxxxxxxxxxxxxxxxx”, preSharedKey=“xxxxxxxxx” ] {
}

Im Vergleich zur alten tradfri.things fällt sofort auf, dass der Code der Rückseite nicht mehr gebraucht wird.

Bridge tradfri:gateway:gw1 [ host=“xxx.xxx.xxx.xxx”, code=“xxxxxxxxxx” ] {
}

Mit OpenHAB Cloud items über Alexa erreichen (Debug)

Mit OpenHAB Cloud items über Alexa erreichen (Debug)

Mit dem OpenHAB Cloud Connector Addon lassen sich Items über myopenhab.org für weitere Dienste erreichbar machen. Die Einrichtung ist im Addon beschrieben. Um beispielsweise einen Schalter einzupflegen sind folgende Schritte notwendig.

Der Simple Mode unter PaperUI -> Configuration –> System ausstellen. Die ausgewählten Items sind mit einem Tag zu versehen. Welche Tags möglich sind kann im HomeKit Addon geprüft werden.

Switch  item_name  "Name" <switch> (Gruppe, Untergruppe) [ "Switchable" ] {channel="Adresse"}

Die Konfiguration erfolgt am besten in der Dabei conf/services/openhabcloud.cfg wie folgt:

############################## openHAB Cloud Connector #############################

# The URL of the openHAB Cloud service to connect to.
# Optional, default is set to the service offered by the openHAB Foundation
# (https://myopenhab.org/)
baseURL=https://myopenhab.org/

# Defines the mode in which you want to operate the connector.
# Possible values are:
# - notification: Only push notifications are enabled, no remote access is allowed.
# - remote: Push notifications and remote access are enabled.
# Optional, default is 'remote'.
mode=remote

# A comma-separated list of items to be exposed to external services like IFTTT. 
# Events of those items are pushed to the openHAB Cloud and commands received for
# these items from the openHAB Cloud service are accepted and sent to the local bus.
# Optional, default is an empty list.
expose=item_name,item_name2

Auf myopenhab.org/items prüfen, ob Items online sind. Vorher einmal schalten, da sonst kein Update erfolgt. Ist dort alles vorhanden kann der Alexa Skill installiert werden. Dabei ist eine Kontoverknüpfung mit myopenhab.org notwendig. Bei der anschließenden Suche werden hoffentlich alle Items gefunden.

Sollte das nicht klappen, liegt es sehr wahrscheinlich an Umlauten in den Items und deren aktuellen Zuständen. Grundsätzlich sollte in den Bezeichnungen der Items auf ö,ä,ü,ß und weitere Sonderzeichen verzichtet werden. In meinem Fall kommen aber noch weitere Dinge hinzu. Ich greife mit dem Amazon Echo Control Binding zum Beispiel die letzten Kommandos ab. Da kommen, genauso wie im Astro Binding, ebenfalls Umlaute vor. Sobald ich diese Items ausblende (ich benenne einfach die Dateiendung um) läuft es. Überprüfen kann man das mittels der Rest API unter https://myopenhab.org/rest/items/. Da müssen auch die angelegten Tags auffindbar sein.

Weiterer Lesestoff: https://community.openhab.org/t/alexa-smart-home-skill-no-devices-found-solution/31953

Serverstatus in WordPress ausgeben

Serverstatus in WordPress ausgeben

Um ein paar Informationen über meine lokalen Server auszuspucken habe ich folgendes Idee: Ein bash-Skript fragt die Informationen lokal ab und macht einen Upload zum Blog. Abzufragen sind erstmal grundsätzlich

ping
uname -a
cat /sys/class/thermal/thermal_zone0/temp
cat /proc/uptime

um Onlinestatus, Hostnamen, Kernel, Release, Architektur der CPU, CPU Temperatur und Laufzeit zu erfahren.

Als erstes ist es ganz hilfreich überhaupt zu prüfen, ob der abzufragende Server vorhanden ist.

ping -q -c1 $ip > /dev/null
if [ $? -eq 0 ]
then
    status1="✓"
else
    status1="✘"
fi

Anschließend kann auch ein möglicher Fernzugriff erfolgen, um mit ‘uname‘ grundlegende Informationen abzugreifen.

host1=$(uname -a)
kernelname1="$(cut -d' ' -f1 <<<$host1)"
release1="$(cut -d' ' -f3 <<<$host1)"
machine1="$(cut -d' ' -f11 <<<$host1)"
host1="$(cut -d' ' -f2 <<<$host1)"

Die Ausgabe des Temperaturwertes ist in Tausendstel °C, also ist eine kurze Rechnung zur Anpassung nötig.

temp1=$(cat /sys/class/thermal/thermal_zone0/temp)
temp1="$(($temp1/1000))°C"

Die Ausgabe der Laufzeit gibt zunächst zwei Werte aus, einmal die eigentliche Laufzeit in Sekunden und der Anteil daran im Idle. Also ist nur der erste Wert zur Berechnung notwendig. Jetzt muss nur noch das Sekundenwirrwarr in eine sinnvolle Darstellung umgerechnet werden (Tage, Stunden, Minuten, Sekunden). Die Sekunden berechnen sich aus der Gesamtzahl der Sekunden mit dem Modulo 60. Für die Minuten wird die Gesamtzahl der Sekunden mit ‘/60‘ in Minuten umgerechnet (Ganzzahl!!, der “Überschuss” fällt weg und ist ja auch schon zuvor in den Sekunden berechnet worden) und anschließend mit ‘%60‘ der Rest ausgegeben, der keine ganze Stunde mehr ergibt. Ähnliches erfolgt bei der Stunden- und Tagesberechnung. In der Ausgabe gibt es noch eine kleinere Spielerei, um Tage auszublenden, wenn keine vorhanden sind.

uptime1=$(cat /proc/uptime)
uptime1=${uptime1%%.*};
secs=$((${uptime1}%60))
mins=$((${uptime1}/60%60))
hours=$((${uptime1}/3600%24))
days=$((${uptime1}/86400))
if [ "${days}" -eq "0" ]
then
    uptime="${hours}h${mins}m${secs}s"
else
    uptime="${days}d${hours}h${mins}m${secs}s"
fi

Die bereitgestellten Informationen speichere ich im aktuellen Verzeichnis (Dateiname besteht aus dem Hostanteil der IP Adresse, eventuell vorehandene Leerzeichen werden noch entfernt) und lade diese hoch.

workdir=$(pwd);
workname=$(hostname -I)
worknameshort=$(cut -d'.' -f4 <<<$workname)
worknameshort=`echo "$worknameshort" | sed "s/ //g"`
echo $host > $workdir/$worknameshort.js
echo $status >> $workdir/$worknameshort.js
echo $kernelname >> $workdir/$worknameshort.js
echo $release >> $workdir/$worknameshort.js
echo $machine >> $workdir/$worknameshort.js
echo $temp >> $workdir/$worknameshort.js
echo $uptime >> $workdir/$worknameshort.js
# upload $data.js to webspace
curl -T $worknameshort.js -u user:pass ftp://serveradress.net/
# clean up the mess
rm $workdir/$worknameshort.js

Jetzt tummeln sich etliche Geräte im Netzwerk, das Skript kann alle nach einander abarbeiten. Dazu ist ein kleines Array mit IP Adressen notwendig.

ip[1]=192.168.178.5  #raspberry
ip[2]=192.168.178.17 #berrycam
ip[3]=192.168.178.28 #plexberry
ip[4]=192.168.178.39 #kitchentable
ip[5]=192.168.178.74 #openhab
ip[6]=192.186.178.80 #pihole
ip[7]=192.168.178.99 #automotiverocketlauncher

Daraus kann dann mittels ‘ ${ip[@]} ‘ innerhalb einer Schleife die jeweilige IP genutzt werden. Natürlich muss zunächst mal der ECDSA Key akzeptiert werden (Alternativ kann auch nach ‘sshpass -p ${passwd} ssh‘ mit ‘-o StrictHostKeyChecking=no‘ dieses umgangen werden). Um eine Anmeldung am Remote ohne Passworteingabe zu bewerkstelligen installiert man das Paket sshpass. Die bash ruft ein Subskript ‘remote.sh‘ auf in der alles aufbereitet wird. Falls kein Zugriff erfolgen kann (ping erfolglos) schreibt das Skript trotzdem einen Eintrag. Daten dazu auf Git.

for adress in ${ip[@]} ; do
    ping -q -c1 ${adress} > /dev/null
    if [ $? -eq 0 ]
    then
        sshpass -p ${passwd} ssh -o StrictHostKeyChecking=no ${user}@${adress} 'bash -s' < /home/pi/statuspi/remote.sh
    status="✘";
    workdir=$(pwd);
    workname=${adress};
    worknameshort=$(cut -d'.' -f4<<<$workname)
    worknameshort=`echo "$worknameshort" | sed "s/ //g"`
    echo $adress > $workdir/$worknameshort.js
    echo $status >> $workdir/$worknameshort.js
    # upload $data.js to webspace
    curl -T $worknameshort.js -u user:pass ftp://serveradress.net/
    # clean up the mess
    rm $workdir/$worknameshort.js
    fi
done

Das Skript selbst muss alle x Minuten ausgeführt werden, um einen ständigen Upload zu garantieren. Für mich reicht da ein Abstand von 60 Minuten. Also muss folgendes mit crontab /e als cronjob eingetragen werden.

1 * * * * /home/pi/statuspi/statuspi.sh

Um das ganze in WordPress anzuzeigen ist folgender Code nötig. Ich habe die Dateinamen einfach in einem Array übernommen, das geht natürlich anders. Mit dem Plugin WP H-PHP Widget lässt sich das ganze problemlos einfügen.

<?php
$name = array("5.js","17.js","28.js","39.js","74.js","80.js","9.js");
$dir = "http://serveradress.net/";
$text = array("Name","Status","System","Release","Architektur","Temperatur","Laufzeit");

for($k=0;$k < count($name); $k++){
    $data = file($dir . $name[$k]);
    echo substr($data[0], 0, -1);
    echo " ist ";
    echo $data[1];
    echo "<br />";
    for($i=2;$i < count($data); $i++){
        echo $text[$i];
        echo ": ";
        echo $data[$i];
        echo "<br />";
    }
    echo "<hr>";
}
?>
Pan-Tilt Servos am Raspberry Pi mit motionEye

Pan-Tilt Servos am Raspberry Pi mit motionEye

Bauteile:

Anschluss der Servos: Vertikal an 0, horizontal an 1. Ground (braun) an Außenseite der Platine

motionEye auflegen: Entweder inklusive Homekit oder die einfache und schnelle Variante (Kamera aktivieren, wenn Raspberry Camera Modul verwendet wird!):

sudo apt-get install ffmpeg
sudo modprobe bcm2835-v4l2 
sudo apt-get install libmariadbclient18 libpq5
wget https://github.com/Motion-Project/motion/releases/download/release-4.1.1/pi_stretch_motion_4.1.1-1_armhf.deb
sudo dpkg -i pi_stretch_motion_4.1.1-1_armhf.deb
sudo apt-get install python-pip python-dev libssl-dev libcurl4-openssl-dev libjpeg-dev libz-dev
sudo pip install motioneye
sudo mkdir -p /etc/motioneye
sudo cp /usr/local/share/motioneye/extra/motioneye.conf.sample /etc/motioneye/motioneye.conf
sudo mkdir -p /var/lib/motioneye
sudo cp /usr/local/share/motioneye/extra/motioneye.systemd-unit-local /etc/systemd/system/motioneye.service
sudo systemctl daemon-reload
sudo systemctl enable motioneye
sudo systemctl start motioneye

I2C in raspi-config aktivieren

sudo apt-get install python-smbus
sudo apt-get install i2c-tools
sudo i2cdetect -y 1

Adafruit Python PCA9685 installieren

sudo apt-get install git build-essential python-dev
git clone https://github.com/adafruit/Adafruit_Python_PCA9685.git
cd Adafruit_Python_PCA9685
sudo python setup.py install

Sollte es zu Problemen bei ausführen von setup.py kommen (“File is not a zip file“) liegt das am Inhalt “301 moved permanently”. Das ganze mit wget
https://pypi.python.org/packages/source/s/setuptools/setuptools-3.5.1.zip direkt in das erstellte Verzeichnis Adafruit_Python_PCA9685 laden hilft.
Bei weiteren Problemen folgende Pakete händisch installieren: spidev, adafruit-pureio, Adafruit-GPIO, adafruit-pca9685

sudo pip3 install spidev
sudo pip3 install Adafruit-PureIO
sudo pip3 install Adafruit-GPIO
sudo pip3 install Adafruit-PCA9685

oder auf

sudo pip install adafruit-pca9685

zurückgreifen.

Die passenden Skripte für die Steuerung der Tilt-Shift Servos gibt es hier:

git clone https://github.com/luetzel/motion_eye_servo_action.git

Die Dateien einmal in /etc/motioneye kopieren und ausführbar machen. Beispiel:

sudo chmod 755 /etc/motioneye/up_1

Die ‘1‘ in den Dateien bezieht sich auf die Kamera. Sollten mehrere in motionEye vorhanden sein, bitte anpassen.
Die Einträge ‘servo_min‘ und ‘servo_max‘  in left_1, right_1, down_1 und up_1 sind noch anzupassen an die gegebenen Endpositionen der beiden Servos (vertikal von 225 bis 575, horizontal von 150 bis 625 bei mir).

In motionEye (http://ipdesraspberry:8765, Login: admin oder user ohne Passwort) Kamera als Typ Local MMAL Camera mit VideoCore Camera anlegen. Gute und flüssige Übertragung klappt zum Beispiel bei einer Auflösung von 1024×600.

Quelle: https://github.com/luetzel/motion_eye_servo_action, https://raspberryblog.de/?p=2209 https://github.com/luetzel/motion_eye_servo_action

Die Plexdatenbank exportieren

Die Plexdatenbank exportieren

Um die Datenbank von Plex auszulesen gibt es verschiedene Wege. Mit dem ExportTools Plugin lassen sich fix csv beziehungsweise xls Dateien erstellen. Man muss nur darauf achten dem Ausgabeverzeichnis die richtigen Rechte zu geben, damit der User plex auch zugreifen kann.

Um gleich eine webbasierte Darstellung zu erhalten kann momentan noch das nicht mehr weiterentwickelte Plex Export genutzt werden. Durch lokalen Zugriff (oder auch auf dem Plexserver selbst) kann ein kompletter Export erfolgen.

Durch ein paar schnelle Anpassungen in der cli.php, plex.js und index.html ist eine eingedeutschte Darstellung möglich.

Das Skript ist auf einem lokalen Web-Server mit ‘php /pfad/zum/www/Verzeichnis/cli.php -plex-url=http://plexIP:32400 -token=deinToken‘ auszuführen. Den eigenen Token findet man so.

Raspberry Pi Camera in Homekit einbinden

Raspberry Pi Camera in Homekit einbinden

Der Weg zur Tür ist etwas weit, um mal eben zu schauen was auf dem Hof los ist, habe ich die Idee einen Raspberry mit eigener Kamera einzusetzen. Viele andere Ansätze haben leider nicht wirklich zum Erfolg geführt. Und ganz nebenbei ist auch noch ein Abgreifen des Signals über den Browser möglich. Das ganze läuft mit HAP-NodJS Framework und motionEye.

Notwendig sind folgende Sachen:

  • Raspberry Pi
  • SD Karte mit einem aktuellen Raspbian
  • Netzteil
  • Raspberry Pi Camera Modul mit Flachbandkabel

Schritt 1

Raspberry Pi einrichten:
ssh, wifi, Kamera aktivieren, Memory Split auf mindestens 128MB

sudo modprobe bcm2835-v4l2
sudo reboot

Schritt 2

Installation:
Folgendes ausführen:

curl -sSL goo.gl/k8QMGm | bash 

oder folgende Befehle abarbeiten:

cd /home/pi
sudo apt-get update
sudo apt-get remove node nodejs nodejs-legacy -y
sudo apt-get install git-core libnss-mdns libavahi-compat-libdnssd-dev -y
uname -m # bei armv6l folgendes
    sudo wget http://node-arm.herokuapp.com/node_latest_armhf.deb
    sudo dpkg -i node_latest_armhf.deb
    sudo rm -rf node_latest_armhf.deb
    sudo npm install -g n
    sudo rm /usr/local/bin/node
    sudo rm -rf /usr/local/lib/node_modules/npm
    sudo n prune
    sudo n 8.2.1
# ansonsten
    sudo curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
    sudo apt-get install nodejs -y
    sudo npm install -g n
    sudo rm /usr/local/bin/node
    sudo rm -rf /usr/local/lib/node_modules/npm
    sudo n prune
    sudo n 8.2.1
# weiter im Text
sudo apt-get install gcc g++ make -y
sudo npm install -g node-gyp
sudo git clone --branch v0.4.27 https://github.com/KhaosT/HAP-NodeJS.git
cd HAP-NodeJS/
sudo rm -rf accessories/AirConditioner_accessory.js
sudo npm install

Schritt 3

motionEye installieren, dazu folgendes ausführen:

curl -sSL goo.gl/68K6gS | bash

Oder folgende Befehle abarbeiten:

cd /home/pi
sudo apt-get remove libavcodec-extra-57 libavformat57 libavresample2 libavutil55
sudo apt-get install libavutil55 libavformat57 libswscale3 -y
sudo apt-get install python-pip python-dev curl libssl-dev libcurl4-openssl-dev libmariadbclient18 libpq5 libjpeg8-dev mysql-common ffmpeg -y
sudo wget "https://github.com/Motion-Project/motion/releases/download/release-4.1/pi_stretch_motion_4.1-1_armhf.deb" #für Raspbian Stretch!
sudo dpkg -i pi_stretch_motion_4.1-1_armhf.deb
sudo rm -rf pi_stretch_motion_4.1-1_armhf.deb
sudo pip install motioneye
sudo mkdir -p /etc/motioneye
sudo cp /usr/local/share/motioneye/extra/motioneye.conf.sample /etc/motioneye/motioneye.conf
sudo mkdir -p /var/lib/motioneye
sudo cp /usr/local/share/motioneye/extra/motioneye.systemd-unit-local /etc/systemd/system/motioneye.service
sudo systemctl daemon-reload
sudo systemctl enable motioneye
sudo systemctl start motioneye
cd /home/pi/HAP-NodeJS
sudo npm install
sudo npm install node-cmd
sudo systemctl restart motioneye
cd /home/pi/HAP-NodeJS/lib/
sudo mv Camera.js OriginalCamera.bak
sudo wget https://goo.gl/VZZMYV -O Camera.js

Schritt 4

Kamera einrichten:

Im Browser die url des Raspberry Pis mit dem Port 8765 aufrufen, Anmeldung erfolgt als admin, ohne Passwort (Kann später geändert werden). Die Einrichtung der neuen Kamera erfolgt mit folgenden Parametern:

Camera type: Local MMAL Camera
Camera: VideoCore Camera

Schritt 5

Um das ganze zu automatisieren ist ein Autostart einzurichten:

cd ~
sudo npm install forever -g
sudo nano /start

Dort folgende Zeilen einsetzen und speichern:

sudo forever stopall
cd /home/pi/HAP-NodeJS
sudo forever start CameraCore.js

Anschließend folgendes ausführen:

sudo chmod +x /start
sudo nano /etc/rc.local

Und dort vor exit 0 folgendes einsetzen und speichern:

sudo sh /start

Abschließend einmal durchstarten. Jetzt kann die Kamera in Homekit eingebunden werden. Dazu in der Home App auf ‘+‘, ‘Gerät hinzufügen‘, ‘Code fehlt bzw. kann nicht gescannt werden?‘, Kamera auswählen und mit dem Code 031-45-154 einbinden. Fertig!

Quelle:  https://raspberrytips.nl/raspberry-pi-homekit-camera/

Update von motionEye durch:

sudo pip install motioneye --upgrade
sudo systemctl restart motioneye

Als Anhang die modifizierte Camera.js (als Download im Skript oben enthalten):

'use strict';

var debug = require('debug')('Camera');
var inherits = require('util').inherits;
var EventEmitter = require('events').EventEmitter;
var clone = require('./util/clone').clone;
var uuid = require('./util/uuid');
var Service = require('./Service').Service;
var Characteristic = require('./Characteristic').Characteristic;
var StreamController = require('./StreamController').StreamController;
var HomeKitTypes = require('./gen/HomeKitTypes');
var fs = require('fs');
var ip = require('ip');
var spawn = require('child_process').spawn;

module.exports = {
  Camera: Camera
};

function Camera() {
  this.services = [];
  this.streamControllers = [];

  this.pendingSessions = {};
  this.ongoingSessions = {};

  let options = {
    proxy: false, // Requires RTP/RTCP MUX Proxy
    disable_audio_proxy: false, // If proxy = true, you can opt out audio proxy via this
    srtp: true, // Supports SRTP AES_CM_128_HMAC_SHA1_80 encryption
    video: {
      resolutions: [
        [1280, 720, 30],
        [320, 240, 15]
      ],
      codec: {
        profiles: [0, 1, 2], // Enum, please refer StreamController.VideoCodecParamProfileIDTypes
        levels: [0, 1, 2] // Enum, please refer StreamController.VideoCodecParamLevelTypes
      }
    },
    audio: {
      comfort_noise: false,
      codecs: [
        {
          type: "OPUS", // Audio Codec
          samplerate: 24 // 8, 16, 24 KHz
        },
        {
          type: "AAC-eld",
          samplerate: 16
        }
      ]
    }
  }

  this.createCameraControlService();
  this._createStreamControllers(2, options);
}

Camera.prototype.handleSnapshotRequest = function(request, callback) {
  // Image request: {width: number, height: number}
  // Please override this and invoke callback(error, image buffer) when the snapshot is ready

  let resolution = request.width + 'x' + request.height;
  var ffmpegImageSource = "-i http://localhost:8765/picture/1/current/"
  var imageSource = ffmpegImageSource !== undefined ? ffmpegImageSource : this.ffmpegSource;
  let ffmpeg = spawn('ffmpeg', (imageSource + ' -t 1 -s '+ '1280x720' + ' -f image2 -').split(' '), {env: process.env});
  var imageBuffer = Buffer(0);

  ffmpeg.stdout.on('data', function(data) {
    imageBuffer = Buffer.concat([imageBuffer, data]);
  });
  ffmpeg.on('close', function(code) {
    callback(undefined, imageBuffer);
  });
}

Camera.prototype.handleCloseConnection = function(connectionID) {
  this.streamControllers.forEach(function(controller) {
    controller.handleCloseConnection(connectionID);
  });
}

Camera.prototype.prepareStream = function(request, callback) {
  // Invoked when iOS device requires stream

  var sessionInfo = {};

  let sessionID = request["sessionID"];
  let targetAddress = request["targetAddress"];

  sessionInfo["address"] = targetAddress;

  var response = {};

  let
videoInfo = request["video"];
  if (videoInfo) {
    let targetPort = videoInfo["port"];
    let srtp_key = videoInfo["srtp_key"];
    let srtp_salt = videoInfo["srtp_salt"];

    let videoResp = {
      port: targetPort,
      ssrc: 1,
      srtp_key: srtp_key,
      srtp_salt: srtp_salt
    };

    response["video"] = videoResp;

    sessionInfo["video_port"] = targetPort;
    sessionInfo["video_srtp"] = Buffer.concat([srtp_key, srtp_salt]);
    sessionInfo["video_ssrc"] = 1;
  }

  let audioInfo = request["audio"];
  if (audioInfo) {
    let targetPort = audioInfo["port"];
    let srtp_key = audioInfo["srtp_key"];
    let srtp_salt = audioInfo["srtp_salt"];

    let audioResp = {
      port: targetPort,
      ssrc: 1,
      srtp_key: srtp_key,
      srtp_salt: srtp_salt
    };

    response["audio"] = audioResp;

    sessionInfo["audio_port"] = targetPort;
    sessionInfo["audio_srtp"] = Buffer.concat([srtp_key, srtp_salt]);
    sessionInfo["audio_ssrc"] = 1;
  }

  let currentAddress = ip.address();
  var addressResp = {
    address: currentAddress
  };

  if (ip.isV4Format(currentAddress)) {
    addressResp["type"] = "v4";
  } else {
    addressResp["type"] = "v6";
  }

  response["address"] = addressResp;
  this.pendingSessions[uuid.unparse(sessionID)] = sessionInfo;

  callback(response);
}

Camera.prototype.handleStreamRequest = function(request) {
  // Invoked when iOS device asks stream to start/stop/reconfigure
  var sessionID = request["sessionID"];
  var requestType = request["type"];
  if (sessionID) {
    let sessionIdentifier = uuid.unparse(sessionID);

    if (requestType == "start") {
      var sessionInfo = this.pendingSessions[sessionIdentifier];
      if (sessionInfo) {
        var width = 1024;
        var height = 600;
        var fps = 30;
        var bitrate = 250;

        let videoInfo = request["video"];
        if (videoInfo) {
          width = videoInfo["width"];
          height = videoInfo["height"];

          let expectedFPS = videoInfo["fps"];
          if (expectedFPS < fps) {
            fps = expectedFPS;
          }

//          bitrate = videoInfo["max_bit_rate"];
        }

        let targetAddress = sessionInfo["address"];
        let targetVideoPort = sessionInfo["video_port"];
        let videoKey = sessionInfo["video_srtp"];

        let ffmpegCommand = '-re -i http://localhost:8081 -threads 0 -vcodec h264_omx -an -pix_fmt yuv420p -r '+ fps +' -f rawvideo -tune zerolatency -vf scale='+ width +':'+ height +' -b:v '+ bitrate +'k -bufsize '+ bitrate +'k -payload_type 99 -ssrc 1 -f rtp -srtp_out_suite AES_CM_128_HMAC_SHA1_80 -srtp_out_params '+videoKey.toString('base64')+' srtp://'+targetAddress+':'+targetVideoPort+'?rtcpport='+targetVideoPort+'&localrtcpport='+targetVideoPort+'&pkt_size=1378';
        let ffmpeg = spawn('ffmpeg', ffmpegCommand.split(' '), {env: process.env});
        this.ongoingSessions[sessionIdentifier] = ffmpeg;
      }

      delete this.pendingSessions[sessionIdentifier];
    } else if (requestType == "stop") {
      var ffmpegProcess = this.ongoingSessions[sessionIdentifier];
      if (ffmpegProcess) {
        ffmpegProcess.kill('SIGKILL');
      }

      delete this.ongoingSessions[sessionIdentifier];
    }
  }
}

Camera.prototype.createCameraControlService = function() {
  var controlService = new Service.CameraControl();

  // Developer can add control characteristics like rotation, night vision at here.

  this.services.push(controlService);
}

// Private

Camera.prototype._createStreamControllers = function(maxStreams, options) {
  let self = this;

  for (var i = 0; i < maxStreams; i++) {
    var streamController = new StreamController(i, options, self);

    self.services.push(streamController.service);
    self.streamControllers.push(streamController);
  }
}
Wie die Waschmaschine smart wird

Wie die Waschmaschine smart wird

Die Waschmaschine steht im Keller und sagt nicht bescheid wenn sie fertig ist? Dann lassen wir sie doch einfach sprechen!
Grundsätzlich ganz einfach mittels OpenHAB und einer smarten Steckdose. In meinem Fall habe ich eine devolo Schalt- und Messsteckdose, die über Z-Wave kommuniziert, genommen. Dafür hängt am OpenHAB Raspberry Pi ein Razberry-Modul am GPIO. Die Einrichtung erspare ich mir mal. Der eigentliche Trick ist ganz einfach, anhand des Verbrauchs werden Modi der Maschine festgelegt. Dazu muss einmalig ein kompletter Waschmaschinengang gemessen werden. OpenHAB schreibt alles schon mit, aus dem Log müssen nur die richtigen Zeilen entnommen werden.

grep "steckdose_bz_wama_watt changed" /var/log/openhab2/events.log

Gibt dann folgendes aus:

...
2019-03-29 15:12:14.953 [vent.ItemStateChangedEvent] - steckdose_bz_wama_watt changed from 194.5 to 182.2
2019-03-29 15:17:18.166 [vent.ItemStateChangedEvent] - steckdose_bz_wama_watt changed from 182.2 to 12.8
2019-03-29 15:17:44.169 [vent.ItemStateChangedEvent] - steckdose_bz_wama_watt changed from 12.8 to 16.7
2019-03-29 15:17:53.172 [vent.ItemStateChangedEvent] - steckdose_bz_wama_watt changed from 16.7 to 24.9
2019-03-29 15:17:56.195 [vent.ItemStateChangedEvent] - steckdose_bz_wama_watt changed from 24.9 to 26.3
...

Um das ganze einfacher auszuwerten schmeißen alles unnötige raus.

grep "steckdose_bz_wama_watt changed" /var/log/openhab2/events.log | sed 's/.[0-9]* \[vent.ItemStateChangedEvent.* to /;/'

Und erhalten folgendes:

...
2019-03-29 15:12:14;182.2
2019-03-29 15:17:18;12.8
2019-03-29 15:17:44;16.7
2019-03-29 15:17:53;24.9
2019-03-29 15:17:56;26.3
...

Das lässt sich dann grafisch aufbereiten.

Leistungsdiagramm Waschmaschine

Ein Waschgang

Grundsätzlich ist die Waschmaschine

  • Aus,
  • im Standby,
  • Aktiv,
  • fertig.

Die große Schwierigkeit ist die Übergänge zwischen den einzelnen Zuständen herauszufinden. Zu erkennen ist auf Anhieb, dass alles knapp über 0 Zustand ‘Aus‘ ist. Größer als 5 ist ‘aktiv‘ und wenn nach einer aktiven Phase der Wert auf unter 4,5 fällt ist die Maschine ‘fertig‘. Für ‘Standby’ bleibt dann die Lücke 1 x 5. Hier sind je nach Maschine natürlich individuelle Werte notwendig. Je nach Maschine sind auch verschiedene Waschgänge zu untersuchen um alles abzudecken.

Als Anzeige dient ein einfaches Item und zur Übersetzung eine Map.

Number wama_status "Waschmaschine Status [MAP(wama_status.map):%d]"
0=Aus
1=Standby
2=Aktiv
3=Fertig

Das ganze Prozedere zur Statuserkennung in eine Rule verpackt sieht dann so aus:

val Number MODE_OFF = 0
val Number MODE_STANDBY = 1
val Number MODE_ACTIVE = 2
val Number MODE_FINISHED = 3

rule "Waschmaschinenstatus"
when
    Item steckdose_bz_wama_watt changed
then
    if (steckdose_bz_wama_watt.state < 1) wama_status.postUpdate(MODE_OFF)
    else if (steckdose_bz_wama_watt.state > 5) wama_status.postUpdate(MODE_ACTIVE)
    else if (steckdose_bz_wama_watt.state < 4.5) {
        if (wama_status.state == MODE_OFF) wama_status.postUpdate(MODE_STANDBY)
        else if (wama_status.state == MODE_ACTIVE) {
		wama_status.postUpdate(MODE_FINISHED)
		echo_wohnzimmer_TTS.sendCommand('Ich glaube die Waschmaschine ist fertig') 
		sendTelegram("sensorenbot", "Die Wäsche ist fertig!")
		}		
    }
end

Zusätzlich sind noch eine Telegramnachricht und eine Alexa Sprachausgabe eingebaut.

Quelle: https://community.openhab.org/t/washing-machine-state-machine/15587

Hallo alle, hier ist alles!

Hallo alle, hier ist alles!

Hier ist eine kleine Ansammlung an Codeschnipseln und Gedanken zu allem was mit OpenHAB, Smart Home, Apple, Essen, Trinken und dem Leben zu tun hat. Also der ganz normale Wahnsinn.