<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on gillwaldt</title><link>https://www.gillwaldt.de/posts/</link><description>Recent content in Posts on gillwaldt</description><generator>Hugo -- gohugo.io</generator><language>de-DE</language><copyright>This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.</copyright><lastBuildDate>Sun, 22 Sep 2024 13:37:00 +0200</lastBuildDate><atom:link href="https://www.gillwaldt.de/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Umzug</title><link>https://www.gillwaldt.de/posts/2024/umzug/</link><pubDate>Sun, 22 Sep 2024 13:37:00 +0200</pubDate><guid>https://www.gillwaldt.de/posts/2024/umzug/</guid><description>%!s(&lt;nil>)</description><content type="html"><![CDATA[<h2 id="tldr">TL;DR;</h2>
<p>Ich belebe meine Homepage (mal wieder) neu und werde hoffentlich öfter dazu kommen hier etwas zu posten. Es is viel passiert.</p>
<h2 id="was-bisher-geschah">Was bisher geschah</h2>
<p>Seit meinem letzten Update hier ist ja nun schon eine Weile vergangen und in der Zwischenzeit ist eine Menge passiert, ich fass&rsquo; das mal kurz zusammen.</p>
<h3 id="umzug">Umzug</h3>
<p>Nach einer Eigenbedarfskündigung mussten wir uns was Neues suchen. Der Berliner Wohnungsmarkt ist total kaputt zur Zeit. Wir hatten Besichtigungen mit 60 und mehr Leuten auf Wohnungen, die bestenfalls mittel-gut waren. Um es kurz zu machen, wir haben eine schöne Wohnung im Süden von Berlin gefunden. Es war schon eine gewisse Umstellung vom Wedding nach Licherfelde Süd, hier ist alles sehr viel ruhiger. Nach Jahren mit Baustellen, gleich nebenan oder Dachausbauten im Hinterhaus, die sich fast ein Jahr hingezogen haben, kann man hier Homeoffice machen ohne die Fenster schließen zu müssen.</p>
<h3 id="jobs">Jobs</h3>
<p>Beruflich habe ich auch einige Fortschritte gemacht.</p>
<h4 id="berlin-direkt-versicherung">Berlin Direkt Versicherung</h4>
<p>Bei der <a href="https://www.berlin-direktversicherung.de/" title="Berlin Direkt Versicherung">BD24</a> war ich damals als .Net Developer angestellt, der Job und Teamleiter waren toll und ich konnte mich Richtung <a href="https://de.wikipedia.org/wiki/DevOps" title="DevOps Engineer">DevOps</a> weiterentwickeln. Im Grunde habe ich ja schon immer versucht Dinge in der IT zu automatisieren. Das macht mir einfach sehr viel Spaß. Als mein Teamleiter die <a href="https://www.berlin-direktversicherung.de/" title="Berlin Direkt Versicherung">BD24</a> verließ, war das auch für mich der Zeitpunkt mich nach neuen Herausforderungen umzuschauen. Ich habe mir damals <a href="https://www.linkedin.com">LinkedIn</a> und <a href="https://www.xing.com">Xing</a> Profile angelegt und wurde sofort von Personalvermittlern regelrecht zugespammt.</p>
<h4 id="bundesdruckerei">Bundesdruckerei</h4>
<p>Am Ende entschied ich mich für eine Stelle als <a href="https://de.wikipedia.org/wiki/DevOps" title="DevOps Engineer">DevOps</a> bei der <a href="https://www.bundesdruckerei.de">bdr</a>, vermutlich auch weil ich dort am ehesten das Gefühl hatte in ein Team zu kommen und an spannenden Aufgaben arbeiten zu können. Ich hatte bei den anderen Jobangeboten, auch wenn sie finanziell attraktiver waren, irgendwie immer das Gefühl die suchen zu verzweifelt.</p>
<h4 id="charité">Charité</h4>
<p>Nach etwas über zwei Jahren bei der <a href="https://www.bundesdruckerei.de">bdr</a>, bot sich mir die Gelegenheit zur <a href="https://www.charite.de/">Charité</a> zu wechseln und mit meinem Teamleiter von <a href="https://www.berlin-direktversicherung.de/" title="Berlin Direkt Versicherung">BD24</a> dort etwas Neues aufzubauen. Da konnte ich einfach nicht wiederstehen. Hier werde ich vermutlich in späteren Posts mehr dazu erzählen.</p>
<h3 id="verbesserungen">Verbesserungen</h3>
<p>Mit dem Umzug bot sich die Möglichkeit ein paar Verbesserungen vorzunehmen. Ich werde auf ein paar Dinge, davon in späteren Post mehr berichten, aber unteranderem wurde in neue Büromöbel, PC-Hardware, Netzwerk, Verkabelung, Internetanbindung und vieles mehr invenstiert.</p>
<h2 id="das-wars-erstmal">Das wars erstmal</h2>
<p>Ein kleiner Teaser vielleicht noch: Ich habe angefangen ein wenig mit Holz Dinge zu bauen, macht mir sehr viel Spaß.</p>
]]></content></item><item><title>Raspberry Pi Gehäuse</title><link>https://www.gillwaldt.de/posts/2019/raspberry-pi-gehaeuse/</link><pubDate>Tue, 07 May 2019 23:45:06 +0200</pubDate><guid>https://www.gillwaldt.de/posts/2019/raspberry-pi-gehaeuse/</guid><description>%!s(&lt;nil>)</description><content type="html"><![CDATA[<p>Eines vorweg, dass ist mein erstes 3D-Druck Projekt.</p>
<h2 id="tltr">TL:TR</h2>
<p>Ein Raspberry Pi 3 unter Last braucht eine aktive Kühlung, sonst drosselt er sich.
Normale Gehäuse bieten maximal 40mm Lüfter, die sind zu laut und lassen sich nicht
regeln. Dies ist mein Entwurf für ein Gehäuse mit Platz für einen 4-Pin PWM
80mm Lüfter. STL-Files: <a href="top-raspberry-pi-case-v1.stl">Oberteil</a>, <a href="basis-raspberry-pi-case-v1.stl">Basis</a></p>
<h2 id="ausgangssituation">Ausgangssituation</h2>
<p>Ich betreibe mehrere Webdienste intern in meinem lokalen Netzwerk zu Hause. Um
diese Dienste aus dem Internet erreichbar zu machen, betreibe ich einen kleinen
<a href="https://de.wikipedia.org/wiki/Reverse_Proxy">Reverse-SSL-Proxy</a>. Der Proxy hat zwei Aufgaben, erstens werden die internen
Webdienste unter einer URL (mit verschiedenen Pfaden) zusammengefasst und aus
dem Internet verfügbar gemacht. Zweitens werden alle intern unverschlüsselten
Webdienste nach aussen über https angeboten.</p>
<h2 id="das-problem">Das Problem</h2>
<p>Der Reverse-SSL-Proxy läuft auf einem Raspberry Pi 3B in einem kleinen Gehäuse
mit Wandbefestigung. Jeder Zugriff auf einen internen Webdienst muss durch
diesen kleinen ARM-Rechner und erzeugt damit CPU-Last, dies bedeutet Abwärme.
Ein kleiner Test mit dem <a href="https://httpd.apache.org/docs/2.4/programs/ab.html">Apache HTTP server benchmarking tool</a> zeigt, dass
bereits nach weniger als hundert Anfragen, die CPU des Raspberrys so heiß wird,
dass er beginnt sich selbst zu drosseln. Zusammengefasst: Ein Raspberry Pi 3B
unter Last benötigt einen Lüfter. In den gängigen Gehäusen passt maximal ein
<a href="https://www.google.com/search?tbm=isch&amp;q=40mm+fan&amp;oq=40mm+fan">40mm DC Lüfter</a>. Die kleinen Dinger sind laut und lassen sich schlecht regeln.
Zum diesem Zeitpunkt gab es auf <a href="https://www.thingiverse.com/search?q=pi+fan+80mm">thingiverse.com</a> leider nur Gehäuse für
wirklich große Lüfter (ab 120mm), meist wird dort noch eine
Schrittmotorensteuerung für CNC-Fräsen oder 3D-Drucker mit gekühlt. Das ist zu
groß für meine Zwecke.</p>
<p>Ein anderes Problem ist die Stromversorgung. Der Pi 3B(+) möchte mit mindestens
2.5A bei 5V versorgt werden. Der Pi 3B(+) ist da sehr viel anspruchsvoller als
seine Vorgägner, bei schlechter Stromversorgung gibt es schnell eine
&lsquo;undervoltage&rsquo; Warnung. Gute USB-Kabel sind sehr wichtig, allerdings habe ich bisher
kein Kabel gefunden das länger als 2m ist und den Pi stabil versorgt. Das liegt
unter anderem am Innenwiderstand der USB-Kabel, an der niedrigen Spannung und
daran das die gängigen Netzteile die Spannung nicht nachregeln.</p>
<h2 id="die-idee">Die Idee</h2>
<p>Ich bräuchte ein Gehäuse, mit Platz für einen flachen <a href="https://www.akasa.co.uk/search.php?seed=AK-FN076">80mm 4-Pin PWM Lüfter</a>
und einen StepUp-Wandler (12V zu 5V/3A). Wandmontage sollte möglich sein, am
besten so das man noch an die MicroSD-Karte kommt. Der Lüfter sollte nicht
direkt mit dem Gehäuse verschraubt werden, besser ist eine Verbindung mit Gummi.
Lüftungsschlitze müssen vorhanden sein, möglichst nicht oben, es soll ja nicht
ins Gehäuse stauben.</p>
<h2 id="der-entwurf">Der Entwurf</h2>
<p>Der Pi braucht 85x56mm Grundfläche, um ihn dann noch mit Strom zu versorgen,
braucht man noch etwas Platz für den Micro-USB-Stecker. Das heißt der Pi wird
nicht symetrisch in der Mitte liegen, sondern am rechten Rand. Mein <a href="https://www.akasa.co.uk/search.php?seed=AK-FN076">80mm 4-Pin
PWM Lüfter</a> ist etwas über 10mm hoch und es muss noch etwas Platz für die
Gummidämpfer eingeplant werden. Mit diesen Rahmenbedingungen und meinem Wunsch
nach geraden Werten, ergibt sich eine ungefähre Gehäusegröße von 100x100x50mm.</p>
<p>Dann brauche ich Halterungen für den Pi, Aussparungen für USB, Netzwerk,
MicroSD-Karte und einen Rundstecker (12V Versorgungsspannung). Lüftungsschlitze
an den Seiten und im Deckel und irgendetwas um den Lüfter zu befestigen und um
den StepUp-Wanlder zu fixieren.</p>
<h2 id="die-software">Die Software</h2>
<p>Ich hatte bisher noch nie selbst mit 3D-Modelierung zu tun. Die meisten
Anwendungen sahen für meinen Geschmack zu kompliziert aus. Ansprechend und
einfach sah <a href="https://www.tinkercad.com/">TinkerCAD</a> von <a href="https://www.autodesk.com/">Autodesk</a> aus. Ich war zuerst etwas skeptisch, da
die Anwendung komplett im Browser läuft. Insgesamt bin ich positiv überrascht
worden. Das Konzept und die Bedienung sind definitv an Anfänger gerichtet.</p>
<p>Im Grunde zieht man einfache geometrische Objekte, wie Quader, Kugeln oder
Zylinder von der Seite auf die Arbeitsfläche und kann dessen Grösse dann in
allen Dimensionen anpassen. Man bestimmt ob die Objekte massiv sind oder
Aussparungen haben und dann kann man die Objekte verschmelzen.</p>
<p>Zur Ausrichtung der Objekte kann man nur zentriert, sowie links- oder
rechtsbündig wählen. Genau hier merkt man dann auch die Zielgruppe, ein Objekt
millimetergenau zu positionieren geht nur über selbst erstellte Hilfsobjekte.</p>
<h2 id="das-model">Das Model</h2>
<p>Die Konstruktion war recht straightforward. Als erstes habe ich auf der 100x100mm
Grundfläche die Halterungen für den Pi positioniert. Zur Befestigung drückt man
[M2,5] Muttern in die Unterseite der Grundplatte, dann lässt sich der Pi mit
Schrauben von oben fixieren. Die Grundplatte brauchte dann noch eine Aussparung,
um von aussen an die MicroSD-Karte zu kommen und schließlich noch ein paar
Laschen für Kabelbinder, hier wird später der StepDown-Wandler zur
Stromversorgung befestigt. In die Seitenteile habe ich Lüftungsschlitze eingefügt
und in der Vorderseite Aussparungen für Netzwerk, USB und eine 5,5x2,1mm Hohlbuchse.</p>
<p>Der Deckel braucht auch Lüftungsschlitze, hier habe ich eine Wabenstruktur
gewählt, da dies wohl etwas stabiler ist und besser aussieht. Innen braucht man
kleine Taschen um die Gummidämpfer zur Lüfterfixierung zu befestigen. Fertig.</p>
<p><img src="model_ver1.png" alt="3D-Model" title="3D-Model">
bnsp;</p>
<h2 id="der-druck">Der Druck</h2>
<p>Ich selbst habe noch keinen 3D-Drucker, deshalb war meine erste Idee das Model
bei einem der vielen kommerziellen Anbieter im Internet drucken zu lassen.
Kurzum - das war mir zu teuer, vor allem, weil es sich um einen ersten Entwurf
handelt. Ich hatte ja keine Ahnung ob das alles am Ende auch so passt wie ich
mir das gedacht habe.</p>
<p>In der Nähe von mir wibt die <a href="https://www.berlin.de/stadtbibliothek-mitte/bibliotheken/schiller-bibliothek-mit-hugojugendmedienetage/">Schiller-Bibliothek</a> damit, dass sie einen
Makerspace hat, also bin ich dahin um dort vielleicht zu drucken. Leider
versteht man in der Bibliothek etwas anderes unter Makerspace. Dort wird die
Möglichkeit geboten einmal im Monat ein Objekt von thingiverse zu laden und
zu drucken, vorausgesetzt es dauert nicht zu lange. Wenn die beantragten
Fördermittel bewilligt werden, soll das auf einmal die Woche erhöht werden.
Das bietet eine schöne Gelegenheit sich mal 3D-Druck anzuschauen, ist aber keine
Lösung für mich.</p>
<p>Auf der Suche nach &ldquo;richtigen&rdquo; Makerspaces, nach dem Prinzip der offenen
Werkstatt, bin ich auf das <a href="https://www.happylab.at/de_ber/home">HappyLab</a> gestossen. Die haben einen Industrie
3D-Drucker, der wäre im Prinzip schon gut gewesen, leider wollen sie 0,45€ pro
cm³ Druck- bzw. Stützmaterial. Ich verwende dünnere Wände als sie minimal
empfehlen und würde dort dennoch etwa 40€ zahlen.</p>
<p>Am Ende bot mir ein Freund an, dass am Wochenende bei ihm auf der Arbeit zu
drucken. Der Chef hatte sich vor einer Weile einen <a href="https://www.creality3d.cn/creality3d-cr-10-s5-p00099p1.html">Creality3D CR-10 S5</a>
zugelegt und meinte das wäre ok wenn wir den am Wochenende mal benutzen.
Der erste Versuch lief leider schief, irgendwann nach zwei oder drei Lagen
stockte der Filamentnachschub und der Drucker arbeitete fleissig in der Luft
weiter. Als wir das bemerkten war es bereits zu spät.</p>
<p>bnsp;
<img src="case-top-printing.png" alt="printing&hellip;" title="printing...">
bnsp;</p>
<p>Beim zweiten Versuch haben wir den Deckel des Gehäuses fertig gedruckt, dass hat
sehr viel länger gedauert als ich dachte. Wir haben auf anraten des Chefs mit
weniger als 50% Druckgeschwindikeit gedruckt. Die Ecken des Deckels haben sich
um einen Millimeter von der Glasplatte gelöst und angehoben, dass sieht man auch
wenn man genau hinschaut, aber stört mich nicht sonderlich. Das Unterteil des
Gehäuses haben wir dann über Nacht drucken lassen mit 35% Druckgeschwindigkeit.
Das Ergebnis ist gut. Leider sind auch bei der niedriegen Druckgeschwindigkeit
die Ecken etwas hochgekommen.</p>
<p><img src="case-both-parts.png" alt="fertiges Gehäuse" title="fertiges Gehäuse">
bnsp;</p>
<h2 id="die-montage">Die Montage</h2>
<p>Der Lüfter wurde, zwecks Geräuschminimierung, mit Entkoppel-Gummies im Deckel
befestigt. Die Gummidämpfer habe ich mit einem Tropfen Sekundenkleber in den
Aussparungen im Deckel geklebt, damit bleiben sie dehnbar genug um den Lüfter
wechseln zu können.</p>
<p>Um das Stromversorgungsproblem zu beheben, habe ich einen StepDown-Wandler
verwendet. Die hier verwendete <a href="https://de.aliexpress.com/wholesale?SearchText=%22QC3.0%22+USB+DC-DC+Step+Down+apple">QC3-StepDown-Wandler</a> ist im Grunde der Kern
eines USB-Ladegeräts. Den Wandler betreibe ich mit einem normalen 12V Netzteil.</p>
<p>bnsp;
<img src="qc3-stepdown.png" alt="12V zu 5V PSU" title="12V zu 5V PSU">
bnsp;</p>
<p>Im Grunde kann der Wandler viel mehr, er beherrscht QuickCharge3 und kann bis
zu 12V und 24W liefern. Zudem kostet er nur etwas über 1€. Die für mich wichtigste
Funktion ist, dass er nachregelt, d.h. wenn der Pi wirklich mal Strom zieht und
die Spannung runtergeht, erhöht der Wandler automatisch die Spannung um über 5V
zu bleiben. Der Plan war den StepDown-Wandler mittels super kurzem Kabel
anzuschließen. Leider habe ich kein passendes USB-zu-MicroUSB Kabel gefunden.
Alle Kabel waren zu lang oder zu unflexibel. Ich habe mich also enschlossen den
Pi direkt über seine PINs mit Strom zu versorgen. Damit umgeht man die
Sicherungen des Raspberry. Man muss also sehr aufpassen, vertut man sich hier
mit der PIN-Belegung ist der Pi recht schnell hin.</p>
<p>Schließlich muss noch der Lüfter mit 12V versorgt werden und der PWM- und der
Tacho-Pin mit dem Raspberry verbunden werden.</p>
<h2 id="die-lüfterbeschaltung">Die Lüfterbeschaltung</h2>
<p>Der Raspberry Pi kann max. 3.3V an seinen PINs ab, mehr zerstört ihn sehr schnell.
Beim Tacho- und PWM-Pin des Lüfters kann es sein, je nach Lüfter-Bauart, dass
dort kurzzeitig mehr als 3.3V anliegen. Also habe ich mir eine <a href="https://www.pavouk.org/hw/fan/en_fan4wire.html">kleine
Schutzschaltung aus dem Internet</a> gesucht, die den Pi vor zu hohen Strömen
schützt.</p>
<p>bnsp;
<img src="schutzschaltung.png" alt="Schutzschaltung" title="Schutzschaltung">
bnsp;</p>
<p>Mein erster Versuch war es, dies mit in die Verkabelung einzubauen. Das hat
nicht so gut funktioniert. Ich habe die Schaltung dann einfach auf einer
Lochstreifenraster-Platine aufgebaut und mit Schrumpfschlauch isoliert.
Die zusätzliche kleine Platine im Gehäuse unterzubringen war eine
Herausvorderung. Sie klemmt jetzt auf der Oberseite vom MicroSD Karten Slot,
zwischen Pi und Gehäusewand. Das hält erstaunlich gut.</p>
<h2 id="inbetriebnahme">Inbetriebnahme</h2>
<p>An der Wand befestigt fand ich den Deckel etwas locker. Laut 3D-Model sind etwa
0,2mm Platz zwischen Deckel und Gehäuse. Ich habe einfach ein paar Lagen Tesafilm
auf die Gehäuse Kanten geklebt, der Deckel verdeckt diese und durch die Extralagen
sitzt der Deckel nun schön fest.</p>
<p>bnsp;
<img src="case-in-action.png" alt="case in action" title="case in action">
bnsp;</p>
<h2 id="die-steuerung">Die Steuerung</h2>
<p>Ziel war es, dass der Pi aktiv gekühlt wird, wenn dieser Kühlung benötigt. Im
normalen Betrieb kann der Lüfter so langsam drehen wie möglich, wenn technisch
möglich sogar stehen bleiben. Die Frage war nun, wie aktiv soll die
Temperaturüberwachung sein.</p>
<p>Meine erste Idee war ein Skript, welchen per Cronjob jede Minute aufgerufen
wird. Nach meinen Beobachtungen steigt und fällt die Temperatur der CPU aber sehr
viel schneller. Unter Last dauert es nur Sekunden bis der Pi in den Bereich
kommt, in dem er ohne Kühlung drosseln würde. Ein Minuten-Interval ist einfach
zu langsam.</p>
<p>Ideal wäre eine Regelung, welche direkt bei einer Temperaturänderung anlaufen
würde. Meine Lösung ist nicht ganz so perfekt, sollte aber auch gut genug
funktionieren. Ich lese in einem einstellbaren Interval (zur Zeit 10s) die
CPU-Temperatur aus und passe danach die Lüfterdrehzahl an.</p>
<p>Um aus dem Tachosignal eine Drehzahl zu bekommen gibt es verschiedene Methoden.
Das Tachosignal liefert pro Umdrehung des Lüfters zwei Impulse. Ich habe
mehrere Methoden ausprobiert, um aus dem Tachosignal eine Umdrehungszahl zu
berechnen, keine funktionierte so wie ich mir das vorstellte.</p>
<p>Die besten Ergebnisse erzielte ich, wenn ich die Dauer von mehreren fallenden
Flanken des Tachosignals messe und dann über durchschnittliche Dauer zwischen
zwei Impulsen die Drehzahl errechne. Das liefert gute Ergebnisse, solange man
nicht während der Beschleunigung misst.</p>
<p>bnsp;
<img src="kurve.png" alt="Temperatur-Drehzahl-Kurve" title="Temperatur-Drehzahl-Kurve">
bnsp;</p>
<p>Ich habe zwei Temperaturpunkte definiert, bis zum Punkt A soll der Lüfter mit
minimaler Drehzahl laufen, ab dann soll der Lüfter bis zum Punkt B
beschleunigen. Über Punkt B soll der Lüfter mit voller Drehzahl laufen.</p>
<h2 id="monitoring">Monitoring</h2>
<p>Die CPU-Temperatur wird schon an mein Monitoring übertragen. Die Lüfterdrehzahl
möchte ich auch gern aufzeichen. Problematisch ist eine Drehzahlmessung während der
Regelung, da diese oft unsinnige Drehzahlen liefert</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="ch">#!/usr/bin/python3 -u</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">RPi.GPIO</span> <span class="k">as</span> <span class="nn">gpio</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">wiringpi</span><span class="o">,</span> <span class="nn">time</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">pin_pwm</span> <span class="o">=</span> <span class="mi">18</span>
</span></span><span class="line"><span class="cl"><span class="n">wiringpi</span><span class="o">.</span><span class="n">wiringPiSetupGpio</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">wiringpi</span><span class="o">.</span><span class="n">pinMode</span><span class="p">(</span><span class="n">pin_pwm</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span> <span class="c1"># hardware pwm mode</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">pin_tacho_bcm</span> <span class="o">=</span> <span class="mi">23</span>
</span></span><span class="line"><span class="cl"><span class="n">gpio</span><span class="o">.</span><span class="n">setmode</span><span class="p">(</span><span class="n">gpio</span><span class="o">.</span><span class="n">BCM</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">gpio</span><span class="o">.</span><span class="n">setup</span><span class="p">(</span><span class="n">pin_tacho_bcm</span><span class="p">,</span> <span class="n">gpio</span><span class="o">.</span><span class="n">IN</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">wait_seconds_before_next_loop</span> <span class="o">=</span> <span class="mi">5</span>
</span></span><span class="line"><span class="cl"><span class="n">wait_seconds_after_pwm_change_before_measure_rpm</span> <span class="o">=</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="n">temp_rpm_start_raise</span> <span class="o">=</span> <span class="mi">45</span>
</span></span><span class="line"><span class="cl"><span class="n">temp_rpm_full_speed</span> <span class="o">=</span> <span class="mi">67</span>
</span></span><span class="line"><span class="cl"><span class="n">last_temperature</span> <span class="o">=</span> <span class="n">temp_rpm_start_raise</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># measure: rotation per minute</span>
</span></span><span class="line"><span class="cl">        <span class="n">count_cycles_for_average</span> <span class="o">=</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl">        <span class="n">gpio</span><span class="o">.</span><span class="n">wait_for_edge</span><span class="p">(</span><span class="n">pin_tacho_bcm</span><span class="p">,</span> <span class="n">gpio</span><span class="o">.</span><span class="n">FALLING</span><span class="p">)</span> <span class="c1"># wait till falling edge</span>
</span></span><span class="line"><span class="cl">        <span class="n">start</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>                             <span class="c1"># start stopwatch</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">impulse_count</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">count_cycles_for_average</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">gpio</span><span class="o">.</span><span class="n">wait_for_edge</span><span class="p">(</span><span class="n">pin_tacho_bcm</span><span class="p">,</span> <span class="n">gpio</span><span class="o">.</span><span class="n">FALLING</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">duration</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">start</span>                  <span class="c1"># stop stopwatch</span>
</span></span><span class="line"><span class="cl">        <span class="n">frequency</span> <span class="o">=</span> <span class="n">count_cycles_for_average</span> <span class="o">/</span> <span class="n">duration</span> <span class="c1"># Hz</span>
</span></span><span class="line"><span class="cl">        <span class="n">rpm</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">frequency</span><span class="o">*</span><span class="mi">3</span><span class="p">)</span> <span class="o">*</span> <span class="mi">10</span>                     <span class="c1"># rpm rounded by 10</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># get temperature</span>
</span></span><span class="line"><span class="cl">        <span class="n">temperature_file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s1">&#39;/sys/class/thermal/thermal_zone0/temp&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">cur_temp</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">temperature_file</span><span class="o">.</span><span class="n">read</span><span class="p">())</span> <span class="o">/</span> <span class="mi">1000</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># if current temperature differs last temperatur</span>
</span></span><span class="line"><span class="cl">        <span class="n">new_pwm</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">cur_temp</span> <span class="o">!=</span> <span class="n">last_temperature</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># calculate new pwm value</span>
</span></span><span class="line"><span class="cl">            <span class="n">temp_span</span> <span class="o">=</span> <span class="n">temp_rpm_full_speed</span> <span class="o">-</span> <span class="n">temp_rpm_start_raise</span>
</span></span><span class="line"><span class="cl">            <span class="n">pwm_per_degree</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1024</span> <span class="o">/</span> <span class="n">temp_span</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">new_pwm</span> <span class="o">=</span> <span class="p">(</span><span class="n">cur_temp</span> <span class="o">-</span> <span class="n">temp_rpm_start_raise</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">pwm_per_degree</span>
</span></span><span class="line"><span class="cl">            <span class="n">new_pwm</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="mi">0</span> <span class="k">if</span> <span class="n">new_pwm</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="k">else</span> <span class="mi">1024</span> <span class="k">if</span> <span class="n">new_pwm</span> <span class="o">&gt;</span> <span class="mi">1024</span> <span class="k">else</span> <span class="n">new_pwm</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># set new pwm value</span>
</span></span><span class="line"><span class="cl">            <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">wiringpi</span><span class="o">.</span><span class="n">pwmWrite</span><span class="p">(</span><span class="n">pin_pwm</span><span class="p">,</span> <span class="nb">int</span><span class="p">(</span><span class="n">new_pwm</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="k">except</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">rpm</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">last_temperature</span> <span class="o">=</span> <span class="n">cur_temp</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># write rpm to ramdisk file</span>
</span></span><span class="line"><span class="cl">        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;/run/user/0/rpm&#34;</span><span class="p">,</span><span class="s1">&#39;w&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">out_file</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">out_file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">rpm</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="n">out_file</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># wait</span>
</span></span><span class="line"><span class="cl">        <span class="n">wait_seconds</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">wait_seconds_before_next_loop</span><span class="p">,</span> <span class="n">wait_seconds_after_pwm_change_before_measure_rpm</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">wait_seconds</span><span class="p">)</span>
</span></span></code></pre></div><p>Der Python-Server-Daemon selbst weiß natürlich wann er den PWM-Wert ändert,
kennt also auch den besten Zeitpunkt zum Messen. Meine Lösung besteht nun darin
die Drehzahl im Regelprozess zu messen und in eine Datei auf einer RAM-Disk zu
schreiben. Die Drehzahldatei wird mehrmals die Minute aktuallisiert, um damit
die MicroSD-Karte nicht kaputt zu schreiben, verwende ich die RAM-Disk, welche
das Debiansystem schon angelegt hat.</p>
<p>Zum starten und stoppen bzw. überwachen des Python-Server-Daemon definiere ich
ihn als systemd-Dienst. Das Skript liegt hier:</p>
<pre tabindex="0"><code>/etc/systemd/system/fancontrol.service
</code></pre><p>Aktiviert und gestartet wird es wie folgt:</p>
<pre tabindex="0"><code>systemctl enable pyserver
systemctl start pyserver
</code></pre><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">[</span>Unit<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">Description</span><span class="o">=</span>Fan control server
</span></span><span class="line"><span class="cl"><span class="nv">After</span><span class="o">=</span>syslog.target
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">[</span>Service<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">Type</span><span class="o">=</span>simple
</span></span><span class="line"><span class="cl"><span class="nv">WorkingDirectory</span><span class="o">=</span>/etc/check_mk
</span></span><span class="line"><span class="cl"><span class="nv">ExecStart</span><span class="o">=</span>/etc/check_mk/fancontrol_server.py
</span></span><span class="line"><span class="cl"><span class="nv">SyslogIdentifier</span><span class="o">=</span>fancontrol
</span></span><span class="line"><span class="cl"><span class="nv">StandardOutput</span><span class="o">=</span>syslog
</span></span><span class="line"><span class="cl"><span class="nv">StandardError</span><span class="o">=</span>syslog
</span></span><span class="line"><span class="cl"><span class="nv">Restart</span><span class="o">=</span>always
</span></span><span class="line"><span class="cl"><span class="nv">RestartSec</span><span class="o">=</span><span class="m">3</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">[</span>Install<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">WantedBy</span><span class="o">=</span>multi-user.target
</span></span></code></pre></div><p>Das Skript, welches dann die Drehzahl ausliest und ans Monitoring überträgt
kann somit los gelöst von der Regelung ausgeführt werden.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="ch">#!/usr/bin/python3</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">sys</span><span class="o">,</span> <span class="nn">os</span><span class="o">,</span> <span class="nn">time</span><span class="o">,</span> <span class="nn">stat</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">FILE</span> <span class="o">=</span> <span class="s2">&#34;/run/user/0/rpm&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">WARN_FILE_AGE_IN_SECONDS</span> <span class="o">=</span> <span class="mi">60</span>
</span></span><span class="line"><span class="cl"><span class="n">CRIT_FILE_AGE_IN_SECONDS</span> <span class="o">=</span> <span class="mi">120</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">FILE</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">  <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;UNKNOWN - FanControl file not found.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">file_age</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">os</span><span class="o">.</span><span class="n">stat</span><span class="p">(</span><span class="n">FILE</span><span class="p">)[</span><span class="n">stat</span><span class="o">.</span><span class="n">ST_MTIME</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">file_age</span> <span class="o">&gt;</span> <span class="n">WARN_FILE_AGE_IN_SECONDS</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;WARNING - FanControl RPM Value is old.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">file_age</span> <span class="o">&gt;</span> <span class="n">CRIT_FILE_AGE_IN_SECONDS</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;CRITICAL - FanControl RPM Value is outdated.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">line</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">FILE</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">infile</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">data</span> <span class="o">=</span> <span class="n">infile</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="n">infile</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">         <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;UNKNOWN - FanControl file open failed.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">         <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">rpm</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">rpm</span> <span class="o">&lt;</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;CRITICAL - FanControl RPM is 0..&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">rpm</span> <span class="o">&lt;</span> <span class="mi">500</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;WARNING - FanControl RPM is too slow.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># maybe waring/critical if too long too high</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;OK - FanControl is working. Fan has &#34;</span> <span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">rpm</span><span class="p">)</span><span class="o">+</span> <span class="s2">&#34;rpm. |fan=&#34;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">rpm</span><span class="p">)</span><span class="o">+</span><span class="s2">&#34;;:500;:200;600;3500&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span></code></pre></div><p>So sieht das dann in meinem Monitoring aus, ich habe hier mal Last aufs System
gegeben, damit man den Peak am Ende des Graphen sehen kann.</p>
<p><img src="drehzahl-monitoring.png" alt="Temperatur-Drehzahl" title="Temperatur-Drehzahl"></p>
<h2 id="fazit-und-verbesserungen">Fazit und Verbesserungen</h2>
<p>So im Ganzen finde ich es ein gelungenes Projekt. Hier ein paar Sachen die
ich beim nächsten mal besser machen würde:</p>
<ul>
<li>Das Gehäuse etwas größer machen, damit Platz ist für die Schutzschaltung.</li>
<li>Eine bessere Wandbefestigung, zur Zeit muss man den Pi dafür ausbauen.</li>
<li>Den Pi dichter an die Gehäusewand, manche USB Stecker passen z.Z. nicht.</li>
<li>Ein Kabel finden und verwenden, dass zwischen StepDown-Wandler und Pi passt.</li>
<li>Gehäusewand etwas dicker machen, bringt mehr Stabilität.</li>
</ul>
<p>STL-Files:</p>
<ul>
<li><a href="top-raspberry-pi-case-v1.stl">Oberteil</a></li>
<li><a href="basis-raspberry-pi-case-v1.stl">Basis</a></li>
</ul>
<p>Bei Fragen oder Kommentaren schreibt mir einfach eine <a href="mailto://comment@gillwaldt.de">E-Mail</a>, ich
veröffentliche das dann hier wenn ihr wollt.</p>
]]></content></item><item><title>Lüfter Steuerung</title><link>https://www.gillwaldt.de/posts/2019/luefter-steuerung/</link><pubDate>Thu, 28 Mar 2019 01:51:38 +0100</pubDate><guid>https://www.gillwaldt.de/posts/2019/luefter-steuerung/</guid><description>%!s(&lt;nil>)</description><content type="html"><![CDATA[<p>Wie im <a href="/posts/2019/logic-analyzer/">Logic Analyzer</a> beschrieben, brauchte ich eine Lüftersteuerung für
meinen neuen Fileserver, da ich unter Debian, genauer mit <a href="https://web.archive.org/web/20150627102528/http://www.lm-sensors.org/">lm-sensors</a>, nicht
auf die Daten der Lüfter zugreifen kann.</p>
<h3 id="anforderungen">Anforderungen</h3>
<p>Die Anforderungen an die Lüftersteuerung waren übersichtlich:</p>
<ul>
<li>Bei Steuerungsausfall müssen die Lüfter mit voller Geschwindigkeit laufen.</li>
<li>Die Lüfter sollen immer mit einer Mindestdrehzahl laufen.</li>
<li>Die Temperatur der Festplatten soll um die <a href="https://static.googleusercontent.com/media/research.google.com/de//archive/disk_failures.pdf">40 °C</a> gehalten werden.</li>
<li>Je ein Sensor soll je eine Festplattentemperatur messen.</li>
<li>Bis zu vier Lüfter sollen individuell gesteuert werden.</li>
<li>Die Steuerung soll die Lüfter und deren ideale Drehzahl selbst ermitteln.</li>
<li>Eine Schnittstelle zum Steuerungsdaten abfragen soll bereitgestellt werden.</li>
<li>Die Drehgeschwindigkeit der Lüfter soll messbar sein.</li>
</ul>
<h3 id="prototypen">Prototypen</h3>
<p>Die Anforderungen an die Messbarkeit sprechen für einen 3-Pin oder 4-Pin Lüfter.
Die Steuerung von 4-Pin Lüftern ist allerdings sehr viel einfacher und preislich ist
da kein großer Unterschied. 4-Pin Lüfter für PCs funktionieren nach einer
<a href="https://web.archive.org/web/20110726062453/http://www.formfactors.org/developer/specs/4_Wire_PWM_Spec.pdf">Intel Spezifikation</a>. Die Lüfter haben 4 Anschlüsse: GND, 12V, Tacho, PWM.
Der Pin für das PWM Signal nimmt 0V als Low und 5V als High entgegen, kann also
direkt am Arduino betrieben werden. Das Tacho-Signal wird meist mit einem
Hall-Sensor realisiert, pro Umdrehung liefert Sensor 2 Impulse. Der Arduino muss
also Impulse über Zeit zählen und kann daraus die Drehzahl errechnen. Um die
Impulse sauber zu erkennen, wird die Verbindung zwischen Tacho-Signal und Arduino
mit einem Widerstand auf 5V gezogen. Als Temperatursensoren verwende ich <a href="https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf">Dallas
DS18B20</a> OneWire Sensoren, dies ermöglicht es mehrere Sensoren an einem Bus zu
betreiben. Den OneWire-Bus zieht man ebenfalls über einen Widerstand auf 5V.
Daraus ergibt sich folgende Schaltung.</p>
<p> 
<img src="fancontrol_v1_steckplatine.png" alt="FanControll v1.0 Schaltung" title="FanControll v1.0 Schaltung">
 </p>
<p>Wie ich im <a href="/posts/2019/logic-analyzer/">Logic Analyzer</a> schon erklärte, hat der <a href="https://store.arduino.cc/arduino-uno-rev3">Arduino Uno</a> bzw. sein
Mikroprozessor der <a href="https://www.microchip.com/wwwproducts/en/ATmega328P">ATmega328P</a> leider zu wenig 16-Bit Timer. Ich verwende deshalb
den <a href="https://www.arduino.cc/en/Main/Arduino_BoardLeonardo">Arduino Leonardo</a>, dessen Mikroprozessor hat einen 16-Bit mehr und damit
genug für die Ansteuerung von 4 Lüftern.</p>
<p>Wenn man die PWM-Signale nicht vom Arduino erzeugen lässt, geht natürlich auch
ein Arduino Uno. Ich habe einen Prototypen gebaut, der ein <a href="https://de.aliexpress.com/wholesale?SearchText=pwm+generator+3">PWM-Generator-Board</a>
via UART (also serieler Ansteuererung) zur Erzeugung der PWM-Signale benutzt.</p>
<p> 
<img src="fancontroll-prototyp-extern-pwm.png" alt="Prototyp mit externen PWM-Generator" title="Prototyp mit externen PWM-Generator">
 </p>
<p>Leider hat das Board, welches die PWM-Signale erzeugt, auch nur drei Ausgänge,
ich hatte da noch die Hoffnung ein ähnliches Board mit vier oder mehr Ausgängen
zu finden, leider erfolglos.</p>
<p>Die ursprüngliche Schaltung habe ich auf einem <a href="https://de.aliexpress.com/wholesale?SearchText=Arduino+Prototyp+Shield">Arduino Prototyp-Shield</a>
aufgebaut, um sie zu testen und mit der Softwareentwicklung anfangen zu können.</p>
<p> 
<img src="fancontroll-prototyp-shield.png" alt="Prototyp mit Arduino-Shield" title="Prototyp mit Arduino-Shield">
 </p>
<h3 id="eigene-platine-pcb">Eigene Platine (PCB)</h3>
<p>Eigentlich hätte ich jeden Pin des Arduinos fest verdrahten können, also in der
Software festlegen können an welchen Pin das PWM-Signal ausgegeben werden muss
und an welchem Pin das dazugehörige Tacho-Signal anliegt. Bei meinem
Prototyp-Shield sieht man eher schlecht was an welchen Pin geführt wird. Ich
habe in der Software nur die Pins festgelegt, welche für Tacho bzw. PWM
verwendet werden. Im Setup testet die Software dann selbständig welche Lüfter
angeschlossen sind und an welchen Pins die dazugeöhrigen Tacho-Signale anliegen.
Das finde ich sehr komfortabel und verhindert auch Fehlverdrahtungen auf dem
Breadboard, auch wenn es beim Erstellen eines PCB nicht mehr nötig wäre.</p>
<p><a href="https://fritzing.org/home/">Fritzing</a> ermöglicht es aus dem Breadboard-Aufbau ein PCB zu erstellen. Nach
dem händischen Optimieren der auto-gerouteten Leiterbahnen erhält man
produktionsfähiges Layout. 2-Layer, also unten und oben, reichen hier aus. Manche
Leiterbahnen müssen ab und an die Seite wechseln, damit es keine ungewollten
Verbindungen gibt. Eigentlich wollte ich mir das dann von irgendwem ätzen
lassen, aber das Durchkontaktieren der zwei Layer ist relativ umständlich.</p>
<p> 
<img src="fancontroll-pcb-layout.png" alt="Layout des PCBs" title="Layout des PCBs">
 </p>
<p>Aus <a href="https://fritzing.org/home/">Fritzing</a> heraus kann man mit wenigen Klicks direkt bei <a href="https://aisler.net/">aisler.net</a> das
PCB in Auftrag geben. Die Mindestbestellmenge lag bei mir bei drei Stück und
die sollten etwa 25€ kosten. Das ist im Prinzip recht günstig, verglichen mit
den anderen deutschen Herstellern, dass liegt an der geringen Stückzahl.</p>
<p>Direkt in China stellt man deutlich günstiger her. Ich hatte das vorher noch
nie gemacht. Ich habe hier <a href="https://www.pcbway.com/">PCBWay</a> getestet, dort war die  Mindestmenge fünf
Stück für $1 das Stück, der Express-Versand hat $6 gekostet und als Neukunde
habe ich $5 Rabatt bekommen.</p>
<p>Für 5 PCBs habe ich etwa 5€ gezahlt. Die Dateien die man zur Produktion braucht,
können direkt aus Fritzing exportiert werden. Die Produktion kann man auf der
Webseite gut verfolgen und dauerte knapp drei Tage. Der Versand hat dann etwa
eine Woche gedauert, ich hatte also nach 10 Tagen die PCBs zu Hause.</p>
<p> 
<img src="fancontroll-pcb.png" alt="fertiges PCB" title="fertiges PCB">
 </p>
<p>Für die Sensoren hatte ich zuerst <a href="https://de.aliexpress.com/wholesale?SearchText=pin+header">2,54mm Pin-Header</a> verwendet. Leider sind die
nicht verdrehsicher, es hat mich einen Arduino gekostet dies herauszufinden. OK
bei dem Arduino ist nur die Spannungsversorgung durchgebrannt, der Mikroprozessor
selbst funktioniert noch. Ich habe dann für den zweiten Anlauf
<a href="https://www.google.com/search?q=5267-04A+%3BMolex">Steckerbuchsen von Molex</a> verwendet, die kosten bei <a href="https://www.segor.de/">Segor</a> pro Sensor (Wanne,
Stecker &amp; Crimkontakte) etwas unter 1€, dafür geht aber kein Arduino mehr kaputt.</p>
<p>Im ersten Versuch waren alle Widerstände 4,7kΩ, leider konnte ich dann nur noch
vier Temperatursensoren anschließen, einer mehr und es wurde keiner mehr gefunden.
Ich habe den Widerstand der zwischen 5V und dem OneWire-Bus durch einen 2,7kΩ
ersetzt, damit ging es dann ohne weitere Probleme.</p>
<p>Die <a href="https://de.aliexpress.com/wholesale?SearchText=KF2510+3+%2B+1">4-Pin PWM Lüfter Buchsen</a> sind etwas speziell. Der Teil der beim
zusammenstecken für das Einrasten sorgt, ist nur drei Pin breit. Das ermöglicht
im PC 3-Pin und 4-Pin Lüfter zu verwenden und sorgt dafür das 4-Pin Lüfter
nicht falsch aufgesteckt werden können. Bei Segor habe ich die leider nicht
bekommen. Aufgebaut sieht das Arduino-Shield dann so aus:</p>
<p> 
<img src="fancontroll-shield.png" alt="fertiges Arduino-Shield" title="fertiges Arduino-Shield">
 </p>
<p>Für die Stromversorgung benötigt man 12V für die Lüfter und irgendetwas zwischen
7-12V für den Arduino. Man könnte auch direkt 5V nehmen und den Arduino über
die Pins mit Strom versorgen. Das würde vermutlich sogar etwas Strom sparen, da
der Spannungswandler auf dem Arduino nicht verwendet wird. Ich habe einfach
die 12V genommen mit denen ich auch die Lüfter versorge und einen kleiner
Y-Adapter gebastelt.</p>
<p> 
<img src="molex-to-power-jack-y-cable.png" alt="Stromversorgungskabel" title="Stromversorgungskabel">
 </p>
<h3 id="softwareentwicklung">Softwareentwicklung</h3>
<p>Beim Testaufbau für die Softwareentwicklung habe ich die Anzahl und Art der
Lüfter und Anzahl der Sensoren variiert. Mit maximaler Bestückung sieht das dann
so aus:</p>
<p> 
<img src="fancontroll-versuchsaufbau.png" alt="Versuchsaufbau für die Softwareentwicklung" title="Versuchsaufbau für die Softwareentwicklung">
 </p>
<p>Die Software habe ich so geschrieben, dass beim Einschalten oder Reset des
Arduinos im Setup erst einmal alle Parameter ermittelt werden, die für die
Steuerung benötigt werden. Ich beschreiber hier nur die grobe Funktionsweise.</p>
<p>Als erstes wird geschaut wieviele Temperatursensoren angeschlossen sind. Es
muss mindestens ein Sensor angeschlossen sein, sonst verharrt der Arduino
hier bis der erste Sensor angeschlossen wird. Das Vorhandensein von Sensoren
wird später regelmäßig überprüft, sodass man auch im Betrieb welche hinzufügen
oder entfernen kann. Sollte die Software allerdings keine Sensoren mehr finden,
werden die Lüfter voll aufgedreht.</p>
<p>Im nächsten Schritt werden die vier möglichen PWM Signale den vier möglichen
Tachosignalen zugeordnet. Dabei wird auch ermittelt wieviele Lüfter
angeschlossen sind. Es muss mindestens ein Lüfter angeschlossen sein, damit
dieser Schritt abgeschlossen wird, sonst wartet der Arduino hier wieder. Jede
Änderung an der Lüfterkonfiguration bedarf eines Neustarts bzw. Resets.</p>
<p>Im letzten Schritt werden die Lüfter ausgemessen. Es wird pro Lüfter der höhste
PWM-Wert ermittelt, bei dem der Lüfter eine minimale Drehzahl größer als 0 hat.</p>
<p>Die Spanne zwischen welcher der Lüfter geregelt wird, befindet sich dann zwischen
PWM-Wert 100 und dem gemessenen minimalen PWM-Wert. Es werden zwei
Temperaturpunkte definiert. Punkt A, unter dem die Lüfter mit minimaler Drehzahl
laufen soll, und Punkt B, bei welcher der Lüfter mit voller Drehzahl laufen soll.</p>
<p> 
<img src="kurve.png" alt="Temperatur-Drehzahl-Kurve" title="Temperatur-Drehzahl-Kurve">
 </p>
<p>Die Spanne zwischen den beiden Temperaturen wird gleichmäßig auf die Spanne der
möglichen PWM-Werte aufgeteilt. So kann man für jede Temperatur den passenden
PWM-Wert berechnen.</p>
<h3 id="betrieb">Betrieb</h3>
<p>Die Steuerung selbst ist recht einfach. Es werden alle Temperaturen gemessen
und die Höhste wird zur Regelung verwendet. Für jeden Lüfter wird der PWM-Wert
passend berechnet und der Lüfter entsprechend angesteuert.</p>
<p>Um mit Arduino zu kommunizieren, wird er an einen internen USB-Anschluss
angeschlossen. Ich habe mir dafür so ein kleines Kabel gebaut.</p>
<p> 
<img src="internes-usb-kabel.png" alt="InternesUSB zu MicroUSB Kabel" title="InternesUSB zu MicroUSB Kabel">
 </p>
<p>Mit dem internen USB verbunden, verhält sich der Arduino wie eine über USB
verbundene serielle Schnittstelle. Man kann an die serielle Schnittstelle ein
beliebiges Byte schicken (ausser das kleine &lsquo;r&rsquo;) und er antwortet mit den
aktuellen Parametern. Sendet man das kleine &lsquo;r&rsquo;, wird ein Reset durchgeführt.
Ich verwende zum Auslesen und der Weitergabe an <a href="https://mathias-kettner.de/">check_mk</a> folgendes kleines
Python-Skript:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="ch">#!/usr/bin/python</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">serial</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">sys</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">connected</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl"><span class="n">tries</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="ow">not</span> <span class="n">connected</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">arduino</span> <span class="o">=</span> <span class="n">serial</span><span class="o">.</span><span class="n">Serial</span><span class="p">(</span><span class="s1">&#39;/dev/fancontrol&#39;</span><span class="p">,</span> <span class="mi">9600</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">connected</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">tries</span> <span class="o">&gt;</span> <span class="mi">10</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;FanControl Failed - Not connectable. |&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">pass</span>
</span></span><span class="line"><span class="cl">    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tries</span> <span class="o">=</span> <span class="n">tries</span> <span class="o">+</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">arduino</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;x&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;FanControl OK - Running and readable. |&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">arduino</span><span class="o">.</span><span class="n">readline</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span></code></pre></div><h3 id="fazit-und-verbesserungen">Fazit und Verbesserungen</h3>
<p>Nach ausgiebigen Tests läuft die Steuerung nun seit drei Wochen zuverlässig
in meinem Fileserver. Ich bin insgesamt zufrieden. Für Version 1.1 würde ich
ein paar Sachen verbessern:</p>
<ul>
<li>Mehr Änschlüsse für den OneWire-Bus und den Abstand dazwischen vergrößern.</li>
<li>Die Widersände leicht versetzen, damit der 12V auch 90° zum Shield zeigen kann.</li>
<li>Eine Diode oder so einbauen, damit ein verdrehter Sensor nichts beschädigt.</li>
<li>Statt des Arduinos, eine eigene Platine mit dem ATmega32u4 entwerfen.</li>
<li>Ein richtiges Gehäuse zb. 3D gedruckt, vielleicht als 3,5 Zoll Laufwerk.</li>
<li>Vielleicht ein Display oder Kontroll-Leds.</li>
<li>Temperaturpunkte A und B via serieller Kommunikation ändern.</li>
<li>Der ExitCode für check_mk sollte vom Arduino kommen.</li>
</ul>
<p> 
<img src="/posts/2019/luefter-steuerung/fancontroll-in-action.png" alt="Lüftersteuerung im Einsatz" title="Lüftersteuerung im Einsatz">
 </p>
