[gelöst] Daten zwischen FHEM und bash (hier: node.js) austauschen

Begonnen von andies, 09 März 2024, 16:15:48

Vorheriges Thema - Nächstes Thema

andies

Ich habe eine Frage an die Perl-Fachleute. Ich kann mir Perl anlesen, aber die Frage, die ich jetzt habe, übersteigt vor allem meine praktischen Erfahrungen. Und das scheint hier wichtig zu sein.

Zuerst das Problem. Ich baue gerade an einem  Modul für eCharts. Dabei gibt es einige Probleme mit dem rendern (zum Beispiel hier). Konkret geht es darum, dass ich aus FHEM Daten senden muss (ein Javascript-Code), der dann durch das externe Programm node.js bearbeitet wird und das Ergebnis an FHEM zurückgibt.

Das habe ich bisher so gelöst:
Zeile 903    my $svgdata = eval { `$cmd`};      $cmd enthält den Javascript-Code, wobei noch "/entsprechenderPfad/node -e" vorangestellt wird. Bei größerem Codeumfang scheint das schiefzugehen, denn ich lese
PERL WARNING: Can't exec "/bin/sh": Die Argumentliste ist zu lang at ./FHEM/98_eCharts.pm line 903.Mein Betriebssysstem verkraftet die üblichen 2MB (getconf ARG_MAX=2097152), übergeben wurden in diesem Fall aber "nur" 787 KB. Trotzdem geht das schief, $svgdata ist manchmal leer, manchmal aber auch nicht (ich kann nicht herauskriegen, wann und warum - und hier fehlt mir praktische Erfahrung und ich kann nicht debuggen, weil ich nicht weiß, wie man das hier machen kann).

Mögliche Lösungen. Ich habe ChatGPT4 gefragt. Es gibt angeblich keine node.js-Bibliothek für Perl. Also muss man das anders machen. ChatGPT schlägt vor, eine websocket-Verbindung aufzubauen oder das per stdin/stdout zu machen.

Letzteres würde man wohl so umgesetzt werden, indem man
open(my $pipe, "|-", "/entsprechenderPfad/node -e") or die "Geht nicht";
print $pipe $cmd;
close($pipe); 

Nun meine Frage. Kann mir jemand, der da etwa Erfahrung hat, sagen, wie ich da am besten vorgehe? Gibt es da Vorbilder? Bessere Lösungen als das? Im Forum finde ich da nichts ausführliches. Und wenn ich den FHEM-Code in github untersuche, werde ich auch nicht fündig.
FHEM 6.3 auf RaspPi4 (Raspbian:  6.6.28+; Perl: v5.36.0)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

andies

#1
Ich habe nun ein wenig ChatGPT bemüht und gelesen und angeblich soll das hier gehen,
my $pid = open3(my $chld_in, my $chld_out, my $chld_err, $cmd); # in $cmd steht der komplette node-Befehl
my $MeinOutput = '';
while (my $line = <$chld_out>){
$MeinOutput .= $line;
}
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;
die "hat nicht geklappt" if ($child_exit_status != 0) ;
aber ich kriege nur die oben stehende Fehlermeldung. Das klappt also nicht und ich weiß nicht, warum.

Wenn ich den Inhalt von $cmd direkt in der Kommandozeile eingebe, erhalte ich dagegen den Output, den ich auch erwarte. Also da passiert kein Fehler.
FHEM 6.3 auf RaspPi4 (Raspbian:  6.6.28+; Perl: v5.36.0)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

JoWiemann

Zitat von: andies am 09 März 2024, 19:42:24Ich habe nun ein wenig ChatGPT bemüht und gelesen und angeblich soll das hier gehen,

Off Topic:

Bin mal gespannt, wann wir das Forum dicht machen können und nur noch auf der Startseite auf eine KI verweisen.

Grüße Jörg
Jörg Wiemann

Slave: RPi B+ mit 512 MB, COC (868 MHz), CUL V3 (433.92MHz SlowRF); FHEMduino, Aktuelles FHEM

Master: CubieTruck; Debian; Aktuelles FHEM

andies

Immerhin hilft mir die Software und bestellt bei meinen Fragen kein Popcorn wie der eine oder andere hier  ;D
FHEM 6.3 auf RaspPi4 (Raspbian:  6.6.28+; Perl: v5.36.0)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

JoWiemann

Zitat von: andies am 09 März 2024, 21:05:32Immerhin hilft mir die Software und bestellt bei meinen Fragen kein Popcorn wie der eine oder andere hier  ;D

Warts mal ab...
Jörg Wiemann

Slave: RPi B+ mit 512 MB, COC (868 MHz), CUL V3 (433.92MHz SlowRF); FHEMduino, Aktuelles FHEM

Master: CubieTruck; Debian; Aktuelles FHEM

andies

Zitat von: andies am 09 März 2024, 19:42:24Das klappt also nicht und ich weiß nicht, warum.
Ich glaube, ich habe es jetzt. Der Fehler war folgender. Wenn man auf der Kommandozeile mit node ein Javascript-Bild bearbeiten will, muss man unmittelbar nach "node" und vor den Javascript-Befehlen noch die Option "-e" (für evaluate) eingeben. Genau dieses "-e" muss aber, wenn es über diese Art von Prozess läuft, weggelassen werden. Dann klappt alles.

Falls jemand mal dasselbe Problem haben sollte: Ich mache das jetzt wie folgt.
use IPC::Open3;use Symbol 'gensym';
...
my $cmd = ...;                                      #$cmd enthält den Pfad zu node inkl. dem Befehl node, aber ohne -e
...
my $err = gensym;                                   #sammelt Fehler
my $pid = open3(my $in_fh, my $out_fh, $err, $cmd); # siehe https://perldoc.perl.org/IPC::Open3
my $svgdata;                                        # sammelt Output des Befehls "node <Javascript-Befehle>" ein
print $in_fh $eCharts_RET;                          # $eCharts_RET enthält die <Javascript-Befehle>
close($in_fh);

my $sel = IO::Select->new();
$sel->add($out_fh, $err);
while (my @ready = $sel->can_read){
    foreach my $fh (@ready){
        if (eof($fh)){
            $sel->remove($fh);
            next;
        }
        my $line = <$fh>;
        if ($fh == $out_fh){
            $svgdata .= $line;                      # in $svgdata wird der output gesammelt
        } else {
            Log3 $name, 1, "Fehler beim rendern: ".$line; # wenn es schief ging
        }
    }
}

waitpid($pid, 0);
FHEM 6.3 auf RaspPi4 (Raspbian:  6.6.28+; Perl: v5.36.0)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann