Elektronik_Header_3Lüftersteuerung mit ESP-01

 

Custom UPS Gen6

Der normale Betrieb der UPS Gen6 war mehr oder weniger unspektakulär. Die Probleme fingen erst an, als ich beschlossen hatte, den Raspberry Pi 3B+ (RPi) nicht mehr unter Debian laufen zu lassen, sondern HAOS (Home Assistant Operating System) als Betriebssystem zu verwenden.

Den Ausschlag dazu gab die Idee, die Phasenumschaltung der Keba Wallbox P30 nicht ecvv zu überlassen, sondern mittels HA Skript zu steuern.

Für diese Entscheidung gibt es handfeste Gründe. Evcc unterstützt zwar prinzipiell die Umschaltung der Phasen von 1 nach 3 und umgekehrt, aber die Entwickler weigern sich standhaft, die dabei notwendigen Pausen einzuhalten. In Folge geht unser Elektro-Fahrzeug in Störung und muss mittels Stecker ziehen/stecken wieder zur Räson gebracht werden.

Der Klassiker dabei: Evcc sagt, die Zeiten müssen von der Wallbox automatisch eingehalten werden, Keba, der Hersteller der Wallbox sagt, dafür ist eindeutig der Controller, also evcc zuständig. Deadlock.

Also mache ich es selbst und nutze dafür Home Assistant (HA).

Die Steuerung der Phasen war relativ schnell erledigt, dann ging es an den Einsatz der UPS in Verbindung mit dem HAOS RPi...

Damit HA auf I2C Slaves zugreifen kann, muss ein bisschen im Getriebe des Betriebssystems gerührt werden, denn solche Hardwarezugriffe werden von HAOS einfach erst mal unterbunden. Als der Zugang klappte, hat die UPS plötzlich die Zusammenarbeit verweigert und nicht mehr auf Zugriffe reagiert. Ein paar Versuche später ließ sie sich auch nicht mehr in den OTA Modus versetzen -> gebrickt - Mist!

Mein Ansatz, den Hersteller zu einer kulanten Regelung im Sinne von rettenden Binaries oder nur dem notwendigen Bootloader zu überreden, scheitern an NDAs (non disclosure agreement) mit dem Chiphersteller des auf der UPS verwendeten Controllers IP5389 und sonstigen Hinderungsgründen.

Eine wohl noch funktionierende UPS Hardware auf dem Tisch liegen haben und keine Firmware dafür zu bekommen kann ich nicht ausstehen, also habe ich mich dazu durchgerungen, die Firmware in Eigenregie nachzubauen (unterstützt von Gemini).

Die nächsten Tage habe ich mit dem Durchgangsprüfer, einer Kopflupe auf der Stirn und einem elektronischen Mikroskop in der Hand verbracht. Da die Platine der UPS mindestens 4-lagig aufgebaut ist, sind Signale teilweise an einem Via in der Innenlage verschwunden, Raten ist angesagt. Gemini hat mich tapfer immer wieder mit Testprogrammen versorgt, die ein spezielles Signal wackeln ließen, so dass mit dem Oszilloskop Signalverfolgung möglich war. So ist sukzessive das Verständnis für die Schaltung der USV und letztlich das Grundgerüst der Firmware entstanden.

Eine Konversation mit dem Chefentwickler bei 52PI, dem Hersteller der UPS Gen6, hat mich in eine Sackgasse geschickt und ich habe aufgrund einer Andeutung, wie der STM32F411 an die Daten des IP5389 herankommt, eine halbe Woche lang vergeblich versucht, eine I2C Verbindung zwischen dem IP5389 und dem STM32 herzustellen. “Geholfen” hat dabei eine Application Note von Injoinic (Hersteller des IP5389) in der beschrieben wird, mit welchem Voodoo man den Chip dazu überreden kann, die LED Pins temporär auf I2C umzuschalten. Nach gefühlt 200 Versuchen per Programm und Kontrollmessungen an einer zwischenzeitlich gekauften zweiten UPS Gen6 war dann endlich klar: Die von 52PI eingesetzte Variante des IP5389 hat definitiv kein I2C Interface. Der Chip kommuniziert nicht mit dem STM32, liefert keine Daten und wird nicht gesteuert sondern arbeitet mehr oder weniger unabhängig als intelligenter Powerbank Controller und kümmert sich um die Bereitstellung der benötigten Spannungen, die er ohne Unterbrechung an alle Beteiligten weiterleitet. Die einzige Interaktion zwischen STM32 und IP5389 erfolgt über den KEY Eingang des IP5389. Hierüber kann der STM32 den IP5389 in den Ruhezustand versetzen oder ihn neu starten.

Untermauert wird diese Erkenntnis durch die Tatsache, dass ziemlich alle Parameter, die den Betrieb der UPS als Solche ermöglichen - im wesentlichen Spannungen und Ströme der verschiedenen Ein- und Ausgänge - über dedizierte Sensoren (INA219, INA138) oder Widerstandsnetzwerke erfasst und an den STM32 heran geführt werden. Wäre eine Kommunikation mit dem IP5389 implementiert, könnten diese und viele weitere Informationen einfach vom IP5389 erhoben werden. Dass ich zuletzt von 52PI erneut einen Hinweis darauf erhalten habe, dass Konfigurationsregister des IP5389 geändert werden können, lasse ich einfach mal so stehen... Vielleicht habe ich ja einfach den entscheidenden Trick nicht gefunden.

Die Originalfirmware  der UPS hat noch ein paar Gimmicks in der Hinterhand, die mich nicht interessieren. Dazu gehört ein minimalistischer Python Interpreter, der es dem Nutzer erlaubt, eigene Skripte auf dem STM32 auszuführen. Mir war nur wichtig, alle Register des Originals mit Leben zu erfüllen, so dass die von 52PI zur Verfügung gestellten Skripte und Programme, die die reine USV-Funktion betreffen, auch mit meiner Custom Firmware ordentlich zusammen arbeiten.

Die Registerstruktur des Originals ist bis auf wenige Ausnahmen 1:1 abgebildet. Da die Laufzeit-Register von mir nicht genutzt werden, stehen 8 Byte für andere Zwecke zur Verfügung.

Die Ausnahmen sind:

Register

Original

Bits

Zugriff

Neu

0x27

rsv

16

R

untere 14 Bit: Lüfterdrehzahl

obere 2 Bit: Batterie-Status

  • 0 - Ok
  • 1 - Batterie-Kabel abgezogen
  • 2 - Zelle 1 CID ausgelöst
  • 3 - Zelle 2 CID ausgelöst

0x29

ota_request

16

R

ohne Funktion

0x2B

runtime

16

R

Batterieladezustand [%]

0x2D

runtime

8

R/W

Temperatur ab der der Lüfter mit kleinster Drehzahl dreht [°C]

0x2E

runtime

8

R/W

Temperatur ab der der Lüfter mit voller Drehzahl dreht [°C]

0x2F

runtime

16

R

Zellenspannung Zelle 1 [V]

0x31

runtime

16

R

Zellenspannung Zelle 2 [V]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Das hat nicht gereicht, um weitere Spezialfunktionen zu realisieren, weshalb ich die Registerbank um zwei weitere Register erweitert habe. Diese zusätzlichen Register bedienen Funktionen im Zusammenhang mit dem akustischen Alarm bei ungleichen Zellenspannungen. Das habe ich eingebaut, um ein ausgelöstes CID (Current Interruption Device) gemeldet zu bekommen. Tritt das ein, Ursache erst mal egal, muss gehandelt werden: Alarm!

0x36

 

8

R/W

Bit 7: Sound 1 / Sound 2
Bit 0-6: Lautstärke

0x37

 

8

R/W

Alarmsound testen

 

 

 

Sound 1 ist momentan ein einfaches Tatü Tatü, Sound 2 kennt der Insider von Raumschiff Enterprise - Red Alert ;)

Hier die Original Registerstruktur zum Vergleich:

Address

Name

Bits

Access

Description

Default

0x00

WHO_AM_I

8

R

Device identification register

0xA6

0x01

version

8

R

Version number

-

0x02

uuid0

32

R

Unique ID (lower 32 bits)

-

0x06

uuid1

32

R

Unique ID (middle 32 bits)

-

0x0A

uuid2

32

R

Unique ID (upper 32 bits)

-

0x0E

output_voltage

16

R

Output voltage (unit: mV, 5000mV output)

-

0x10

input_voltage

16

R

Input voltage (unit: mV)

-

0x12

battery_voltage

16

R

Battery voltage (unit: mV)

-

0x14

mcu_voltage

16

R

MCU voltage (unit: mV)

-

0x16

output_current

16

R

Output current (unit: mA, 5V output)

-

0x18

input_current

16

R

Input current (unit: mA)

-

0x1A

battery_current

16

R

Battery current (signed, unit: mA)

-

0x1C

temperature

8

R

Temperature (two's complement, unit: °C)

-

0x1D

CR1

8

R/W

Control Register 1

0x01

0x1E

CR2

8

R/W

Control Register 2 (Reserved)

0x00

0x1F

SR1

8

R

Status Register 1

-

0x20

SR2

8

R

Status Register 2

-

0x21

battery_protection_ voltage

16

R/W

Battery protection voltage (unit: mV)

7400

0x23

shutdown_ countdown

16

R/W

Shutdown countdown (unit: seconds)

-

0x25

auto_start_voltage

16

R/W

Auto-start voltage threshold (unit: mV)

7400

0x27

rsv

16

R/W

Python output buffer content length

-

0x29

ota_request

16

W

Writing to 0xA5A5 will request OTA mode.

-

0x2B

runtime

64

R

Cumulative runtime (unit: millisecond)

-

0x33

charge_detect_ interval

16

R/W

Charge detection interval (unit: seconds)

-

0x35

led_ctl

8

R/W

LED control register

0x01

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Das heißt, alle Parameter, die zum sicheren Betrieb einer UPS notwendig sind, können über die vom Original bekannten Register abgerufen werden. Skripte und Programme, die von 52PI über Github für den Betrieb der UPS Gen 6 zur Verfügung gestellt werden, laufen mit der Custom Firmware.

Die geänderten Register - in der Tabelle gelb markiert - stellen Parameter zur Verfügung, die in der Original-Firmware nicht vorhanden sind.

Die Funktionen des Tasters der UPS sind etwas umfangreicher geworden:

  • Im normalen Betrieb der UPS geht das Display nach 5 Minuten aus. In diesem Zustand bewirkt der erste Druck auf den Taster das Aufwecken des Displays.
  • Ist die UPS deaktiviert, bewirkt ein einzelner Druck den Start der UPS, die 5 V-Leitung zum Raspberry Pi (RPi) wird aktiviert. Ist ein Netzteil angeschlossen, übernimmt dieses die Versorgung des RPi, ohne Netzteil erledigen das die beiden in Serie geschalteten LiIon-Akkus.
  • Läuft der RPi, kann das System mittels Doppelklick auf den Taster ausgeschaltet werden. Dabei bekommt zuerst der RPi eine Aufforderung zum ordentlichen Shutdown, wofür er 2 Minuten Zeit bekommt, bevor sich die UPS selbst abschaltet. Dieser Shutdown-Prozess muss vom RPi selbst initiiert werden. Er muss dafür zyklisch das shutdown countdown Register der UPS überwachen und entsprechend reagieren.
  • Mit 5 Klicks startet der STM32 in seinen Bootloader und erwartet dann, über den USART mit einer neuen Firmware gefüttert zu werden. Die 5 V Versorgung läuft in diesem Fall weiter, der RPi muss also nicht vorher runtergefahren werden.
  • Wird der Taster für mehr als 4 Sekunden – aber weniger als 8 Sekunden – festgehalten, wird der Powerbank IC IP5389 resettet. Die 5 V Versorgung bleibt dabei bestehen, der RPi läuft weiter.
  • Hält man den Taster länger als 8 Sekunden fest, wird sofort und bedingungslos die 5V Versorgung abgeschaltet. Die UPS geht in PowerDown – alles AUS. In diesem Zustand kann die UPS mit einem einzelnen Druck auf den Taster wieder aufgeweckt werden, die 5 V Versorgung wird aktiviert, der RPi startet.

Diese Kombination aus „Taster 10 Sekunden halten – warten bis das Display „SYS: OFF“ anzeigt -  Taster einmal drücken“ ist die einzige Möglichkeit, den RPi zu starten, ohne Netzteil und Akku ab- und wieder einzustöpseln.

Ist die USV bei Netzausfall so lange in Betrieb, dass die Akkus leer werden, bekommt zuerst der RPi den Hinweis, dass es Zeit ist, sich selbst schlafen zu legen. Auf dem RPi muss ein Skript laufen, das diesen Hinweis (das shutdown countdown Register nimmt einen von 0 (Null) verschiedenen Wert an) entgegen nimmt und auch beherzigt. Danach gibt die USV dem RPi 120 Sekunden Zeit, runter zu fahren. Mein RPi 3 B+ mit HAOS benötigt dafür ziemlich genau 90 Sekunden, ein RPi 5 ist mit ca. 35 s deutlich schneller. Nach den 120 Sekunden legt sich die USV selbst ins Koma und wacht fürderhin alle 5 Sekunde kurz auf, prüft, ob das Netzteil wieder Strom liefert und legt sich wieder schlafen, falls das nicht der Fall ist.

Wenn in so einem Aufwachmoment der Taster an der USV aktiv ist (dazu den Taster im Zweifelsfall 5 Sekunden lang festhalten), springt der STM32 kurz an, zeigt auf dem OLED die wesentlichen Parameter an und startet einen Countdown von 15 Sekunden mit Anzeige der Restzeit im Display. Während dieser 15 Sekunden funktioniert der Taster wie im normalen Betrieb, d.h. alle oben beschriebenen Funktionen können ausgelöst werden. Wird die Taste in dieser Zeit nicht betätigt, legt sich die USV wieder schlafen.

Da der Programmierzugang zum STM32 über einen 10-poligen FFC-Sockel erfolgt, der neben dem USART zum Programmieren der Firmware über den unzerstörbar im ROM abgelegten Bootloader noch GND, 3,3 V und 5 V sowie ein paar IOs zur Verfügung stellt, habe ich als Gimmick ein OLED Display und als echten Mehrwert die PWM Ansteuerung eines Lüfters, z.B. Noctua NF-A9 5V PWM, zusätzlich implementiert. Die angedachte Drehzahlanzeige auf dem Display wurde zugunsten der Anzeige der Ströme am USB-C Eingang und am Ausgang der UPS verworfen. Der angezeigte Ausgangsstrom ist die Summe der Ströme für den RPi, die SSD, das OLED Display, den Lüfter und die Schaltung der UPS an sich.

Der eingebaute Mini-Lüfter ist mir zu laut, weshalb ich ihn nicht benutze. Stattdessen wird ein 92 mm durchmessender Noctua 92 5V PWM-Lüfter verwendet, der unhörbar seinen Dienst versieht.

Im Getriebe meiner HA Skripte existiert übrigens ebenfalls eine identisch aufgebaute Steuerung für den Lüfter, die wahlweise verwendet werden kann. Die Betriebsspannung erhält der Lüfter dann über den SATA Power Port der UPS, der PWM Eingang des Lüfters wird über Pin 12 des RPi Steckers angesteuert. Damit das funktioniert, muss das AddOn pigpio in HA installiert werden, das den Zugriff auf den PWM-Ausgang des RPi aus HA heraus ermöglicht. (Nachtrag: Diese Möglichkeit habe ich wieder entfernt, die Steuerung über den STM32 ist die bessere Alternative. Bei Verwendung meiner Adapterplatine kann das Originalkabel des Lüfters ohne Bastelei einfach angesteckt werden).

Achtung! Dieser spezielle Noctua Lüfter darf ausschließlich mit 5 V betrieben werden!

Die Steuerung des Lüfters über den STM32 der UPS hat den Vorteil, dass der Lüfter auch bei heruntergefahrenem RPi gesteuert wird. Hat der RPi bzw. HA die Hoheit über den Lüfter, geht er aus oder dreht mit voller Drehzahl, sobald HA gestoppt wird, z.B. bei einem HA Update.

Den 92 mm durchmessenden Lüfter habe ich gewählt, weil der Turm aus Akku-Halter, Kühlelement, UPS-Platine, Raspberry Pi und SSD-HAT rund 90 mm hoch baut. Der Lüfter bläst quer durch den Platinenstapel und hält die Temperatur aller Bauteile auf gesundem Niveau.

Damit der Lüfter nicht einfach neben dem Platinenstapel stehen muss, habe ich eine Art offenes Gehäuse entworfen und 3D-gedruckt.

UPS Gen6 Gehäuse

Die schicke Einkerbung in der Mitte der Seite ist für die LED des SSD-HAT, wobei ich diese LED erst ein einziges Mal habe leuchten sehen. Sie ist definitiv keine Aktivitätsanzeige der SSD - eventuell zeigt sie an, wenn der USB-mSATA Controller Housekeeping-Aufgaben (Garbage Collection und/oder Wear Leveling) durchführt.

Im richtigen Leben sieht der Tower so aus:

UPS-Tower. Draufsicht

Das weiße Kabel ist der Mittelabgriff der Akkus, das 4-fach Kabel rechts oben ist der Lüfter-Anschluss. Das graue FFC-Kabel muss leider etwas verzwirbelt werden. Die freie 6-fach Buchsenleiste nimmt während des Flash-Vorgangs den 3,3 V USB-Seriell-Adapter auf.

Der Lüfter sitzt eingepasst mit seinen Gummiecken mehr oder weniger fest in den Ausschnitten unten und oben und hält die beiden Teile zusammen. Der RPi-Tower steht ebenfalls nur in seinem Ausschnitt.

UPS-Tower von der Seite

Zuletzt hat der Turm noch eine Abdeckung erhalten. Eigentlich dachte ich, das Rahmendesign ist genau richtig, um das Teil irgendwo in die Ecke zu stellen. Da ich aber bisher immer mal wieder daran herum hantieren musste und ich jedesmal höllisch auf die Verdrahtung, insbesondere auf das empfindliche FFC-Kabel achten musste, konnte ich nicht widerstehen.

UPS Gen 6 Gehäusedeckel

Die Abdeckung ist nicht hundertprozentig gelungen, aber seinen ursprünglichen Zweck - den Drahtverhau schützen - erfüllt das Teil perfekt.

Abdeckung für den Tower

Die Designunterlagen im Format Designspark Mechanical V6.x und die fertigen STL-Dateien für den Slicer gibt es im ZIP.

Nachtrag
Da der bisher im Einsatz befindliche Raspberry Pi 3B+ mit den mittlerweile laufenden Prozessen an den Rand seiner Leitungsfähigkeit gebracht wird, leider öfters aber auch deutlich darüber hinaus, habe ich den Turm aufgerüstet.


Um OLED Display, Lüfter und den Programmieradapter an den FFC-Connector auf dem UPS Board anzuschließen, habe ich mir FFC-Breakout Boards besorgt, die die winzigen FFC -Verbinder auf normale 2,54 mm Steckverbinder umbiegen. Das ist deutlich einfacher und robuster im Betrieb und in der Verarbeitung, als an anderer Stelle schon getestet. Bei diesem anderen Projekt ist die Verwendung eines selbst aufgelöteten FFC-Connectors zu verantworten, da FFC-Connector und das anzuschließende Bauteil statisch auf derselben Platine befestigt sind, also im Betrieb keine Kräfte auf den FFC-Connector einwirken.

UPS Gen6 OLED-Adapter          (Click auf das Bild für größere Darstellung)

R1 sorgt dafür, dass der Lüfter ohne PWM-Signal nicht auf Vollgas geht, sondern still steht. R2, R3 und C3 stellen den Mittelabgriff des 2S Akkupacks für den STM32 zur Spannungsmessung der Einzelzellen zur Verfügung. R4, R5 und C1 sind PullUp und Tiefpass für das Tacho-Signal des Lüfters. C1 und C3 sind Keramikkondensatoren in bedrahteter Perlenform. C3 muss flach auf die Platine gelegt werden, damit der FFC-Adapter sauber darüber passt, den ich mit super flachen 4 mm Stiftleisten auf die Platine gelötet habe.

Nachtrag
R1 muss auf 2k2 geändert werden, um den Lüfter sicher still zu setzen, wenn keine PWM vom µC kommt. Normalerweise dreht der Lüfter ohne PWM mit voller Drehzahl.

Die Platine ist einseitig entflochten, was den Einsatz von TH (Through Hole) Bauelementen anstelle von Hühnerfutter (SMD Bauteile) bedingt. So kommen die auch mal wieder zu Ehren :)

UPS Gen6 OLED-Adapter

Der Adapter liegt einfach oben in seinem schräg angeordneten Fach im Deckel des Tower.

Adapter mit OLED, FFC-Breakout und Programmeranschluss


Die Custom Firmware für die UPS Gen6 von 52PI, die das Ganze zu einem Bündel schnürt, biete ich zum Download an. Damit der Code compilierbar ist und wie vorgesehen arbeitet, muss die selbst geschriebene Library I2C bitbanging eingebunden werden.

Hinter dem Link auf die Custom Firmware liegt immer der aktuelle Stand. Geschuldet der Eigenart von Arduino, dass Verzeichnisname und Dateiname übereinstimmen müssen, heißt die Datei immer gleich, die Version steht im Sourcecode etwa auf Zeile 160:

// =================================================================================
//   FIRMWARE VERSION
// =================================================================================
#define FW_VERSION_MAJOR "1.9."
#define FW_VERSION_MINOR_SUB 84

Solange nur funktionale Erweiterungen eingebaut oder Fehler behoben werden, wird sich die Major Version nicht ändern. Angezeigt wird die Version übrigens ausschließlich auf dem OLED Display, wie im Bild oben (leicht unscharf) zu sehen ist.

Aktualisierung
Die Firmware läuft jetzt (Stand 10/2026) seit ein paar Wochen ohne Fehler oder Auffälligkeiten. Aber kürzlich hat mir David zwei weitere Verbindungen zwischen der Peripherie der USV und dem STM32 Microcontroller aufgezeigt, die ich natürlich nachgezogen habe.

Zum einen wird damit die Spannung am Ausgang der USV Richtung Raspberry Pi ermittelt. Diese Spannung war vorher als Literal fest mit 5V angegeben, jetzt misst der STM32 die Spannung über den Pin PA3. Zum anderen gibt es eine Alternative zur INA219 Messung der Akku-Gesamtspannung über den Analogeingang PB0. Diese beiden Spannungen werden verglichen und bei einer Abweichung größer als 250 mV wird das entsprechende Flag im Statusregister 1 gesetzt. Die aktualisierte Firmware gibt es hier.

Achtung
Der Code hat Prototyp Status und kann sich jederzeit ändern. Ich übernehme keinerlei Verantwortung für die Fehlerfreiheit der Firmware. Der Einsatz der Firmware auf eigener Hardware erfolgt eigenverantwortlich, für eventuelle Probleme, Schäden und Folgeschäden übernehme ich keine Haftung.

Hier noch einmal der Hinweis, dass die UPS Gen 6 mit der Original-Firmware nach meinen Erfahrungen unter Debian Bookworm einwandfrei läuft und keine Probleme bereitet. Die Probleme fingen erst an, als ich die USV dazu verwendet habe, einen Raspberry Pi 3B+ unter HAOS abzusichern.

Wie weiter oben schon angedeutet, gibt es eine aktualisierte Version des RPi Tower.

 


Beim Aufruf dieser Funktion werden Daten an Google in USA übermittelt. Neben Ihrer IP-Adresse wird auch die URL der besuchten Seite übertragen.
Besucherzaehler

Besucher seit
25.11.2000