<p>Hier nochmal alle Teile die ich verwendet habe:</p>
<ul>
<li><a href="https://de.aliexpress.com/wholesale?SearchText=arduino+leonardo">Arduino Leonardo China-Version</a></li>
<li><a href="https://de.aliexpress.com/wholesale?SearchText=pin+header+19mm">Extra lange Pin-Header</a></li>
<li><a href="https://de.aliexpress.com/wholesale?SearchText=KF2510+3+%2B+1">4-Pin PWM Lüfter Buchsen</a></li>
<li><a href="https://de.aliexpress.com/wholesale?SearchText=ds18b20+waterproof">Dallas DS18B20 Temperatursensoren</a></li>
<li>4 x 4,7kΩ und 1 x 2,7kΩ Widerstände</li>
<li>Y-Kabel-Stromkabel: <a href="https://de.aliexpress.com/wholesale?SearchText=Molex+4Pin+Female+Housing">4-Pin Molex</a> + 5,5 x 2.1mm <a href="https://de.aliexpress.com/wholesale?SearchText=2.1mm+x+5.5mm+Male+Plug">Hohlstecker</a></li>
<li>internes USB-Kabel: <a href="https://de.aliexpress.com/wholesale?SearchText=Dupont">Dupont</a></li>
</ul>
<p>Hier alle benötigten Dateien:</p>
<ul>
<li><a href="fancontrol_rev1.fzz">fritzing file</a></li>
<li><a href="fancontrol.zip">arduino code</a></li>
</ul>
<p>Bei Fragen, Anregungen, Kommentaren oder Verbesserungsvorschlägen schickt mir
einfach eine <a href="mailto://comment@gillwaldt.de">E-Mail</a>, ich baue das hier dann ein.</p>
]]></content></item><item><title>Logic Analyzer</title><link>https://www.gillwaldt.de/posts/2019/logic-analyzer/</link><pubDate>Mon, 25 Mar 2019 21:17:16 +0100</pubDate><guid>https://www.gillwaldt.de/posts/2019/logic-analyzer/</guid><description>%!s(&lt;nil>)</description><content type="html"><![CDATA[<p>Mein neuer Fileserver steht in hörweite meines Arbeitsplatzes, er soll also so
leise wie möglich sein. Gleichzeitig sollen die Lüfter aber so schnell wie nötig
laufen, um die Festplatten auf durchschnittlich <a href="https://static.googleusercontent.com/media/research.google.com/de//archive/disk_failures.pdf">40 °C</a> zu halten.</p>
<p>Da mein Mainboard bzw. der Chipsatz nicht von <a href="https://web.archive.org/web/20150627102528/http://www.lm-sensors.org/">lm-sensors</a> unterstützt wird, baue
ich zur Zeit eine Lüftersteuerung auf <a href="https://www.arduino.cc/">Arduino</a>-Basis. Die Lüftersteuerung wird
einen eigenen Post bekommen. Hier geht es nur um ein Teilproblem.</p>
<p>Der Arduino muss zur Steuerung der 4-Pin PWM-Lüfter laut <a href="https://web.archive.org/web/20110726062453/http://www.formfactors.org/developer/specs/4_Wire_PWM_Spec.pdf">Intel Spezifikation</a>
ein <a href="https://de.wikipedia.org/wiki/Pulsdauermodulation">Pulsweitenmodulation</a>s-Signal mit etwa 25 kHz erzeugen.
Pulsweitenmodulation (kurz: PWM) bedeutet in idealen Fall ein <a href="https://de.wikipedia.org/wiki/Rechteckschwingung">Rechtecksignal</a>.
Die obere Linien des Signals bedeutet das Strom fließt (An) und die untere
Linie das kein Strom fließt (Aus). Das Verhältnis der Länge der An-Phase zur
Länge der Aus-Phase plus Aus-Phase, also einer Periode, nennt man Tastgrad
im englischen <a href="https://en.wikipedia.org/wiki/Duty_cycle">duty cycle</a>, mit ihr wird die Geschwindigkeit des Lüfters
gesteuert.</p>
<p>Zurück zum Arduino. Ich möchte mehrere Lüfter individuell steuern, alle brauchen
also ein 25 kHz PWM-Signal, aber mit unterschiedlichen duty cycles.</p>
<p>Es gibt verschiedene Möglichkeiten diese Signale mit dem Arduino zu erzeugen.
Man kann das in Software machen, in Hardware und es gibt spezielle Bibliotheken
dafür. Ich habe nun die verschiedenen Möglichkeiten auf verschiedenen Arduinos
getestet. Mein Problem war nur wie ich die resultierende PWM-Signale
kontrolliere.</p>
<p>Man könnte einen Lüfter als Messinstrument benutzen und aus den Veränderungen
der Drehgeschwindigkeit Rückschlüsse über den duty cycle ableiten. Ich finde
das ohne ein Messinstrument für die Lüfterdrehzahl viel zu ungenau. Ausserdem
sagt das auch nicht viel über die Frequenz des PWM-Signals aus, da ein 4-Pin
PWM-Lüfter laut <a href="https://web.archive.org/web/20110726062453/http://www.formfactors.org/developer/specs/4_Wire_PWM_Spec.pdf">Intel Spezifikation</a> durchaus um mehrere kHz varieren darf.
Im Internet liest man oft eine LED bzw. deren Helligkeit wären eine gute
Messmethode. Das finde ich auch zu ungenau.</p>
<p>Die sicherlich beste Methode wäre ein Oszilloskop, hier könnte man sich das
Signal sehr genau anschauen. Für die Zukunft ist eine Anschaffung geplant, zur
Zeit besitze ich leider keins. Für digitale Signale, also solche die nur aus
An/Aus bzw High/Low bestehen, kann man einen Logic Analyser verwenden.</p>
<p>Wie bei allen Messgeräten ist die Preisspanne der verfügbaren Geräte extrem.
Ich wollte preiswert einsteigen und habe mir einen bei <a href="https://de.aliexpress.com/item/USB-Logic-Analyzer/32960102049.html?isOrigTitle=true">Logic Analyser bei
Aliexpress für 5€</a> bestellt.</p>
<p><img src="logicanalyzer.jpg" alt="Logic Analyzer" title="Logic Analyzer"></p>
<p>Beim Aliexpress stand leider nicht wirklich viel über kompatible Software, mit
irgendetwas muss man sich die Signale ja dann anschauen. Die Firma <a href="https://www.saleae.com/de/">saleae</a>
verkauft eigene Logic Analyzer und liefert eine gute Software mit. Irgendwo habe
ich gelesen, dass die kleinen preiswerten China-Geräte mit deren Software
kompatible sind. Der saleae-Support schrieb mir recht klar, dass die Software
zwar kostenlos sei, aber nur ihre eigenen Produkte unterstützt.</p>
<p>Entgegen dieser Aussage, funktioniert mein (China) Logic Analyzer einwandfrei
mit der saleae-Software.</p>
<p>Nach ein paar Experimenten habe ich es dann geschafft mit einem <a href="https://store.arduino.cc/arduino-uno-rev3">Arduino Uno</a>
mehrere PWM-Signale mit 25 kHz und verschiendenen duty cycles hinzubekommen.</p>
<p><img src="pwm-signals.jpg" alt="PWM Signale" title="PWM Signale"></p>
<p>Leider muss man beim <a href="https://www.microchip.com/wwwproducts/en/ATmega328P">ATmega328P</a> (das ist der Mikroprozessor des Arduino Uno)
dafür auch den Timer0 verwenden bzw. umkonfigurieren. Der wird aber für viele
andere Dinge wie delay() oder OneWire benötigt. Das heißt für mich kommt
der Uno nicht in Frage. Ich werde den Arduino Leonardo (<a href="https://www.microchip.com/wwwproducts/en/ATmega32u4">ATmega32u4</a>) verwenden,
dieser hat einen weiteren 16Bit-Timer, damit sollte alles realisierbar sein.</p>
]]></content></item><item><title>SATA Stromkabel DIY</title><link>https://www.gillwaldt.de/posts/2019/sata-stromkabel-diy/</link><pubDate>Thu, 21 Mar 2019 20:42:13 +0100</pubDate><guid>https://www.gillwaldt.de/posts/2019/sata-stromkabel-diy/</guid><description>%!s(&lt;nil>)</description><content type="html"><![CDATA[<p>Anfang des Jahres war es mal wieder soweit, mein Fileserver brauchte ein
Update. Das letzte Update hatte mein Fileserver Anfang 2015, damals entschied
ich mich für <a href="https://www.fractal-design.com/home/product/cases/node-series/node-304-black">Node 304 Black</a> von <a href="https://www.fractal-design.com/">Fractal Design</a>. Ich fand das Gehäuse sah
gut aus und hatte mit Platz für sechs Festplatten alles was ich brauchte.</p>
<p>Leider konnte FreeNAS damals noch nicht die Temperatur der Festplatten
überwachen. Irgendwann letztes Jahr fiel einer der zwei Frontlüfter aus. Das
habe ich leider nicht mitbekommen. Langsam aber sicher hat das die Platten
gegrillt.</p>
<p>Lange Rede, kurzer Sinn: Diesmal wollte ich ein Gehäuse für größere Mainboards
als MiniITX und mit ordentlich Platz zwischen den Festplatten. Meine Wahl fiel
auf <a href="https://www.bequiet.com/">BeQuiet</a>&rsquo;s <a href="https://www.bequiet.com/en/case/pure-base/919">PURE BASE</a>, hier lagern bis zu fünf Festplatten in
Einzelkäfigen übereinander. In der Front kann man zwei 14 cm oder drei 12 cm
Lüfter verbauen.</p>
<p>Nun wollte ich natürlich alle Kabel sauber verlegen. Bei den SATA-Stromkabeln
stieß ich auf Probleme. Erstens hat mein Netzteil an jedem Kabelstrang nur drei
SATA-Anschlüsse und zweitens liegen die Festplatten etwa 6 cm auseinander. Das
ist zu dicht um die Standard-Kabel ordentlich zu verlegen und zu weit
auseinander für die gängigen Mehrfach-SATA-Kabel.</p>
<p>Was lag da näher als die Kabel passgenau selbst herzustellen. Folgende Teile
habe ich beim <a href="https://de.aliexpress.com/">AliExpress</a> gekauft:</p>
<ul>
<li>5 x <a href="https://de.aliexpress.com/item/sata/32953737646.html?isOrigTitle=true">SATA-Stecker mit Verriegelung</a> (Σ ~ 2,50€)</li>
<li>4 x <a href="https://de.aliexpress.com/item/18AWG/32952838832.html?isOrigTitle=true">AWG 18 Kabel</a> in den Farben Rot/Schwarz/Gelb (Σ ~ 2,00€)</li>
<li>1 x <a href="https://de.aliexpress.com/item/molex/32812826812.html?isOrigTitle=true">4 Pin Molex-Buchse</a> Gehäuse und Pins (~ 0,50€)</li>
</ul>
<p>Der Zusammenbau ist einfach, die Kabel kann man einfach in die Stecker
quetschen, ich habe dafür einen Phasenprüfer benutzt. Für die Pins der
Molex-Buchse braucht man eine Crimp-Zange, es gibt aber auch hier Varianten mit
Quetsch-Verbindungen.</p>
<p>Beim AliExpress muss man immer etwas suchen und vergleichen. Einzelne Artikel
sind oft günstiger wenn man sie mit kostenlosem Versand bestellt, bei mehreren
Artikeln ist es machmal besser mit Versandkosten zu bestellen.</p>
<p>Insgesamt habe ich etwa 5€ für die Materialien für das Kabel bezahlt, dass ist
deutlich unter dem was man für ähnliche fertige Kabel bezahlen würde, wenn man
sie denn käuflich erwerben könnte.</p>
<p>Ich habe die Kabel zwischen den Steckern noch mit Schrumpfschlauch versehen,
möglich und etwas schöner wäre vermutlich Nylon-Gewebe gewesen.</p>
<p><img src="sata-kabel-prepare.jpg" alt="fertiges Kabel" title="fertiges Kabel"></p>
<p>Verbaut sieht das Ganze recht ordentlich aus und funktioniert tadellos, aber
was soll da auch nicht funktionieren, ist ja nur Strom.</p>
<p><img src="sata-kabel-builtin.jpg" alt="eingebautes Kabel" title="eingebautes Kabel"></p>
<p>Als nächstes hab&rsquo; ich mich um die Lüftersteuerung gekümmert. Das ein Lüfter
aussteigt und ich das nicht mitbekomme soll ja nie wieder passieren.</p>
<p>Bei Fragen oder Kommentaren schreibt mir einfach eine <a href="mailto://comment@gillwaldt.de">E-Mail</a>, ich
veröffentliche das dann hier wenn ihr wollt.</p>
]]></content></item><item><title>Neue Homepage</title><link>https://www.gillwaldt.de/posts/2019/neue-homepage/</link><pubDate>Tue, 26 Feb 2019 13:37:00 +0100</pubDate><guid>https://www.gillwaldt.de/posts/2019/neue-homepage/</guid><description>%!s(&lt;nil>)</description><content type="html"><![CDATA[<p>Um genau zu sein versuche ich diesmal auf jegliche Art von <a href="https://de.wikipedia.org/wiki/Server_Side_Scripting">Server Side Scripting</a> und damit auch auf Datenbanken zu verzichen. Die Homepage ist nur eine Sammlung statischer HTML Seiten und ein wenig Javascript zum aufhübschen.</p>
<p>Ich hatte die letzten Jahre <a href="https://de.wordpress.org/">Wordpress</a> im Einsatz und war immer nur so mittel zufrieden. Das lag sicher auch daran das ich nicht so regelmäßig veröffentlicht habe und mich jedes mal wieder neu in die Feinheiten einarbeiten musste.
Ein anderer Punkt war, dass trotz der vielfältigen Einstellungsmöglichkeiten, bestimmte Sachen nicht so gingen, wie ich mir das vorstellte, außer ich hätte angefangen Templates zu verändern oder am Wordpress-Code selbst rum zu spielen. Beides keine Gute Idee, denn bei einem Update werden solche Änderungen meist überschrieben.</p>
<p>Diesmal verwende ich <a href="https://gohugo.io/">Hugo</a>, ein in <a href="https://de.wikipedia.org/wiki/Go_(Programmiersprache)">Go</a> geschriebens Framework zum Erstellen statischer Webseiten. Im Grunde erstellt man seine Seiten in der Auszeichnungssprache <a href="https://de.wikipedia.org/wiki/Markdown">Markdown</a>, welche auch HTML enthalten können und legt diese in einer Ordernerstruktur ab. Zusammen mit CSS und einer Konfigurationdatei generiert Hugo dann daraus die eigentliche Webseite, mit Indexseiten, Tags und Kategorien.</p>
<p>Dafür braucht man Serverseitig keinen Interpreter, d.h. aber auch das man keine Daten entgegen nehmen und/oder verarbeiten kann. Das hat den Nachteil das Formulare und ähliches so erstmal nicht möglich sind, hat aber auch den Vorteil das prinzipbedingt die üblichen Angriffe auf Webseiten (<a href="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_2017_Project">OWASP Top 10</a>) schwerer durchzuführen sind.</p>
<p>Ob das ganze für mich funktioniert wird sich zeigen, aber auf die letzten Jahre zurück blickend denke ich das wird schon klappen &#x1f44d;, die paar Kommentare kann ich auch per E-Mail entgegen nehmen und hier veröffentlichen. Also dann auf ein fleissiges <del>bloggen</del> ähm posten &hellip;</p>
]]></content></item></channel></rss>