[Contrib] GIFTV (Geek Magic Ultra) als Anzeigegerät für FHEM

Begonnen von Dr. Boris Neubert, 22 Februar 2026, 15:09:43

Vorheriges Thema - Nächstes Thema

Dr. Boris Neubert

Beim Ali gibt es für teils nur 8 € einen "Mini-Fernseher" Namens Geek Magic Ultra, der aus einem ESP-Microcontroller und einem 240x240-Pixel-LCD besteht, und per USB-Port/-Netzteil mit Strom versorgt wird. Es gibt im Web zahlreiche Rezensionen vom dem Gadget und auch wie man es befreit und auf andere Firmware umflasht, damit es aus HomeAssistant heraus bespielt werden kann. Ich zeige euch im folgenden, wie man es mit der Originalfirmware als Anzeigegerät für FHEM nutzt! Weil sich der Access Point im Gerät mit GIFTV meldet, nenne ich das Gerät im folgenden GIFTV (es kann nämlich auch bewegte GIF-Animationen abspielen).

Prinzip

Das Gerät hat eine Funktion als Fotoalbum mit zeitgesteuertem Bildwechsler. Es ist auch möglich, eingebaute Funktionen wie z. B. die Anzeige von Wetter und Uhrzeit am Standort und irgendwelche Fotos im Wechsel zu zeigen. Um das GIFTV als Anzeigegerät für FHEM zu benutzen, muss man also "nur" in FHEM erzeugte Grafiken regelmäßig zum GIFTV hochladen, nachdem man die im GIFTV vorinstallierten Beispieldateien im Pictures-Menü mit CLEAR gelöscht hat.

Die Grafiken in FHEM werden mit meinem Modul RSS erzeugt und mit dem Perl-Befehl push2giftv() hochgeladen. Über ein wiederholendes at lassen sich dann aktualisierte Grafiken z. B. alle 10 Sekunden auf das GIFTV schieben. Mit mehreren RSS-Geräten können dann auch mehrere Anzeigen im Wechsel geschaltet werden.

push2giftv

Ich habe ein Modul 99_GIFTV.pm in /opt/fhem/FHEM erstellt mit folgendem Inhalt:

sub push2giftv($$) {
    my ($name, $hostname) = @_;
    # wrap code in eval to avoid lethal errors crashing FHEM
    eval {
        # make RSS generate the image
        my $type = "jpg";
        my ($mimetype, $image) = RSS_returnIMG($name, $type);
        # parameters for GIFTV
        my $url = "http://$hostname/doUpload?dir=%2Fimage%2F";
        my $targetfilename = "$name.$type";
        my $param = {
                loglevel => 1,
                url => $url,
                method => "POST",
                hideurl => 0,
                noshutdown => 0,
                callback => sub($$$) { Log3 $name, 1,"ERR:$_[1] DATA:".length($_[2]) },
        };
        # add image as multipart form data
        HttpUtils_AddMultipartData($param, $image,
            {"Content-Disposition" => "form-data; name=\"file\"; filename=\"$targetfilename\"", "Content-Type" => $mimetype }
        );
        # upload to GIFTV
        HttpUtils_NonblockingGet($param);
    };
    if ($@) {
        my $msg = $@;
        chomp $msg;
        Log3 $name, 2, $msg;
    }
}

Dabei wird das seit 22.02.2026 um neue Funktionalität erweiterte HttpUtils verwendet.

Zu laden mit reload 99_GIFTV oder FHEM neu starten.

Der Befehl wird auf der FHEM-Kommandozeile wie folgt aufgerufen:

{ push2giftv("sensorfeed", "192.168.178.131") }
Das erste Argument ist der Name des RSS-Geräts und das zweite Argument die IP-Adresse oder der Hostname des GIFTV. Die JPEG-Datei auf dem GIFTV heißt dann so wie das RSS-Gerät.

RSS

Zum Testen habe ich ein simples RSS-Gerät angelegt.

define sensorfeed RSS jpg has.m11.saarlust.de /opt/fhem/conf/sensorfeed.layout
attr sensorfeed bgcolor ff0000
attr sensorfeed size 240x240

Die Konfigurationsdatei sensorfeed.layout sieht so aus:

# ------------------
# font
# ------------------

font /opt/fhem/conf/DroidSans.ttf

# ------------------
# bottom left corner
# ------------------

#
# date/time
#

rgb "c0c0c0"
pt 18
date 10 160
time 10 180
text 10 200 "Hallo, Welt!"

Damit wird das in der Anlage gezeigte Bild erzeugt.

Zukunft

Ich werde 99_GIFTV.pm gelegentlich im Contrib-Ordner bereitstellen.

Ich habe 4 von den Dingern und werde es vermutlich nutzen, um wesentliche Hausparameter an verschiedenen Stellen im Haus anzeigen zu lassen. Vermutlich muss ich dafür noch das RSS-Modul erweitern, um einfacher Widgets für so eine kleine Anzeige zeichnen zu können.
FHEM-Developer seit 2007, Mitgründer und Förder-Mitglied des FHEM e.V.
Bitte keine unaufgeforderten privaten Nachrichten!

Dr. Boris Neubert

FHEM-Developer seit 2007, Mitgründer und Förder-Mitglied des FHEM e.V.
Bitte keine unaufgeforderten privaten Nachrichten!

Wzut

@Boris, könntest du bitte die Code Abschnitte im Wiki nochmal überarbeiten bzw neu formatieren ?
Der eine oder andere Anfänger wird sich schwer tun diese direkt via copy & paste so zu übernehmen.

Und für Nanchahmer : Könntest du bitte auch deine verwendeten Readings Namen inkl. userReadings etwas näher erklären ?
Also etwa - BatteryPercent = Ladezustand der Batterie - SoC  (das war mir noch klar) ,
aber was sind u.A. BatteryPowerSinkW  , PowerSourceW  ..... usw.
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

Dr. Boris Neubert

Hallo,

ich habe mich mit der Wiki-Formatierung gestern sehr schwer getan. Die Abschnitte sitzen zwischen <code><nowiki>...</nowiki></code>-Tags, aber das Ergebnis ist, wie es ist. Wie muss ich das richtig machen?

Die Readings sind doch im oberen Abschnitt erläutert. Was fehlt da fürs Verständnis denn genau?

Viele Grüße
Boris
FHEM-Developer seit 2007, Mitgründer und Förder-Mitglied des FHEM e.V.
Bitte keine unaufgeforderten privaten Nachrichten!

schwatter

Nabend Boris,

einfach bei anderen Wikieinträgen stöbern. Mach ich auch immer. Beispiel
<syntaxhighlight lang="perl">
define aggr.PV readingsProxy \
  smainverter:SPOT_PDC_SUM:PVPowerSourceW \
  smainverter:SPOT_EPVTODAY:PVEnergySourceWh \      
  smaem:SMAEM1234567890_Bezug_Wirkleistung:GridPowerSourceW \
  smaem:SMAEM1234567890_Einspeisung_Wirkleistung:GridPowerSinkW \
  calc.Netzbezug:smaem_SMAEM1234567890_Bezug_Wirkleistung_Zaehler_EnergyDay:GridEnergySourcekWh \
  calc.Netzeinspeisung:smaem_SMAEM1234567890_Einspeisung_Wirkleistung_Zaehler_EnergyDay:GridEnergySinkkWh \
  smainverter:BAT_P_CHARGE:BatteryPowerSinkW \
  smainverter:BAT_P_DISCHARGE:BatteryPowerSourceW \
  smainverter:ChargeStatus:BatteryPercent \
  smainverter:BAT_LOADTODAY:BatteryEnergySinkWh \
  smainverter:BAT_UNLOADTODAY:BatteryEnergySourceWh \
  smaem:SMAEM1234567890_GridFreq:GridFrequencyHz
attr aggr.PV stateFormat PV: PVPowerSourceW W < PVEnergySourcekWh kWh | Haus: HousePowerSinkW W > HouseEnergySinkkWh kWh | Netz: GridPowerW W < GridEnergySourcekWh kWh > GridEnergySinkkWh kWh | Batterie: BatteryPowerW W BatteryPercent % < BatteryEnergySourcekWh kWh > BatteryEnergySinkkWh kWh
attr aggr.PV userReadings \
  GridPowerW { ReadingsNum("aggr.PV", "GridPowerSourceW", 0) - ReadingsNum("aggr.PV", "GridPowerSinkW", 0) }, \
  BatteryPowerW { ReadingsNum("aggr.PV", "BatteryPowerSourceW", 0) - ReadingsNum("aggr.PV", "BatteryPowerSinkW", 0) }, \
  PVEnergySourcekWh { ReadingsNum("aggr.PV", "PVEnergySourceWh", 0)/1000.0 }, \
  BatteryEnergySourcekWh { ReadingsNum("aggr.PV", "BatteryEnergySourceWh", 0)/1000.0 }, \
  BatteryEnergySinkkWh { ReadingsNum("aggr.PV", "BatteryEnergySinkWh", 0)/1000.0 }, \
  HousePowerSinkW { -( ReadingsNum("aggr.PV", "PVPowerSourceW", 0)+ReadingsNum("aggr.PV", "GridPowerW", 0)+ReadingsNum("aggr.PV", "BatteryPowerW", 0) ) }, \
  HouseEnergySinkkWh { ReadingsNum("aggr.PV", "PVEnergySourcekWh", 0)-ReadingsNum("aggr.PV","GridEnergySinkkWh", 0)+ReadingsNum("aggr.PV", "GridEnergySourcekWh", 0)-ReadingsNum("aggr.PV", "BatteryEnergySinkkWh",0)+ReadingsNum("aggr.PV", "BatteryEnergySourcekWh", 0) \
}
</syntaxhighlight>


Gruß schwatter

Dr. Boris Neubert

Danke schwatter, hab auf dem Schlauch gestanden. Kaum macht man's richtig und schon geht's :-)
FHEM-Developer seit 2007, Mitgründer und Förder-Mitglied des FHEM e.V.
Bitte keine unaufgeforderten privaten Nachrichten!

Wzut

Zitat von: Dr. Boris Neubert am 30 März 2026, 20:26:19Kaum macht man's richtig und schon geht's :-)

 :) und kaum liest man mal richtig den ganzen Text und nicht nur die Code Blöcke versteht man auch deine Readings ... :-[
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher