Posts mit dem Label Python werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Python werden angezeigt. Alle Posts anzeigen

Freitag, 14. August 2026

PowerMgr in der Praxis: PV, Batterie, Kühlung und Hauszustand steuern

PowerMgr in der Praxis: PV, Batterie, Kühlung und Hauszustand steuern

PowerMgr geht über eine Sammlung von Gerätetreibern hinaus. Der interessante Teil liegt in der Regelung: Aus Messwerten, Zuständen und Konfiguration entsteht im laufenden Betrieb eine Entscheidung, ob geladen, entladen, gekühlt, gelüftet oder eine Fahrzeugladung freigegeben wird.

Der erste PowerMgr-Artikel beschreibt, warum das System entstanden ist und welche Geräte es verbindet. Dieser zweite Teil schaut auf die praktische Steuerlogik.

Datenfluss

PowerMgr arbeitet mit mehreren Datenquellen, die unterschiedliche Bedeutung haben.

Der Stromfluss im Haus kommt aus Leistungsmessung, PV-Wechselrichter und Batterie-Inverter. Die Batteriedaten kommen vom Victron MultiPlus II und den Pylontech-Batterien. Wetterdaten kommen aus lokaler Wetterstation, Oko-Wetterstation-Sensoren und OpenWeather. Hauszustände wie Tür-/Fensterstatus oder manuelle Freigaben kommen über Homebridge und weitere Sensoren dazu.

Diese Werte landen nicht bloß in einer Oberfläche. Sie werden in den dynamischen Regeln verwendet. Im Repository ist diese Trennung gut sichtbar:

  • dynamic/020-load-device-data.py lädt Gerätedaten.
  • dynamic/025-health.py behandelt Health- und Fehlerzustände.
  • dynamic/030-weather.py verarbeitet Wetterdaten.
  • dynamic/040-homebridge-states.py liest Homebridge-Zustände.
  • dynamic/050-door-window-sensor-handling.py bewertet Tür- und Fensterzustände.
  • dynamic/070-proxon-timed.py trifft zeitabhängige Proxon-Entscheidungen.
  • dynamic/080-proxon.py enthält zusätzliche Proxon-Gates.
  • dynamic/110-evcc.py steuert EVCC.io-Modi.
  • dynamic_threads/rules/010-energy-storage.py berechnet die ESS-Zielleistung.

Die Regeldateien sind dadurch klein genug, um einzelne Entscheidungen nachvollziehen zu können, ohne das ganze System in einer einzigen Datei zu verstecken.

Batterie und MultiPlus II

Die ESS-Regelung läuft im dynamischen Thread 010-energy-storage.py. Dort wird aus Netzleistung, Inverterleistung und geglätteten Werten ein Zielwert für den Batteriespeicher berechnet.

Ein wichtiger Punkt ist die Bedeutung der Vorzeichen. PowerMgr muss unterscheiden, ob das Haus gerade Leistung aus dem Netz bezieht, Leistung einspeist, die Batterie lädt oder die Batterie entlädt. Zusätzlich beeinflusst der Batterie-Inverter selbst die gemessene Leistung. Deshalb berechnet die Regel eine korrigierte reale Leistung:

p_real = power_phases_connected - p_inv

Danach wird dieser Wert geglättet und als p_real_lp verwendet. Aus diesem geglätteten Wert entstehen zwei Richtungen:

  • corrected_charge_power: verfügbare Leistung zum Laden
  • corrected_discharge_power: Bedarf, der durch Entladen gedeckt werden kann

Erst danach greifen Hysterese, Schrittbegrenzung, Mindestleistungen, SoC-Grenzen, Temperaturprüfung und Fallback-Regeln. Am Ende wird entweder Ladeleistung gesetzt, Entladeleistung gesetzt oder die Leistung auf null gestellt.

Diese Reihenfolge ist wichtig. Ohne Glättung und Begrenzung würde die Batterie auf jede kleine Schwankung reagieren. Ohne korrigierte Leistung würde der Regler teilweise auf Werte reagieren, die bereits durch den eigenen Inverter verfälscht sind.

Kühlung über die Proxon FTW-2

Die Proxon-Steuerung ist einer der sichtbarsten Teile von PowerMgr, weil sie Komfort und Energie direkt verbindet.

Die Datei COOLER_CONTROL.md dokumentiert die wichtigsten Kühlungs-Flags. Sie sind als Erlaubnis-Gates zu verstehen. Ein gesetztes Flag bedeutet nicht automatisch, dass die Kühlung gestartet werden muss. Es bedeutet nur, dass die Kühlung in diesem Zustand laufen darf, wenn alle anderen Bedingungen ebenfalls passen.

Für einen automatischen Start prüft dynamic/070-proxon-timed.py unter anderem:

  • verfügbare Leistung oder Batterieunterstützung
  • aktueller Kühlungszustand
  • Intensivlüftung
  • Außentemperatur
  • erwartete Tagesmaximaltemperatur
  • Proxon-Betriebsart
  • Tür-/Fensterzustände
  • Anwesenheit, falls konfiguriert
  • Mindestabstand zwischen mechanischen Schaltvorgängen

Der mechanische Schaltabstand ist bewusst defensiv. Auch wenn die Konfiguration einen niedrigeren Wert erlauben würde, erzwingt der Code für den Proxon-Kühler mindestens 7200 Sekunden. Dadurch wird verhindert, dass die Anlage durch kurzfristige Leistungsschwankungen ständig ein- und ausgeschaltet wird.

Wenn die Batterie gerade lädt und cooler_run_while_battery_charge erlaubt ist, kann die Ladeleistung zur verfügbaren Kühlleistung addiert werden. Wenn die Batterie entlädt, startet die Kühlung nicht einfach deshalb. Ein Start über Batterie-Fallback ist nur möglich, wenn zusätzliche Bedingungen passen: SoC, verfügbare Entladeleistung, Außentemperatur, Raumtemperatur und die konfigurierten Leistungsgrenzen.

Das Ergebnis ist keine einfache Regel wie „bei Sonne kühlen“. PowerMgr versucht, Kühlung dann zu nutzen, wenn das Haus davon profitiert und die Energie dafür sinnvoll verfügbar ist.

Lüftung, Luftqualität und Hauszustand

Neben der Kühlung ist auch die Lüftung Teil des Systems. Der praktische Hintergrund ist Komfort und Luftqualität im Haus. Wenn die Luft abends schlecht ist, kann automatische Lüftung wichtiger sein als eine rein energetisch optimale Entscheidung.

PowerMgr verarbeitet dafür Hauszustände und Sensorinformationen gemeinsam mit den Energieflüssen. Tür- und Fenstersensoren sind dabei keine Dekoration. Eine offene Tür oder ein offenes Fenster kann beeinflussen, ob Kühlung oder Proxon-Zustände geschaltet werden sollen. Homebridge liefert außerdem Steuerflags, mit denen bestimmte Automatiken erlaubt, gesperrt oder manuell übersteuert werden können.

Damit bleibt das System lokal bedienbar. Automatik und manuelle Eingriffe schließen sich nicht aus; sie müssen aber im selben Regelpfad sichtbar sein, damit PowerMgr nicht gegen den tatsächlichen Zustand des Hauses arbeitet.

EVCC.io und Fahrzeugladung

Die Datei dynamic/110-evcc.py zeigt, wie PowerMgr die Fahrzeugladung in die restliche Energielogik einbindet.

EVCC.io bleibt dabei das System für die Ladesteuerung. PowerMgr entscheidet aber, wann ein Modus freigegeben oder deaktiviert wird. Dafür werden verfügbare Leistung, Homebridge-Freigaben, Batterie-Ladezustand, Proxon-Kühlung und Wallbox-Zustand berücksichtigt.

Wenn genug überschüssige Leistung vorhanden ist, kann PowerMgr den konfigurierten EVCC-Standardmodus setzen. Wenn Homebridge die Ladung sperrt oder die verfügbare Leistung zu gering wird, kann PowerMgr EVCC.io wieder auf off setzen. Zusätzlich gibt es Overwrite-Pfade, über die eine manuelle Ladefreigabe Vorrang bekommen kann.

Die Fahrzeugladung wird dadurch nicht isoliert betrachtet. Sie konkurriert mit Batterie, Kühlung und Hausverbrauch um dieselbe Energie.

Fehlerzustände und Decision-Logs

Ein System, das reale Geräte steuert, braucht nachvollziehbare Fehler- und Diagnosepfade.

PowerMgr trennt das Laden von Gerätedaten und die Bewertung der Health-Zustände. Ein Proxon-Lesefehler, ein Batterieproblem oder ein fehlender Wetterstationswert soll nicht still verschwinden. Gleichzeitig darf eine kurzzeitige Störung nicht automatisch wie ein bestätigter Gerätefehler behandelt werden, ohne dass später nachvollziehbar bleibt, was passiert ist.

Dafür gibt es zwei Ebenen:

  • normale technische Logs über print_log(...)
  • strukturierte Decision-Logs für Steuerentscheidungen

Die Decision-Logs enthalten Komponente, Ereignis, Ergebnis, Grund, Eingangsgrößen und Grenzwerte. Bei ESS-Entscheidungen stehen dort zum Beispiel Zielwert, letzter Wert, p_real_lp, unused_pv_lp, power_lp und SoC. Bei Proxon-Entscheidungen werden verfügbare Leistung, Batterieunterstützung, Temperaturwerte und Gründe wie pv_surplus oder battery_support sichtbar.

Das ist im Betrieb entscheidend. Wenn die Kühlung nicht startet, reicht ein „aus“ im Status nicht. Interessant ist, ob Leistung fehlte, die Betriebsart nicht passte, ein Fenster offen war, der Schaltabstand noch lief oder die Batteriegrenze erreicht wurde.

Warum die Regelung lokal bleibt

PowerMgr läuft lokal auf Embedded Linux und wird als Docker-Container betrieben. Das reduziert Abhängigkeiten von Cloud-Diensten und hält die Steuerung nah an den Geräten. Externe Dienste wie OpenWeather oder EVCC.io können eingebunden werden, aber die Grundlogik bleibt im eigenen System.

Für ein Energiemanagement im Haus ist das ein wichtiger Unterschied. Wenn PV, Batterie, Wärmepumpe, Lüftung und Fahrzeugladung zusammenhängen, reicht eine Sammlung loser App-Automatiken nicht aus. Die zentrale Regelung muss Zustände zusammenführen, Konflikte auflösen und begründen können, warum sie gerade nichts tut.

PowerMgr ist genau aus diesem Bedarf gewachsen: messen, bewerten, entscheiden, begrenzen und später erklären können, warum diese Entscheidung getroffen wurde.

Freitag, 7. August 2026

PowerMgr: Mein selbst gebautes Energie- und Smart-Home-System

PowerMgr: Mein selbst gebautes Energie- und Smart-Home-System

PowerMgr ist mein eigenes Home-Energy-Management-System. Es verbindet Photovoltaik, Batteriespeicher, Wechselrichter, Wärmepumpe, Wetterdaten, Sensoren und Smart-Home-Schnittstellen zu einem lokalen System, das Messwerte sammelt und daraus Steuerentscheidungen ableitet.

Der Kern läuft auf einem kleinen Embedded-Linux-System mit Armbian und Docker. Das ist bewusst unspektakulär: kein proprietärer Smart-Home-Computer, keine komplette Neuverkabelung des Hauses, sondern ein dauerhaft laufender Linux-Rechner, der vorhandene Geräte einbindet und die relevanten Daten an einer Stelle zusammenführt.

Ausgangslage

Beim Hausbau war Smart Home zwar grundsätzlich ein Thema, praktisch fehlten aber viele der Dinge, die später wirklich wichtig wurden. Ein zusätzlicher Smart-Home-Computer hätte mehrere tausend Euro gekostet. Damit wären aber noch keine elektrischen Rollos, Tür- und Fenstersensoren, Heizungs- oder Kühlungssteuerungen und keine sinnvolle Einbindung der Energieanlage vorhanden gewesen.

Später kamen Angebote von Ingenieurbüros dazu, die das Haus für den Betrieb mit Batteriespeicher und Energiemanagement deutlich umfassender umgebaut hätten. Die Größenordnung lag im fünfstelligen Bereich bis etwa 25.000 EUR. Der technische und finanzielle Nutzen passte für mich nicht zusammen: Das Haus hätte teuer umgebaut werden müssen, obwohl viele Geräte bereits vorhanden waren und nur miteinander sprechen mussten.

PowerMgr entstand deshalb aus einem sehr konkreten Ziel: Vorhandene Hardware weiterverwenden, offene oder zumindest lokal kontrollierbare Schnittstellen nutzen und daraus ein System bauen, das zum realen Haus passt.

Warum Eigenbau?

Das Problem war nicht, dass es keine Smart-Home-Produkte gab. Das Problem war, dass die verfügbaren Lösungen die eigentlichen Energiefragen nicht gut genug beantworteten.

Für mich ging es nicht darum, eine Lampe per App einzuschalten. Das System sollte verstehen, wann Energie erzeugt, gespeichert, verbraucht oder ins Netz eingespeist wird. Daraus sollten Entscheidungen entstehen:

  • Soll die Batterie geladen oder entladen werden?
  • Ist genug PV-Leistung übrig, um die Kühlung zu starten?
  • Muss die Lüftung laufen, weil die Luft im Haus schlecht ist?
  • Soll eine Fahrzeugladung freigegeben, gedrosselt oder gestoppt werden?
  • Sind Türen oder Fenster offen, obwohl die Kühlung aktiv werden soll?
  • Welche Daten müssen in HomeKit, Grafana oder einer mobilen App sichtbar sein?

Dafür war ein klassisches Smart-Home-System zu oberflächlich. Ein reines Energiemonitoring hätte dagegen nur angezeigt, was passiert, aber nicht aktiv gesteuert. PowerMgr sitzt genau dazwischen: Es ist kein universelles Smart-Home-Framework, sondern eine lokale Steuerung für das eigene Haus und die eigene Energieanlage.

Systemüberblick

PowerMgr ist ein Python-Projekt mit Docker-Betrieb. Im Repository liegen unter anderem ein Dockerfile, eine docker-compose.yml, Konfigurationsdateien, ein Webinterface, dynamische Regeldateien und Module für die angebundenen Geräte.

Die wichtigste Struktur ist nicht eine einzelne große Steuerdatei, sondern die Trennung nach Aufgaben:

  • powermgr.py startet den Hauptprozess.
  • lib/ enthält Geräteanbindungen und gemeinsame Infrastruktur.
  • dynamic/ enthält Regeldateien, die im Betrieb ausgewertet werden.
  • dynamic_threads/ enthält länger laufende Regelpfade, zum Beispiel für die ESS-Leistungssteuerung.
  • html/ stellt Webinterface und Statusseiten bereit.
  • conf/ enthält Beispielkonfiguration und Betriebsparameter.

Die dynamischen Regeldateien werden nach ihrem dreistelligen Präfix sortiert ausgeführt. Dadurch ist der Ablauf im Betrieb nachvollziehbar: erst Grunddaten laden, dann Gesundheitszustände bewerten, Wetter und Homebridge-Status einlesen, anschließend Proxon, Shelly, EVCC und andere Steuerpfade behandeln.

Eingebundene Geräte und Datenquellen

PowerMgr bindet mehrere sehr unterschiedliche Systeme zusammen.

Die Photovoltaikseite wird unter anderem über einen StecaGrid-Wechselrichter ausgelesen. Das Modul lib/stecagrid.py liest die aktuelle AC-Leistung und schreibt die Daten für die spätere Auswertung nach InfluxDB.

Der Batteriespeicher wird über einen Victron MultiPlus II und Pylontech-Batterien eingebunden. Das Modul lib/energy_storage.py liest Inverter- und Batteriedaten, überwacht Zustände und stellt Funktionen bereit, um Lade- und Entladeleistungen zu setzen.

Die Zimmermann Proxon FTW-2 wird angezeigt und gesteuert. PowerMgr kann Betriebsart, Kühlung, Lüftung, Heizelemente und weitere Zustände berücksichtigen. Die Regeln dafür liegen unter anderem in dynamic/070-proxon-timed.py, dynamic/080-proxon.py und dynamic/090-proxon-t300.py.

Wetterdaten kommen aus einer eigenen Wetterstation, optionalen Oko-Wetterstation-Sensoren und OpenWeather. Das ist wichtig, weil Energieentscheidungen im Haus nicht nur vom aktuellen Stromwert abhängen. Für Kühlung und Lüftung spielen Außentemperatur, Tagesmaximaltemperatur, Raumtemperaturen und verfügbare PV-Leistung zusammen.

Zusätzlich sind Homebridge, Shelly-Geräte, Tür-/Fenstersensoren und EVCC.io angebunden. Dadurch werden Hauszustände, manuelle Freigaben und Fahrzeugladung Teil derselben Entscheidungslogik.

Vom Messen zum Steuern

PowerMgr sammelt nicht nur Daten. Das System entscheidet im Betrieb, ob eine Aktion sinnvoll ist.

Ein einfaches Beispiel ist die Kühlung. Wenn genug PV-Leistung verfügbar ist, die Außentemperatur hoch genug ist, die Tagesprognose passt, Türen und Fenster geschlossen sind und die Proxon in der passenden Betriebsart läuft, kann PowerMgr die Kühlung einschalten. Wenn die Batterie gerade lädt, kann diese Ladeleistung je nach Konfiguration als verfügbare Leistung mitgezählt werden. Wenn die Batterie entlädt, kann die Kühlung unter bestimmten Komfort- und SoC-Grenzen weiterlaufen oder durch Batterie-Fallback unterstützt werden.

Das ist der entscheidende Unterschied zu einer starren Zeitsteuerung. Die Anlage reagiert auf Hauszustand, Energiefluss und Komfortbedingungen.

Betrieb und Beobachtbarkeit

Der Betrieb ist lokal und nachvollziehbar aufgebaut. Das Webinterface zeigt Statusdaten, Konfiguration und Diagnoseinformationen. Zusätzlich schreibt PowerMgr Messwerte nach InfluxDB, sodass sie in Grafana ausgewertet werden können.

Für Steuerentscheidungen gibt es ein eigenes Decision-Logging. Neben dem normalen Textlog hält PowerMgr strukturierte Ereignisse im Speicher und stellt sie über diese Endpunkte bereit:

/decision_log
/decision_log.json

Damit lässt sich später sehen, was passiert ist und warum es passiert ist. Bei der Kühlung kann zum Beispiel sichtbar werden, ob PV-Überschuss, Batterieunterstützung, geöffnete Fenster, Wallbox-Ladung oder Temperaturgrenzen die Entscheidung beeinflusst haben. Bei der Batterie wird sichtbar, welcher Zielwert berechnet wurde und welche Eingangsgrößen beteiligt waren.

Ergebnis

Der praktische Nutzen liegt in der Eigenverwendung des erzeugten Stroms. Zu Beginn lag die eigene Nutzung der PV-Erzeugung nur grob bei 10 bis 15 Prozent. Im aktuellen Ausbau liegt sie nach eigener Messung bei etwas über 70 Prozent.

Das ist kein abstrakter Optimierungswert. Es bedeutet, dass mehr selbst erzeugter Strom im Haus bleibt: für Grundlast, Batterie, Kühlung, Lüftung, Heizelemente oder Fahrzeugladung. Gerade bei niedriger Einspeisevergütung ist das wichtiger als eine möglichst schöne Smart-Home-Oberfläche.

PowerMgr ist deshalb für mich weniger ein Smart-Home-Projekt im klassischen Sinn. Es ist ein lokales Energie- und Betriebsleitsystem für ein konkretes Haus.

Dienstag, 14. Juli 2026

Blogger Auto Poster: Aus einem Workspace automatisch Blogposts vorbereiten

Blogger Auto Poster

Zweck

Dieses Projekt ist entstanden, um aus vielen vorhandenen lokalen Projekten automatisch strukturierte Markdown-Dateien zu machen und daraus eine Blogger-Queue für klautesblog.blogspot.com aufzubauen. Die Dateien sollen nicht direkt blind veröffentlicht werden, sondern zuerst als geparkte Markdown-Posts im Backlog vorliegen. Danach kann ein Linux-Server in einem festen Intervall jeweils den nächsten Post aus der aktiven Queue hochladen.

Das eigentliche Ziel ist nicht nur ein Upload-Script. Der wichtige Teil ist der Workflow davor: Ein Workspace wird rekursiv analysiert, Projekte werden fachlich eingeordnet, uninteressante Dateien werden ausgeschlossen, relevante Projekte bekommen Story, Ziel, Labels und ein sauberes Markdown-Format.

Ausgangslage

In meinem Entwicklungsordner lagen viele kleine und größere Projekte: Smart-Home-Energiemanagement, Aquarium-Technik, Amateurfunk-Hardware, Homebridge-Integrationen, ESP32/ESP8266-Hacks, alte Software-Fixes und Tabletop-/Mordheim-Material.

Viele dieser Projekte waren technisch interessant, aber nicht direkt als Blogpost nutzbar. Es fehlte eine einheitliche Struktur:

  • Was war das Problem?
  • Warum wurde das Projekt angefangen?
  • Was war das konkrete Ziel?
  • Welche Hardware und Software gehören dazu?
  • Ist das Projekt wirklich postbar?
  • Welche Labels passen später in Blogger?
  • Welche Dateien sollen ignoriert werden?

Grundidee

Der Ablauf besteht aus zwei getrennten Schritten:

  1. Codex analysiert den Workspace und erzeugt Markdown-Dokumentation.
  2. Der Blogger Auto Poster nimmt freigegebene Markdown-Dateien und lädt sie in festen Intervallen zu Blogger hoch.

Diese Trennung ist wichtig. Die Analyse darf ruhig interaktiv sein, weil Projektkontext oft nur im Kopf vorhanden ist. Der Upload soll dagegen langweilig und deterministisch laufen.

Prompt 1: Workspace rekursiv analysieren

Der erste Prompt beschreibt den Analyseauftrag. Er soll nicht sofort posten und auch keine Projektdateien verändern, sondern nur Dokumentation erzeugen.

Analysiere den aktuell geöffneten Workspace rekursiv.

Ziel:
- Finde alle relevanten Projekte.
- Erstelle pro Projekt eine Markdown-Datei im Ordner output/.
- Ändere keine bestehenden Projektdateien.
- Poste nichts automatisch.
- Beschreibe Zweck, Hardware, Software, Aufbau, Build, Konfiguration,
  Verwendung, Schnittstellen, Stolpersteine und offene Punkte.
- Kennzeichne Unsicherheiten klar.
- Dokumentiere keine Secrets, Tokens, privaten IPs oder Passwörter.

Damit entsteht zuerst eine technische Rohdokumentation. Sie ist noch kein fertiger Blogpost, aber sie macht sichtbar, welche Projekte es überhaupt gibt.

Prompt 2: Projekte fachlich bewerten

Danach folgt die Frage, welche Dateien für einen Blog interessant sind. Dabei geht es nicht um perfekte Texte, sondern um eine harte Vorauswahl.

Prüfe alle erzeugten Markdown-Dateien.

Ziel:
- Welche Dateien sind als einzige Posts auf klautesblog.blogspot.com interessant?
- Welche passen zu einem technischen Blog?
- Welche sind eher nicht interessant?
- Nichts posten und nichts extern ändern.
- Liste klar auf, welche Dateien passen und welche nicht.
- Die Story dahinter darf noch fehlen; das ist ein eigener Schritt.

Dieser Schritt trennt technische Artefakte von echten Blog-Kandidaten.

Prompt 3: Upstream-Projekte und Quellen prüfen

Viele kleine Projekte basieren auf fremden GitHub-Repositories, Schaltplänen, YouTube-Videos oder bestehenden Bibliotheken. Das muss sauber in die Dokumentation.

Prüfe bei welchen Projekten ein bestehendes Projekt eines anderen
auf GitHub oder eine andere externe Quelle als Basis genommen wurde.

Wenn das in der Dokumentation fehlt:
- Ergänze einen Hinweis auf Basis/Upstream.
- Mache klar, was eigenes Projekt ist und was nicht.
- Verlinke das Original, wenn es erkennbar ist.
- Ändere nur die erzeugten Dokumentationsdateien.

Das ist wichtig, weil ein Blogpost sonst schnell so wirkt, als sei alles komplett selbst entwickelt worden.

Prompt 4: Entstehung und Ziel interaktiv ergänzen

Die technische Analyse allein reicht nicht. Ein Projekt wird erst durch die Entstehungsgeschichte interessant.

Frage mich zu jedem relevanten Projekt:
- Warum habe ich dieses Projekt angefangen?
- Welches konkrete Problem sollte gelöst werden?
- Was war das Ziel?
- Was ist das Ergebnis oder der aktuelle Status?

Füge diese Angaben in die jeweilige Markdown-Datei im output-Ordner ein.

Ein Beispiel dafür ist PowerMgr.

Beispiel: PowerMgr

Die reine Codeanalyse erkennt ein Python-/Docker-Projekt für Energiemanagement. Der wichtige Blogwert steckt aber in der Geschichte dahinter:

  • Es sollte ein Energiemanagement entstehen, das vorhandene Geräte weiter nutzt.
  • Eingebunden wurden unter anderem StecaGrid-PV-Wechselrichter, Zimmermann Proxon FTW-2, Shelly-Geräte, DIY-Wetterstation, OpenWeather, ESP32-Geräte und EVCC.io.
  • Angebote von Ingenieurbüros lagen bei etwa 15.000 bis 25.000 EUR für einen Umbau des Hauses.
  • Das eigene System bindet einen Victron Multiplus ein.
  • Ergebnis: etwa 50 Prozent weniger Stromkosten und etwa 70 Prozent Eigenverbrauch der PV-Erzeugung.

Aus einer technischen Datei wird dadurch ein nachvollziehbarer Artikel: Problem, Eigenbau, Integration, Ergebnis.

Prompt 5: Ignorierte Projekte verschieben

Nicht alles soll in die Blogqueue. Manche Projekte waren nur Tests, Sackgassen oder reine Fremdsoftware.

Alles, was ich als "ignorieren" markiert habe,
verschiebe in output/ignore.

Diese Dateien sollen erhalten bleiben, aber nicht als Blogpost-Kandidaten gelten.

Im Auto-Poster bleibt dieser Mechanismus erhalten: posts/queue/ignore/ wird vom Upload-Script übersprungen.

Prompt 6: Neues Auto-Poster-Projekt erzeugen

Aus der analysierten Dokumentation wurde danach ein eigenes Projekt gebaut.

Erstelle ein neues Projekt für einen Blogger Auto Poster.

Anforderungen:
- Dockerfile
- docker-compose.yml
- Upload-Script
- Config-Datei für Blogger und Input-Ordner
- Shared Input-Folder im Docker Compose Setup
- Post-Intervall in der Config
- Bereits erledigte Markdown-Dateien nach done/ verschieben
- output-Ordner in das neue Projekt verschieben und umbenennen
- Neues Git-Repository initialisieren
- Markdown-Dateien mit Labels und sauberem Post-Format vorbereiten

Das Ergebnis ist dieses Repository.

Umsetzung im Projekt

Aus dem ersten Upload-Script ist inzwischen ein kleines, klar getrenntes Tooling-Projekt geworden. Die wichtigste Änderung ist die Aufteilung nach Verantwortlichkeiten: Benutzereingabe, Markdown-Logik, Blogger-API, lokale State-Datei, Zeitplanung und Docker-Runtime liegen nicht mehr vermischt in einem Script.

Der nachbaubare Stand des Tools liegt öffentlich auf GitHub: klaute/blogger-auto-poster.

Dieses öffentliche Repository enthält nur das Tooling, eine Beispielkonfiguration, einen neutralen Beispielpost und die Setup-Anleitung. Die echten Blogpost-Entwürfe, lokale State-Dateien, OAuth-Konfigurationen und Tokens bleiben im privaten Arbeitsverzeichnis.

Die aktuelle Projektstruktur sieht so aus:

config/
  config.example.yml
posts/
  queue/
    backlog/
    ignore/
  done/
  failed/
  order.txt
scripts/
  update-venv.sh
  load-venv.sh
  get_blogger_token.py
  extract-refresh-key.py
  diagnose-oauth-config.py
  manage-posts.py
  build-and-verify.sh
  test-blogger-config.sh
src/
  config.py
  markdown_posts.py
  state.py
  scheduling.py
  notifications.py
  blogger_api.py
  posting_runtime.py
  post_management.py
  blogger_auto_poster.py
  prepare_posts.py
Dockerfile
docker-compose.yml
requirements.txt

Die Aufteilung ist bewusst pragmatisch:

  • scripts/manage-posts.py ist nur die interaktive Bedienung.
  • src/markdown_posts.py kennt Markdown, Frontmatter, Labels und HTML-Erzeugung.
  • src/blogger_api.py kapselt OAuth und Blogger-API-Aufrufe.
  • src/posting_runtime.py enthält den automatischen Posting-Zyklus.
  • src/post_management.py enthält manuelle Aktionen wie aktualisieren, offline nehmen oder veröffentlichen.
  • src/state.py verwaltet die lokale Tracking-Datei.
  • src/notifications.py kümmert sich um Pushover.
  • src/blogger_auto_poster.py ist nur noch der CLI-Einstieg für den Container und Kompatibilitäts-Exports.

Markdown-Queue

posts/queue/ enthält die aktiven Markdown-Dateien, die der Server verarbeiten darf. posts/queue/backlog/ enthält geparkte Entwürfe, die der Server ignoriert, die aber vom Management-Script bewusst ausgewählt werden können. posts/queue/ignore/ enthält Dateien, die erhalten bleiben, aber nicht automatisch gepostet werden.

Jede Markdown-Datei hat Frontmatter:

---
title: "PowerMgr"
labels:
  - Smart Home
  - Energie
  - PV
---

Die Freigabe ist absichtlich einfach und erfolgt über Ordner:

  • posts/queue/: aktiv, darf vom Server verarbeitet werden.
  • posts/queue/backlog/: geparkt, wird vom Server nicht automatisch verarbeitet, kann aber vom Management-Script ausgewählt werden.
  • posts/queue/ignore/: ignoriert oder Rohmaterial.

Nach erfolgreichem Upload wandert die Datei nach posts/done/. Fehlerhafte Dateien, die nicht gelesen werden können, wandern nach posts/failed/. Der lokale Upload-Status wird zusätzlich in posts/state.json gespeichert.

Wichtig ist die Trennung zwischen lokaler Datei und Blogger-Post: posts/done/ bedeutet nur, dass die Markdown-Datei lokal bereits verarbeitet wurde. Der Eintrag kann mit einem Blogger-Post verknüpft sein, muss es aber nicht mehr sein, wenn der Post auf Blogger gelöscht wurde oder nicht mehr auffindbar ist.

Labels

Labels werden direkt in die Markdown-Dateien geschrieben. Dadurch ist jede Datei für sich vollständig. Das Upload-Script muss nicht raten, welcher Post welche Kategorien braucht.

Die Config enthält keine Label-Regeln. Bestehende Labels können über das Management-Script aus Blogger als Referenz gelesen werden. Vor echten Blogger-Schreibzugriffen gleicht das Tool die Schreibweise der lokalen Labels mit den vorhandenen Blogger-Labels ab. Neue Labels sind erlaubt, werden aber im Log als neu ausgewiesen.

Zusätzlich haben automatisch erzeugte Dateien das Label KI generiert. Damit bleibt im Blog nachvollziehbar, welche Artikel aus diesem Dokumentationsworkflow stammen.

Upload-Zyklus

Der Auto-Poster läuft im Container. In der Config steht das Intervall:

posting:
  interval_seconds: 604800

604800 Sekunden sind eine Woche. Wenn ein Post fällig ist, nimmt das Script die nächste Datei direkt aus posts/queue, wandelt Markdown nach HTML, setzt Titel und Labels und legt den Post über die Blogger API an. Die Reihenfolge kommt aus posts/order.txt; Dateien, die dort nicht stehen, folgen alphabetisch nach Dateiname.

Dabei wird ein unsichtbarer Tracking-Kommentar in den Blogger-Post geschrieben. Dadurch kann das Tool einen vorhandenen Blogger-Post später wiederfinden und aktualisieren, statt versehentlich einen zweiten Post zu erzeugen.

Sicherheitsmodus

Initial ist der Auto-Poster auf Dry-Run gestellt:

posting:
  dry_run: true
  publish_mode: "draft"

So kann man prüfen, welcher Post als nächstes hochgeladen würde, ohne Blogger zu verändern. Für den echten Betrieb wird dry_run auf false gesetzt. publish_mode: draft ist die vorsichtige Variante, weil Blogger dann nur Entwürfe erzeugt.

Für geplante Veröffentlichung gibt es zusätzlich:

posting:
  dry_run: false
  due_mode: "weekly_schedule"
  publish_mode: "scheduled"
  schedule:
    weekday: "friday"
    time: "09:00"
    timezone: "Europe/Berlin"

Damit prüft der Container regelmäßig die Queue, startet echte Uploads aber nur am eingestellten Wochentag zur eingestellten Uhrzeit.

Blogger OAuth

Der Auto-Poster loggt sich nicht mit Benutzername und Passwort bei Blogger ein. Er nutzt die offizielle Blogger API über Google OAuth 2.0.

Die lokale Einrichtung besteht aus drei Teilen:

  • credentials.json: OAuth-Client-Datei aus Google Cloud, bleibt lokal und wird nicht committed.
  • config/config.yml: lokale Runtime-Config mit Blog-ID, Client-ID, Client-Secret und Refresh-Token.
  • config/config.example.yml: versioniertes Beispiel ohne echte Secrets.

Der wichtigste Stolperstein war der Unterschied zwischen Authorization Code und Refresh Token. Die Callback-URL aus dem Browser enthält einen temporären code=... Wert. Dieser Code gehört nicht in die Config. Er muss erst gegen einen echten Refresh Token getauscht werden.

Dafür gibt es zwei Helper:

scripts/get_blogger_token.py
scripts/extract-refresh-key.py

get_blogger_token.py ist der normale Weg, wenn der Browser auf demselben System geöffnet werden kann. extract-refresh-key.py ist für den Server-Fall gedacht: Die Google-Login-URL kann auf einem anderen Rechner geöffnet werden, die komplette Callback-URL wird danach in das Script kopiert. Das Script tauscht den Code gegen einen Refresh Token und aktualisiert die lokale Config.

Zur Prüfung gibt es:

scripts/test-blogger-config.sh --software
scripts/test-blogger-config.sh --oauth
scripts/test-blogger-config.sh --blogger-draft

Der Software-Test prüft die Modulstruktur, Python-Syntax, CLI-Einstiegspunkte und den manuellen Update-Pfad ohne Blogger-Schreibzugriff.

Der Draft-Test erzeugt einen temporären Blogger-Entwurf, prüft die API-Antwort und löscht den Entwurf danach wieder. Er lädt keinen Markdown-Artikel aus der Queue hoch. Wenn das erfolgreich ist, funktionieren Token, Scope, Blog-ID und Schreibrechte.

Lokale Python-Umgebung

Für lokale Python-Scripte gibt es ein venv-Setup:

scripts/update-venv.sh
. scripts/load-venv.sh

update-venv.sh baut .venv neu auf, installiert requirements.txt und prüft die lokalen Python-Einstiegspunkte. load-venv.sh muss mit führendem Punkt geladen werden, weil ein normales Shell-Script die aufrufende Shell nicht dauerhaft aktivieren kann.

Pushover Benachrichtigungen

Der Auto-Poster kann vor echten Blogger-Schreibzugriffen und bei Fehlern Pushover-Nachrichten senden. Dabei wird nicht direkt die Pushover-API aus dem Container angesprochen, sondern der interne Pushover-Proxy aus dem eigenen Pushover-Server-Projekt.

Die Config sieht dafür vereinfacht so aus:

notifications:
  pushover:
    enabled: true
    host: "pushover-app-server"
    port: 8090
    mode: "get"
    token: "PUSHOVER_APP_TOKEN"
    app_name: "Blogger Auto Poster"
    dedupe_prefix: "blogger-auto-poster"

Das entspricht dem vorhandenen Pushover-Proxy-Vertrag: ein HTTP-Aufruf auf /send mit Token, Titel, Nachricht und optionalem dedupe_key. Der Dedupe-Key verhindert doppelte Nachrichten bei wiederholten Tests oder Retry-Situationen.

Benachrichtigt wird unter anderem bei:

  • echtem Uploadversuch als Draft, Live-Post oder geplanter Post
  • Update eines bestehenden Blogger-Posts
  • Fehler im Posting-Zyklus
  • fehlgeschlagenem Blogger-Draft-Test
  • nicht lesbarer Markdown-Datei, die nach failed verschoben wurde

Auch Pushover wird über das Testscript geprüft:

scripts/test-blogger-config.sh --pushover

Ohne Parameter führt das Testscript den kompletten Check aus: Container vorhanden, Dry-Run, OAuth, Pushover und temporärer Blogger-Draft.

Management-Script

Für den normalen Betrieb reicht der Container. Für manuelle Arbeit an der Queue gibt es zusätzlich ein interaktives Management-Script:

scripts/manage-posts.py --config config/config.yml

Das Script listet Markdown-Dateien mit Titel und Labels. Je nach Aktion werden unterschiedliche Ordner angeboten: normale Wartungsaktionen arbeiten mit aktiven Queue-Dateien oder bereits verarbeiteten Done-Dateien, Aktion 1 zeigt zusätzlich Backlog-Dateien an, weil sie der vorgesehene Weg für Upload, Reupload und Update ist. Backlog-Dateien werden also nicht vom Server verarbeitet, können aber bewusst über die Management-Aktion ausgewählt werden.

Bei done Dateien zeigt das Script zusätzlich, ob der lokale Artikel linked oder not linked ist. linked bedeutet: In posts/state.json ist eine Blogger-Post-ID bekannt. not linked bedeutet: Die Markdown-Datei liegt zwar lokal in done, aber das Tool kennt keinen aktuellen Blogger-Post dazu.

Danach können die wichtigsten Wartungsaktionen direkt ausgeführt werden:

  1. Einen ausgewählten Queue-, Backlog- oder Done-Post mit dem konfigurierten publish_mode hochladen oder aktualisieren.
  2. Einen Blogger-Post offline nehmen, also zurück auf Draft setzen, ohne ihn zu löschen.
  3. Einen Blogger-Draft direkt veröffentlichen.
  4. Einen bestehenden Blogger-Post jetzt aktualisieren.
  5. Blogger-Status und die Verknüpfung lokale Datei -> Blogger post id anzeigen.
  6. Die aktuell auf Blogger vorhandenen Labels anzeigen.
  7. Einen Backlog-Post nur aktivieren, aber noch nicht hochladen.
  8. Einen bereits erkannten Blogger-Post löschen.

Die Aktionen zum Offline-Schalten, Veröffentlichen, Aktualisieren, Statusanzeigen und Löschen brauchen eine bestehende Blogger-Verknüpfung. Ein not linked Artikel kann dafür nicht verwendet werden, weil keine Blogger-Post-ID vorhanden ist. Für einen neuen Upload eines not linked Artikels ist Aktion 1 zuständig.

Aktion 1 ist der normale Weg für neue Uploads, Reuploads und Updates. Das Script zeigt aktive Queue-Dateien, Done-Dateien mit oder ohne Blogger-Verknüpfung und Backlog-Dateien an. Eine verknüpfte Done-Datei wird direkt als bestehender Blogger-Post aktualisiert. Eine nicht verknüpfte Done-Datei wird als neuer Blogger-Post hochgeladen und danach neu in posts/state.json verknüpft. Eine Backlog-Datei wird zuerst auf Blogger geschrieben. Wenn es bereits eine lokale Blogger-Verknüpfung für diese Quelle gibt, wird der bestehende Blogger-Post aktualisiert. Erst nach erfolgreichem Blogger-Write wird eine gleichnamige lokale Datei aus posts/done/ nach posts/done/archive/ archiviert und die Backlog-Datei nach posts/done/ verschoben. Wenn die lokal gespeicherte Blogger-ID auf Blogger nicht mehr existiert und Blogger 404 zurückgibt, erstellt Aktion 1 den Post neu und speichert die neue Blogger-ID.

Aktion 7 ist nur noch für den Sonderfall gedacht, dass ein Backlog-Artikel zwar in die aktive Queue verschoben werden soll, aber der Upload später durch den Server oder einen separaten manuellen Lauf passieren soll.

Wenn derselbe Artikel lokal in mehreren Ordnern liegt, gruppiert Aktion 1 diese Kopien über die source_id und zeigt nur die aktive Kopie an. Die Reihenfolge ist posts/queue/, dann posts/queue/backlog/, dann verknüpfte Dateien aus posts/done/. Dadurch verdeckt eine ältere Done-Kopie nicht mehr eine neuere Backlog-Bearbeitung.

Beim lokalen Aufruf übersetzt das Management-Script die Docker-Pfade aus der Config automatisch auf das Repository: /data/queue wird zu posts/queue, /data/done zu posts/done und /data/state.json zu posts/state.json. Damit kann dieselbe config/config.yml für Container und Host-Wartung verwendet werden. Wenn die Config-Pfade bewusst unverändert genutzt werden sollen, gibt es dafür --use-config-paths.

Damit muss man für typische Betriebsfälle keinen API-Aufruf von Hand bauen und keine Markdown-Datei manuell zwischen Backlog, Queue und Done kopieren. Ein gelöschter oder not linked Artikel wird über Aktion 1 aus dem Backlog neu aktiviert und hochgeladen.

Build, Start und Test

Der Server-Betrieb läuft über docker-compose:

scripts/build-and-verify.sh

Das Script baut das Image, startet den Container und führt einen sicheren Dry-Run aus.

Wenn der Container läuft, prüft das Post-Start-Testscript die Installation:

scripts/test-blogger-config.sh --all

Die Ausgabe ist als Checkliste aufgebaut: Preflight, Software-Selbsttest, Dry-Run, OAuth, Pushover und temporärer Blogger-Draft. Am Ende gibt es eine kompakte PASS/SKIP/FAIL-Zusammenfassung.

Warum das nützlich ist

Der größte Vorteil ist nicht die Automatisierung an sich. Der Vorteil ist, dass viele alte Projekte wieder sichtbar werden. Statt in alten Ordnern zu verschwinden, bekommen sie eine einheitliche Struktur, passende Labels und eine klare Entscheidung: aktiv posten, im Backlog parken oder ignorieren.

So kann aus einem gewachsenen Entwicklungsordner schrittweise ein technisches Blogarchiv entstehen.

Freitag, 18. November 2016

Stehwellenmessgerät frei nach ZL1CVD - #SWRMeter

In diesem Beitrag geht es um ein Stehwellenmessgerät. Es handelt sich dabei - im wesentlichen - um ein ähnliches Gerät wie auch ZL1CVD in seinen Videos auf Youtube zeigt. Allerdings sehe ich es - im Vergleich zu Ihm - nicht so kritisch mit der Veröffentlichung der Software und der Hardware.
Wer das Gerät also nachbauen möchte kann dies gerne tun. Ich würde jedoch gerne um eine Rückmeldung zum Aufbau und auch die Messungen mit dem Gerät bitten. Auch Verbesserungen der Schaltung und der Software sind absolut gerne gesehen und auch erwünscht.
Es gibt neben der Umsetzung von ZL1CVD sehr viele andere Umsetzungen und Ausführungen eines solchen Messgerätes im Internet, so dass es keinen Sinn ergeben würde auch nur daran zu denken meine Arbeit zurück halten zu müssen.
Auch gibt es für einige hundert Euro kommerzielle Produkte, für beispielsweise diejenigen welche sich den Aufwand und Spaß des selbst basteln ersparen wollen.
Die Varianten für die im Internet vorhandenen Messgeräte bestehen aus verschiedenen Ausführungen, angefangen mit einem Stück Koaxialkabel und wenigen Bauteilen (einfachste Variante) bis hin zum vollautomatischen Messgerät mit Display, Mikrocontroller, Tasten und Batterie.

Was macht nun aber ein solches Gerät?

Antwort: Es liefert Informationen über die Anpassung einer Antennenanlage an einen Sender. Hierzu muss man wissen dass eine Antennenanlage an den Wellenwiderstand des Senders angepasst werden muss.
Ist sie das nicht werden die hochfrequenten Signale von der Antenne, oder auch dem Kabel in das Gerät zurück reflektiert. Man bringt also durch das aussenden von Signalen wieder Energie in den Sender ein, die eigentlich aber von der Antenne abgestrahlt werden soll.
Schlimmer noch entstehen durch diese Reflexionen im Kabel sogenannte Mantelwellen, die unerwünschte Nebenaussendungen auf anderen Frequenzen erzeugen.
Das Messgerät ermittelt nur den Grad der Anpassung für eine oder mehrere Frequenzen. In der Regel misst man mit einem solchen Gerät die Anpassung für einen ganzen Frequenzbereich.

Das Ergebniss wird dann entweder auf angeschlossenen Zeigergeräten oder wie im Fall des Messgeräts von ZL1CVD sogar auf einem kleinen Display dargestellt. Worauf ich aber aufgrund des Aufwandes der Implementierung momentan verzichte.

Was benötigt man nun also um eine solche Messung durchführen zu können?

Antwort: Eine Einheit welche in der Lage ist ein Signal in einer bestimmten Frequenz und mit einer guten Stabilität zu erzeugen. Dabei sollte die Frequenz des Signals anpassbar sein. Dann eine Messschaltung um die Reflexionen als auch das in das Antennensystem eingebrachte Signal hinreichend zu erfassen.
Und zuletzt noch eine Möglichkeit die gemessenen Daten zu erfassen, abzuspeichern oder auch weiter an einen PC zu transferieren. Alternativ einen integrierten Puffer der die Messdaten bis zum Abruf vorhält.

Auf meinem Git kann die Schaltung für das Gerät heruntergeladen werden. Eine Platine habe ich dazu nicht erstellt. Mein Aufbau befindet sich auf einer beidseitigen Lochraster-Platine. Lediglich die grundlegenden Positionen der diskret aufzubauenden Komponenten habe ich im Layout der Schaltung skizziert. Dies hilft mir beim Aufbau auf einer Lochrasterplatine ungemein.
Das folgende Bild zeigt die fertig aufgebaute Platine von oben. Das darauf folgende Bild die Platine von oben.

Platine von oben
Platine von unten
Hier ist zu sehen das ich für die Verbindungen Leiterbahnen aus Draht und Lötzinn erstellt habe und die Abstände zwischen den Bauteilen recht großzügig gestaltet habe. Für die Messbrücke (Wheatstone) habe ich möglichst genaue Bauteile (Bauteile mit geringer Toleranz) verwendet - zumindest für die verwendeten 50 Ohm Widerstände.

Die zu messenden Signale werden mittels einem LM358 um den Faktor 11 verstärkt, die gemessene Spannung also angehoben. Der LM358 ist ein Operationsverstärker welcher zwar bereits in die Jahre gekommen ist, jedoch trotzdem gute Ergebnisse liefert. Den von ZL1CVD verwendeten OPAMP erwarte ich noch per China-Mail, ich bin gespannt wie sich die Messergebnisse verändern werden.
Als Signalgenerator - welcher einen Frequenzbereich von etwa 800kHz bis 160MHz ausgeben kann - verwende ich wie auch ZL1CVD einen Si5351 Chip.
Breakoutboard Si5351
Allerdings verzichte auch auf die Erstellung einer Schaltung um den Si5351 und verwende direkt ein Breakout-Board von adafru.itDieses kann mit verschiedenen Eingangsspannungen verwendet werden und ist 5V tolerant an den I2C Eingangsleitungen. Dies ist im besonderen wichtig, da der Mikrocontroller ein Arduino Nano ist der mit 5V betrieben wird.
Die maximale Stromstärke, mit der das hochfrequente Signal aus dem Signalgenerator ausgegeben wird, liegt bei 8mA. Als Spannungsquelle wird der USB-Anschluss eines Rechners verwendet, mit dem das Gerät auch gesteuert wird.

Der Ablauf der Messung(en) erfolgt in etwa wie folgt:


Zunächst beginnt der Signalgenerator ein Signal auszusenden, getriggert durch den Arduino. Hierbei entstehen die oben beschriebenen Reflexionen, oder auch nicht. Eine Wheatstone-Messbrücke teilt die fortlaufenden und zurücklaufenden Signale auf und speist diese (gefiltert) in den Operationsverstärker, den LM358. Die Aufteilung geschieht durch die beiden in der Schaltung enthaltenen Germaniumdioden (1N60).
Der Operationsverstärker verstärkt die beiden Signale jeweils um den Faktor 11, so dass die Messwerte vom Mikrocontroller in einer für Ihn besseren Auflösung messbar werden.

Der Mikrocontroller misst - sobald der Signalgenerator sein HF-Signal aussendet - eine vom Anwender zu definierende Zeit lang die vorlaufenden und zurücklaufende Reflektionen. Genauer gesagt die Spannungen welche von Operationsverstärker ausgegeben werden.
Die Anpassung der Antenne an den Sender ermittelt man nun durch die Bildung des Verhältnisses aus den beiden Messwerten. Das VSWR ist immer größer gleich dem Wert 1, daher muss immer durch den größeren Wert geteilt werden.

VSWR = Umax / Umin

Mein SWRMeter kann, wie im Folgenden Bild zu sehen ist, bis in den VHF - Bereich, also dem 2m Band arbeiten. Der VSWR-Wert ist übrigens nicht linear, so wird bei einem VSWR von drei (Zahlenwert 3) 25% der eingebrachten Leistung reflektiert. Und bei einem Zahlenwert von 1.5, 4% und bei einem VSWR von 2 = 11%.

Der Vorgang des Messens wird dann normalerweise für einen ganzen Frequenzbereich wiederholt, so dass eine Aussage für die Anpassung eines Antennensystems auf diesen Messbereich getroffen werden kann. Das folgende Bild zeigt die Messung einer selbst gebastelten Groundplane-Antenne welche für das 2m Band und 70cm ausgelegt worden ist.
Messung 2m - Band einer Groundplane
Ein Vergleich zu anderen Messgeräten und eine Kalibrierung bleibt momentan noch aus, der Signalgenerator ist jedoch in der Lage Kalibrierungswerte anzunehmen und auch anzuwenden. Auch die Genauigkeit der Messungen werde ich bei Gelegenheit einem anderen Messgerät gegenüberstellen.

Als Interface für den Anwender verwende ich kein Display und Taster sondern die USB-Schnittstelle des verwendeten Arduino. Ich habe ein Python-Script geschrieben welches in der Lage ist alle Funktionen des Messgerätes zu bedienen zu können.
Es können Messungen über Frequenzbereiche definiert und durchgeführt, Standard-Einstellungen gespeichert, die Signal-Ausgabestärke in mA gesetzt und die drei Ausgabekanäle des Breakoutboards separat angesteuert werden. 

Mögliche Script-Parameter
Weiter gibt das Script wenn erwünscht eine grafische Darstellung der Messung und oder auch eine CSV-Datei aus. Die grafische Darstellung wird dabei zur Laufzeit der Messung aktualisiert. Wird das Script ohne die Ausgabe der grafischen Ausgabe gestartet wird lediglich ein Fortschrittsbalken auf der Konsole angezeigt.
Wer nun aber ein Problem damit hat eine Kommandozeile zu bedienen findet diverse Windows-Batch-Files und Scripte welche dazu verwendet werden können um die einzelnen Amateurfunk-Bänder scannen zu können.
Die Skripte verwenden Standard-Parameter, welche jedoch durch bearbeiten geändert werden können.

Ausgabebeispiel einer Messung
Es existiert auch ein Script über das per PIP alle benötigten Python-Module nachträglich installiert werden können. Wichtig ist nur das python 2.7.x bereits installiert ist.

Wie bereits erwähnt ist es auch möglich die drei Ausgabe-Kanäle des Signalgenerators einzeln zu aktivieren und deaktivieren, um diese auch separat verwenden zu können. Wichtig bei der Verwendung dieser ist es zu wissen das nur der Kanal "0" an der Messbrücke angeschlossen ist, dass die Ausgabefrequenz per Angabe der Start-Frequenz definiert wird, und dass die Stromstärke der sekundären Kanäle aktuell fest bei 2mA liegt.

Hier ein Video mit einer Messung:


Schlussendlich muss ich noch dazu sagen: Die dargestellten Messungen habe ich nicht selbst durchgeführt sondern mir von einem befreundeten und lizenzierten Funkamateur helfen und durchführen lassen.

Mittwoch, 22. Juni 2016

Cubietruck GPIO with python und SWIG

Um für meinen ChinaCluster diverse externe Hardware steuern und auslösen zu können benötigte ich vor einiger Zeit eine Möglichkeit auf das GPIO-Subsystem des Cubitrucks zugreifen zu können. Dieser ist das Master-System im Cluster.

Für die Implementierung von Software in C/C++ sind die beiden folgenden Quellen die grundlegenden Informationen zum Ziel. Das allgemeine Cubietruck Tutorial und das Cubieboard GPIO tutorial. Ich jedoch würde gerne per Python - und das ohne möglichst alles neu implementieren zu müssen - auf das GPIO-System zugreifen.

Theoretisch gibt es bereits ein WiringCB-Projekt, welches theoretisch ein GPIO-Interface für Cubieboards bereitstellen sollte, in meinem Fall funktionierte dies jedenfalls in keinem meiner Tests.

Was tun also wenn es keine adäquate Lösung gibt? Selbst umsetzen. Daher habe ich hier bereits ein Repository eingerichtet mit dem per Python auf das GPIO-Subsystem - zumindeste meines Cubitrucks - zugegriffen werden kann.

Letztendlich basiert diese Lösung darauf das ich um die C-Implementierung von Stefan Mavrodiev einen Python-Wrapper gelegt habe. Der gängige Weg ist dabei wohl diesen mittels SWIG, unter Zuhilfename eines .i-Files in dem alle zu exportieren Elemente aus der ursprünglichen Library aufgelistet bzw. definiert werden, den Wrapper automatisch generieren und kompilieren zu lassen. Wichtig ist hierbei ein Setup-File manuell erzeugt zu haben in dem die Eigenschaften der neuen GPIO-Library definiert sind. Das Repository beinhaltet eine sehr übersichtliche Umsetzung und kann so ggfls. theoretisch als Beispiel dienen.

Spezielle Software-Pakete habe ich auf dem Armbian des Cubitrucks nicht installiert. Lediglich Python, pypy swig und make und der gcc sollten installiert sein.

Meine Software kann simpel mittels make durchgeführt werden. Achtung, es wird jeweils die Python und pypy-Version der Library kompiliert. Benötigt man beispielsweise die Python-Version kann man diese Zeile einfach im Makefile auskommentieren. Hat man make als normaler User ausgeführt und bereits ausreichend Rechte auf das GPIO-Subsystem wird zudem der automatisch ausgeführte Library-Test ohne Fehlermeldungen ausgeführt. Ansonsten bleibt einem nur der Weg über den User root.

Dienstag, 21. Juni 2016

Genetische Algorithmen und OpenMPI

Dinge die passieren - einen aber ärgerlich stimmen - wie zum Beispiel das ich diesen Artikel bereits geschrieben hatte und ich ihn nun komplett schreiben muss, da die Datei in der er stand leider bei einem unerwarteten Zwangs-Reset meines Rechners verloren ging.

In dem verlorenen Artikel hatte ich darüber geschrieben das es etwas wie genetische Algorithmen gibt, welche dazu herangezogen werden könne Probleme zu lösen für die man z.B. keinen Lösungsansatz besitzt aber das Ziel kennt. Außerdem habe ich über Affen geschrieben die auf Schreibmaschinen tippen und per Evolution in der Lage wären einen Text wie Shakespeares Sommernachtstraum zu schreiben. Bei diesem so genannten Infinite-Monkey-Theorem kann mathematisch, auch ohne Evolution, bereits bewiesen werden das dies möglich ist. Die Evolution soll dabei nur den Fortschritt unterstützen. Diese Aufgabe ist in Etwa gleichzustellen wie ein erstes "Hello World" bei der Verwendung einer neuen Programmiersprache. Aber vielleicht auch ein klein wenig aufwändiger umzusetzen.

Schlussendlich, mal von den ganzen Affen abgesehen, wollte ich nur darüber berichten das ich nun endlich für meinen Cluster eine Software geschrieben habe die alle Elemente des Systems einmal gründlich ausnutzt. Also das Netzwerk, die 20 Prozessor-Cores der OrangePis und auch den RAM gut ausgelastet.

Die Programmiersprache meiner Wahl bei der Umsetzung ist in diesem Fall python - bzw. pypy - in Verbindung mit MPI4PY und OpenMPI. Die Laufzeit ist durch die Verwendung von pypy deutlich reduziert und durch die Möglichkeit der verteilten Berechnungen und Aktivitäten, welche per OpenMPI ermöglicht werden, kann diese weiter reduziert werden. Leider musste ich bei meinen Tests feststellen das mein Notebook mit dem Intel i7 Quadcore - Prozessor der 16GB RAM zur Verfügung hat immer noch schneller ist als der Cluster - aber schnelle und Moderne Hardware kaufen kann ja jeder.

Mein Script ist unterteilt in zwei Bestandteile, einen generischen Teil der für die Ausführung des genetischen Algorithmus zuständig ist und einem ausführenden Hauptteil der unter anderem für MPI zuständig ist. Weiter gibt es seit kurzem einen weiteren generischen Teil welcher den Aufwand der MPI-Kommunikation (welche per SSH realisiert ist) dadurch reduziert indem ein Node-lokales Multiprozessing verwendet wird.

Der Grundlegende Ablauf bei einem solchen genetischen Algorithmus ist immer gleich. Zunächst wird eine initiale Population von DNA-Elementen erzeugt, auf diese einzelnen DNA-Stränge dann eine Fitness-Funktion angewandt, daraufhin aus den besten n-Stück und durch Rekombination eine neue Population (Generation) erzeugt und schlussendlich Mutationen in dieser neuen Population erzeugt. Danach wird der Vorgang beim ausführen der Fitness-Funktion neu begonnen und fortgefahren bis entweder im Idealfall eine Lösung ermittelt worden ist, oder eben eine maximale Anzahl von Versuchen den Vorgang beendet.

Da es genug Tutorials, Beispiele und Quellen zu finden gibt verzichte ich hier auf weitere Details zu meiner Implementierung. Es war eben auch nur ein Test um die Funktionalität des Clusters zu verifizieren. Die Performance kann in dieser Software an einigen Stellen optimiert werden.

So ist die Verwendung der Sprache Python und des pypy-Interpreters sicher nicht performanter als wenn man eine Hochsprache wie C oder C++ verwenden würde. Weiterhin ist ein häufiges austauschen von Daten zwischen den Nodes und des Masters per SSH, unter Berücksichtigung das es sich bei meiner Hardware um Embeddedsystems handelt, vielleicht auch eher ein Flaschenhals. Ebenso wie das 100MBit Netzwerk, aber um die Hardware geht es hier nicht. Weiterhin wird in meiner generalisierten Implementierung des Multiprocessings für jede anstehende Berechnung einer oder mehrere Prozesse neu gestartet und diese daraufhin wieder beendet, was weiteren Overhead auf der CPU erzeugt den man durch geschickte Verwendung eines anderen Prozessschemas verringern könnte.
Auch die Implementierung der Datenstrukturen in Python-spezifischen Datentypen wie Listen und Dictionaries anstatt der Verwendung von numpy wirkt sich vermutlich nicht positiv auf die Performance aus.

Hierbei muss man sich in jedem Fall vermutlich selbst für sich überlegen ob es einen Sinn ergibt seine Software im Nachhinein zu optimieren oder gleich von Anfang an die Beste der Besten der Besten Verfahren, Datenstrukturen und Soft- und Hardwarekomponenten verwendet. In meinem Fall würde ich noch hinzufügen - Hauptsache es macht Spaß und es gibt neues zu entdecken.

Insgesamt bin ich dennoch zufrieden, da der Cluster bewiesen hatte das er zuverlässig, auch unter Volllast mit einem System-Load von 8 (bei 4 CPU-Cores) und mehr trotzdem weiterhin korrekt Arbeitet.

PowerMgr in der Praxis: PV, Batterie, Kühlung und Hauszustand steuern

PowerMgr in der Praxis: PV, Batterie, Kühlung und Hauszustand steuern PowerMgr geht über eine Sammlung von Gerätetreibern hinaus. Der inte...