Schlagwort-Archive: Linux

Poor mans PC-Interface – Multimeter per Webcam auslesen

Improvisieren? Kann ich. Derzeit teste ich mit einem Gerät herum, welches sich in regelmäßigen Abständen einschaltet – interessant für mich wäre es nun diese Zyklen genauer zu kennen. Zwar habe ich einige Energiekostenmessgeräte, damit lässt sich jedoch nur Min/Max bzw. der Durchschnitt errechnen, nicht jedoch wie oft das Gerät nun tatsächlich läuft. Hier würde ein Multimeter mit PC-Anbindung helfen, leider käme hierzu nur mein UniT in Frage, welches im Dauerbetrieb jedoch recht schnell mit leerer Batterie seinen Dienst einstellen würde. Meine „großen“ HPs besitzen zwar eine GPIB-Schnittstelle, den passenden PC-Adapter habe ich allerdings noch nicht fertig.

Bleibt nur ein anderer Ansatz: Optische Erkennung. Als Multimeter hält mein Rohde&Schwarz/Keithley her – durch die LEDs ist dessen Anzeige am einfachsten lesbar. Direkt davor sitzt nun eine Webcam, welche die Anzeige im Auge behält. Über die Software „motion“ stellt mein Linux-Server einen MJPEG-Stream bereit – ich bin diesen Weg gegangen, da ein ständiges Reinitialisieren der Kamera für einzelne Screenshots gerne zu Hängern führt.

Bild: https://adlerweb.info/blog/wp-content/uploads/2014/08/cam1.jpg

Ein kleiner PHP-Daemon fragt nun regelmäßig das letzte Bild ab, hierzu wird ein (modifizierter) Code des motion-Projektes verwendet:

$camurl='http://127.0.0.1:8081/';
$boundary="\n--";

$f = fopen($camurl,"r") ;

   if(!$f)
   {
        //**** cannot open
        echo "error";
   }
    else
   {
        //**** URL OK
         $r='';
         unset($p);
         while (substr_count($r,"Content-Length") != 2) $r.=fread($f,512);

         $start = strpos($r,chr(0xFF));
         $end   = strpos($r,$boundary,$start)-1;
         $frame = substr("$r",$start,$end - $start);

         //In $frame sind nun die rohen JPEG-Daten - diese können ausgegeben werden, gespeichert werden oder per imagecreatefromstring (gd) in PHP weiter verarbeitet werden
   }

Weiterhin wird das Bild passend beschnitten, gedreht und in ein invertiertes Schwarz-Weiß-Bild umgewandelt:

$src = imagecreatefromstring($frame);
$dst = imagecreatetruecolor(173,75);

imagecopy($dst, $src, 0, 0, 225, 66, 173, 75);
$dst = imagerotate($dst, 10, 0);
imagefilter($dst, IMG_FILTER_NEGATE);
imagefilter($dst, IMG_FILTER_GRAYSCALE);
imagefilter($dst, IMG_FILTER_CONTRAST, -100);

Im Anschluss wird über eine Reihe von „imagecolorat“-Abfragen für jede der 7-Segment-Stellen ein Array generiert – jedes Segment ist entweder an (1) oder aus (0). Zur besseren Erkennung wird jedes Segment an mehreren Stellen abgefragt und der Durchschnitt mit einem Schwellwert bewertet, so ist das System unempfindlicher gegen Rauschen.

Bild: https://adlerweb.info/blog/wp-content/uploads/2014/08/7SEG-208×300.png
(Im Array ist der Index entsprechend 0-6, nicht 1-7)

Am Ende steht ein Mapping, welches die erkannte Anzeige in einen Integer umwandelt

function seven2int($p) {
    $map[1][1][1][0][1][1][1] = 0;
    $map[0][1][0][0][1][0][0] = 1;
    $map[0][0][1][0][0][1][0] = 1;
    $map[1][0][1][1][1][0][1] = 2;
    $map[1][0][1][1][0][1][1] = 3;
    $map[0][1][1][1][0][1][0] = 4;
    $map[1][1][0][1][0][1][1] = 5;
    $map[1][1][0][1][1][1][1] = 6;
    $map[0][1][0][1][1][1][1] = 6;
    $map[1][0][1][0][0][1][0] = 7;
    $map[1][1][1][1][1][1][1] = 8;
    $map[1][1][1][1][0][1][0] = 9;
    $map[1][1][1][1][0][1][1] = 9;

    if(isset($map[$p[0]][$p[1]][$p[2]][$p[3]][$p[4]][$p[5]][$p[6]])) {
        return $map[$p[0]][$p[1]][$p[2]][$p[3]][$p[4]][$p[5]][$p[6]];
    }else{
        return false;
    }
}

Die (passend multiplizierten) Werte ergeben den Messwert. Die Erkennung ist zwar nicht 100%ig, jedoch bei der verfügbaren Auflösung wesentlich zuverlässiger als ein klassischer OCR und ausreichend um ein paar Kurven zu zeichnen. Derzeit werden etwa 80-90% der Captures erkannt. Die meisten Fehler kommen durch ungünstiges Timing – wenn die Kamera eine Aufnahme macht während die LED-Anzeige gerade aktualisiert kommt es zu halben Zahlen.

Bild: https://adlerweb.info/blog/wp-content/uploads/2014/08/Unbenannt.png

Arch Linux: Only console users are allowed to run the X server

Üblicherweise nutze ich an meinem Haupt-PC ein Multihead-Setup, also mehrere Monitore. Was zum Arbeiten praktisch ist bringt Spiele leider gerne aus dem Tritt. Um dem aus dem Weg zu gehen habe ich bisher über startx einen zweiten X-Server gestartet – direkt aus der GUI, somit war auch Pulseaudio & Co immer direkt nutzbar. Seit einem der letzten Updates, vermutlich die neue Rootless-Funktion von xorg 1.16, erscheint nur noch die Meldung „Only console users are allowed to run the X server“.

In einem Post auf Github wird empfohlen eine Datei /etc/X11/Xwrapper.config mit dem Text „allowed_users=anybody“ zu erzeugen. Generell ein Fortschritt, nun bricht jedoch beim Start der propritäre NVidia-Treiber wie folgt zusammen:

(EE) NVIDIA(GPU-0): EVO Push buffer channel allocation failed
(EE) NVIDIA(GPU-0): Failed to allocate EVO core DMA push buffer
(EE) NVIDIA(0): Failing initialization of X screen 0

Leider konnte ich den genauen Auslöser nicht finden – die Rechte sinds nicht, setuid/setgid oder start als root zeigt keine Änderung. Auch ein Wechsel auf die freien Nouveau-Treiber zeigt keine Änderung, hier kann in der zweiten Sitzung kein DRI inizialisiert werden. Glücklicherweise hat der freie Treiber deutlich weniger Rendering-Bugs – nicht nur, dass Chromium endlich wieder nutzbar ist – auch Spiele laufen nun im Multi-Monitor-Modus. Zwar erscheint das Bild immer auf den linken Monitor, aber mit einem VGA-Umschalter als Hardware-Workarround kann ich mir da behelfen.

Attributfehler bei der Verwendung von PyGst

Bei der Verwendung der Python-Bindungen von GStreamer hagelte es auf einem System unverständliche Fehler nach dem Muster AttributeError: 'NoneType' object has no attribute 'get_static_pad_templates' – Auslöser war in diesem Falle ein fehlender GStreamer-Codec, die Installation der zugehörigen Plugins sorgte für Abhilfe

CURL & OpenSSL – Zertifikatsfehler

In den letzten Tagen hatte ich einige seltsame Ergebnisse bei CURL – einige URLs wurden wegen eines fehlerhaften Zertifikatsunterschrift abgelehnt:

Cannot connect to URL : Peer certificate cannot be authenticated with known CA certificates: SSL certificate problem, verify that the CA cert is OK. Details:
[…]routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

Seltsamerweise ist manuell sowohl Zertifikat als auch CA fehlerfrei, letztere ist auch in /etc/ssl/certs/ korrekt hinterlegt. Laut diversen Posts handelt es sich wohl um einen Fehler in OpenSSL – um vorerst Ruhe zu bekommen habe ich curl nun unter Gentoo mit CURL_SSL=“gnutls“ oder CURL_SSL=“polarssl“ installiert und bisher keine Probleme mehr. Für Ubuntu wäre libcurl4-gnutls-dev der richtige Startpunkt.

VsFTPd 3.x und 64Bit-Server

Bein Aufsetzen eines FTP-Servers mittels VsFTPd kam es zu einem etwas anderen Problem: Der Server startete, beim Connect erhielt der Client jedoch lediglich die Meldung „500 OOPS: child died“. Im Log selbst war keine Meldung auffindbar.

Auslöser ist offenbar ein zu strikter Sicherheitsfilter in Verbindung mit 64Bit-Kerneln. Gentoo scheint nicht betroffen zu sein, dort lief die Version 3.0.2 fehlerfrei, selbige unter Arch Linux verursacht den Fehler. Als Workarround kann man die neuen Sicherheitsfunktionen durch setzen des Wertes „seccomp_sandbox=NO“ in der vsftpd.conf abschalten.

Gentoo: Abbruch beim Update auf Qemu 2.x bei Nutzung von libvirt

Das letzte world-Update eines Gentoo-Servers war etwas aufwändiger als üblich: Die betroffene Kiste kümmert sich unter anderem per libvirt und qemu um Virtualisierung, letzteres sollte mit dem Update von einer 1.5.x-Version auf eine 2.x aktualisiert werden. Mit der neuen Qemu-Version haben sich jedoch einige wichtige Dinge geändert, so gibt es nun keine zentrale Datei zum Start von VMs mehr. Auch die KVM-Unterstützung ist nicht länger als eigener Wrapper vonhanden. Statt einem bösen Erwachen fängt glücklicherweise das Update – bei Verwendung von Libvirt – eine veraltete Konfiguration ab und führt zu einer Fehlermeldung:

* The kvm/qemu-kvm wrappers no longer exist, but your libvirt
* instances are still pointing to it. Please update your
* configs in /etc/libvirt/qemu/ to use the -enable-kvm flag
* and the right system binary (e.g. qemu-system-x86_64).
* ERROR: app-emulation/qemu-2.0.0::gentoo failed (pretend phase):
* update your virt configs to not use qemu-kvm
*
* Call stack:
* ebuild.sh, line 93: Called pkg_pretend
* qemu-2.0.0.ebuild, line 225: Called die
* The specific snippet of code:
* die „update your virt configs to not use qemu-kvm“

Schauen wir mal nach – in /etc/libvirt/qemu liegt für jede VM eine XML-Datei mit allen Einstellungen, unter anderem findet sich in jeder der Dateien ein Eintrag <emulator>/usr/bin/qemu-kvm</emulator>, welcher mit dem „neuen“ Pfad des Emulators, also „qemu-system-x86_64“ für einen 64Bit-x86-Client, ersetzt werden muss. Die KVM-Erweiterung muss man hierbei nicht beachten, Libvirt gibt die nötigen Argumente zum aktivieren des Virtualisierungsmodus automatisch mit. Also Texteditor auf und ran ans Editieren, richtig? Nunja, das geht bei 2 oder 3 VMs, ich hab da aber ein paar mehr, also muss folgender Einzeiler herhalten:

for i in /etc/libvirt/qemu/*.xml ;do mv "$i" "$i.backup" && sed 's/\/usr\/bin\/qemu-kvm/\/usr\/bin\/qemu-system-x86_64/' "$i.backup" > "$i" ;done

Hinweis: Der Einzeiler lässt die Originaldateien als Backup zurück – wenn alles funktioniert hat können die Dateien mit der Endung *.backup entfernt werden.

Nachdem die XML-Dateien angepasst wurden lässt sich das Qemu-Update wie gewohnt installieren.

Renicetree – renice a process including it’s children

./configure && make – aw crap.

Immer wieder passiert es mir, dass ich längere Prozesse starte ohne ein „nice“ davor zu setzen. Ergebnis: Der Kompiliervorgang o.Ä. hat die selbe Priorität wie alles andere und zieht die Reaktionsfähigkeit des PC deutlich in den Keller. Üblicherweise kann man nun mir „renice“ den Prozess nachträglich herunterstufen, jedoch klappt das gerade bei Kompiliervorgängen nicht sonderlich gut: renice ändert lediglich die Priorität des angegebenen Prozesses, hierdurch werden auch neu erstellte Kindprozesse erfasst, bereits laufende jedoch nicht. Da Make teils sehr verschachtelt arbeitet und Jobprozessoren zur Verteilung der Aufträge nutzt muss man z.T. einige Prozesse ändern um das System wieder lauffähig zu machen. Hier z.B. der make-Baum eines OpenWRT:

make(25087)->sh(25209)->make(25211)-|->bash(25214)->make(25237)
                                    |->bash(25229)->make(25240)

Da ich keine Lust mehr hatte ständig die nötigen IDs per Hand zu suchen ist renicetree entstanden. Es sucht alle zu einer PID gehörigen Kindprozesse und setzt auch für diese ein renice ab. Um halbwegs kompatibel zu bleiben ist die Software in einer Bash-Syntax entstanden.

Da ich keinerlei erweiterte Ahnung von Shell-Scripting habe dürfte der Code bei Profis vermutlich Haarraufen verursachen, aber er läuft immerhin – auch wenn mir die Eigenheiten der Bash gewaltig auf den Nerv gingen (Keine mehrdimensionalen Arrays, keine indirekte Variabelreferenzen, etc). Script gibt’s wie immer auf Github. Use at your own risk.


Update: Ich wurde darauf hingewiesen, dass renice über die Process Group ID (-g) eine ähnliche Funktion bereits bieten würde. Das kann ich – zumindest für GUI-Betrieb – nicht bestätigen, hier hat z.B. alles unter meinem Terminal-Emulator die selbe Gruppen-ID, also auch Prozesse, welche in einem anderen Tab gestartet sind.

Intel Haswell-ULT Integrated Graphics: TFT-Backlight reagiert langsam

Auf einem Laptop mit Intel Haswell-ULT GPU hatte ich das Phänomen, dass jede Änderung der TFT-Beleuchtungsstufe das System für etwa eine Sekunde einfrieren lies. Besonders ärgerlich, wenn dies wegen Inaktivität automatisch veranlasst wurde, denn in diesem Fall wird ein Fade-Effekt mit mehreren Stufen gefahren – und der Laptop so für etwa 20 Sekunden unbenutzbar.

Auffällig bei diesem Gerät: In /sys/class/backlight/ sind gleich 2 Schnittstellen gelistet: acpi_video0 und intel_backlight. Erstere zeigt das beobachtete Delay, letzeres reagiert ohne spurbare Verzögerung. Um den X.Org-Automatismen die schnellere Schnittstelle ans Herz zu legen muss in /etc/X11/xorg.conf.d/20-intel.conf oder anderer passender Stelle folgender Code gesetzt werden:

Section "Device"
   Identifier  "Intel Graphics"
   Driver      "intel"
   Option      "Backlight"  "intel_backlight"
EndSection

Intel Core i-Prozessoren und die Govenors

Unter Linux wird/wurde die Frequenz der Prozessoren bisher durch das cpufreq-Backend des Kernels geregelt. Es gab verschiedene „Govenors“, welche je eine Eintscheidungsart implementierten. Beispiel:

ondemand CPU auf kleinster Taktfrequenz, wird bei Last erhöht
performance CPU immer auf maximaler Taktfrequenz
powersave CPU immer auf kleinster Taktfrequenz

Mit den neuen Core i-Prozessoren (i3,i5,i7) ist dieses Konzept nur noch bedingt brauchbar – die CPU selbst hat viele Mechanismen um Strom zu sparen, sie muss allerdings „aufwachen“ um über den Govenor entscheiden zu können, ob die Beschäftigt ist oder nicht. Da hierdurch die dynamische Frequenzregelung am Ende mehr Strom verbraucht als ein Prozessor, welcher sich auf höchster Taktrate selbst verwaltet, bieten neue Kernel nun nur noch powersave oder performance für diese Prozessoren an. Für Intel empfiehlt sich „powersave“ zu wählen, durch die TurboBoost-Technologie erhöht die CPU ihren Takt bei entsprechender Last selbstständig. Mit Tools wie z.B. i7z lässt sich die Frequenzänderung auch entsprechend beobachten.

tl;dr: Intel-CPUs nur mit powersave-Govenor betreiben, CPU regelt Takt selbst passend hoch.

btrfs und die delayed allocations (btrfs-delalloc)

Vor etwa einem Jahr hatte btrfs bei mir den Status „beste wo (derzeit für mich) gibt“ erhalten. RAID-Funktionen sind mir zwar im erprobten MD-Code lieber, aber endlich ein Dateisystem mit Kompression ohne Lizenzgewürge. Leider hält die Praxis der damaligen Erwartung – zumindest bei mir – nicht stand. Offenbar gibt es derzeit lediglich einen Thread namens „btrfs-delalloc-„, welcher sich um das Schreiben der Daten kümmert – und das nicht sonderlich schnell. Vor allem bei größeren Datenmengen macht sich dieses Konzept negativ bemerkbar: Vor etwa 15 Minuten beispielsweise wanderten 15GB eines Videoprojektes per NFS auf meienen Server. Der Vorgang lief schön flott, aber kurz drauf war Schluss. Keine HTTP-Antworten, keine neuen SSH-Verbindungen. Auf einer bereits offenen Konsole zeigt sich das gewohnte Bild: Ein Prozess namens „btrfs-delalloc-“ hängt auf 100% CPU, IO-Wait an der Decke und nichts reagiert mehr. (Anm: WWW und System liegen auf einem physikalisch separaten Speicher, da hängts sicher nicht…). Mir erscheint es so, als ob dieser Prozess sich um alle btrfs-Mounts kümmert – ist einer ausgelastet ist auch für alle anderen Sendepause. Sehr unschön.

Bis jetzt habe ich noch nicht so ganz raus, was es mit dem Prozess auf sich hat, aber wenn sich da keine Abhilfe findet muss auf dauer wohl doch wieder fusecompress mit einem reiferen Dateisystem aushelfen :/.