Autor Thema: Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?  (Gelesen 795 mal)

Offline Adimarantis

  • Developer
  • Full Member
  • ****
  • Beiträge: 268
Hallo,

ich bin gerade dabei ein Modul für die Verwendung des Signal Messengers (Signalbot - ähnlich dem Telegrambot) zu entwickeln.
Dabei nutze ich das Programm "signal-cli" ( https://github.com/AsamK/signal-cli ) welches man als Daemon im dbus Modus starten kann.
Über die Library Net::DBus ( https://metacpan.org/release/Net-DBus ) kann ich dieses dann von Perl aus ansteuern.

Ich habe es schon geschafft, dass man Nachrichten und Attachments an Personen oder Gruppen schicken kann (die Registrierung muss über die Kommandozeile von signal-cli erfolgen - die Dbus Schnittstelle unterstützt da noch nicht alle Funktionen).

Jetzt wollte ich auch Nachrichten/Rückmeldungen empfangen. Dazu bietet Net::DBus die Möglichkeit callbacks auf Signale von DBus zu implementieren. Diese werden aber so weit ich das verstehe nur aufgerufen, wenn sich das Perl Programm in einem Warteaufruf befindet:
my $reactor = Net::DBus::Reactor->main();
 $reactor->run();

In einem Standalone Beispiel klappt das auch wunderbarm aber FHEM würde da natürlich solange stehen.
Wäre es ok, hier mit den Blockingcalls zu arbeiten und einen fork zu machen in dem diese Schleife dauerhaft läuft?

Weiteres Problem: Die Callbacks bieten keine Möglichkeit $hash durchzureichen - was ist die eleganteste Möglichkeit da trotzdem dranzukommen?

Danke,
Jörg


Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL
70+ Homematic/HMIP, Diverse 433Mhz Sensoren und Schalter
Module: 52_I2C_ADS1x1x (offiziell), 50_Signalbot, 50_SPI_MAX31865

Offline Dr. Boris Neubert

  • Global Moderator
  • Hero Member
  • ****
  • Beiträge: 4835
  • Are we just self-replicating DNA?
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

Offline Adimarantis

  • Developer
  • Full Member
  • ****
  • Beiträge: 268
Antw:Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?
« Antwort #2 am: 24 Januar 2021, 17:58:28 »
Danke!
Hab natürlich intensiv in den offiziellen Modulen gesucht, aber beim allgemeinen "googeln" ist "Signal" ein übler Suchbegriff.
Das schaue ich mir natürlich näher an bevor ich jetzt da Rad zum zweiten Mal erfinde. Hab schon einen Punkt entdeckt, wo man was von mir reinmergen könnte  :)
 
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL
70+ Homematic/HMIP, Diverse 433Mhz Sensoren und Schalter
Module: 52_I2C_ADS1x1x (offiziell), 50_Signalbot, 50_SPI_MAX31865

Offline Wzut

  • Developer
  • Hero Member
  • ****
  • Beiträge: 4430
Antw:Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?
« Antwort #3 am: 24 Januar 2021, 18:03:51 »
Wäre es ok, hier mit den Blockingcalls zu arbeiten und einen fork zu machen in dem diese Schleife dauerhaft läuft?
Mache ich in 73_MPD um die Nachrichten des MPD auszuwerten und fast genau so nochmal in 96_SIP wenn das Modul auf einen Anruf wartet.
Würde mich daher auch interessieren wenn es Argumente dagegen gibt und eventuelle Alternativen.
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

Offline Adimarantis

  • Developer
  • Full Member
  • ****
  • Beiträge: 268
Antw:Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?
« Antwort #4 am: 24 Januar 2021, 23:20:10 »
Ich habe mir SiSi jetzt mal ein wenig angeschaut. Schaut so aus, als würde das Modul nicht sehr aktiv maintained zu werden.
Außerdem funktioniert genau mein Problem dort anscheinend auch nicht: Es werden keine Messages empfangen.

Scheint ein allgemeines Problem unter FHEM zu sein:

Ein blankes Perl Programm ala
my $bus = Net::DBus->system;
my $service = $bus->get_service("org.asamk.Signal");
my $object = $service->get_object("/org/asamk/Signal");

my $sig1 = $object->connect_to_signal("ReceiptReceived", \&rec_callback);
my $sig2 = $object->connect_to_signal("SyncMessageReceived", \&sync_callback);
my $sig3 = $object->connect_to_signal("MessageReceived", \&msg_callback);
my $reactor = Net::DBus::Reactor->main();
$reactor->run();
wartet brav in run() auf Rückmeldungen und ruft die Callbacks auf, so dass man Nachrichten empfangen kann.
Selbst wenn ich diesen Code ganz genau so in einem geforkten FHEM process laufen lassen, dann kommt run() sofort zurück und keine Callbacks werden aufgerufen. Das passiert auch direkt in FHEM ohne fork - hat also mit dem forken eher nichts zu tun.

Weiss irgendein Perl Profi was bei einem Perl Programm von der Kommandozeile hier anders läuft als wenn es in FHEM aufgerufen wird?
Oder vielleicht ist es auch ein Problem bei mir. Sieht jemand unter SiSi dass auch Nachrichten empfangen werden (verbose 5, dann sollte was im Log stehen)? (die Frage habe ich direkt im SiSi Thread gestellt - antworten auch gerne da, falls der Original Entwickler dort eher mitliest).

Gruß,
Jörg
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL
70+ Homematic/HMIP, Diverse 433Mhz Sensoren und Schalter
Module: 52_I2C_ADS1x1x (offiziell), 50_Signalbot, 50_SPI_MAX31865

Offline Dr. Boris Neubert

  • Global Moderator
  • Hero Member
  • ****
  • Beiträge: 4835
  • Are we just self-replicating DNA?
Antw:Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?
« Antwort #5 am: 25 Januar 2021, 08:27:25 »
Hallo Jörg,

ich habe neulich jemandem SiSi installiert und dort wurden Nachrichten empfangen. Das war unter einem aktuelle Raspberry Pi OS.

Grüße
Boris
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

Offline Adimarantis

  • Developer
  • Full Member
  • ****
  • Beiträge: 268
Antw:Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?
« Antwort #6 am: 25 Januar 2021, 10:37:25 »
Hmm.. sehr seltsam.
Habe den Raspberry jetzt mal durchgestartet und das hat geholfen. Jetzt geht sowohl SiSi als auch meine Lösung.
Warum es unter ohne FHEM ging und mit nicht, ist mir ein Rätsel.
Mal sehen ob ich das weiterverfolge. Ich wollte die BlockingCall API nutzen während SiSi da was selbst gebaut hat - aber vielleicht hatte das ja seinen Grund.

Jörg
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL
70+ Homematic/HMIP, Diverse 433Mhz Sensoren und Schalter
Module: 52_I2C_ADS1x1x (offiziell), 50_Signalbot, 50_SPI_MAX31865

Offline Adimarantis

  • Developer
  • Full Member
  • ****
  • Beiträge: 268
Antw:Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?
« Antwort #7 am: 25 Januar 2021, 14:14:00 »
Dann komme ich nochmal auf die Problematik zurück die Device/$hash durchzureichen.

1. Aufruf von BlockingCall im Parent -> alles gut, kann den Devicenamen als Parameter übergeben
2. Callback für Net::DBus initialisieren -> hier kann ich meines Wissen keine Parameter übergeben
    meine Lösung: Globale Variable (die ich nur im Child verwende)
3. Im Net::DBus Callback -> Globale Variable auslesen, message auswerten und per BlockingInformParent() auch den Namen im return String übergeben.
4. Im Parent Callback, diesen String auswerten und über $defs den $hash wiederherstellen.

Mich stört jetzt die globale Variable zwischen (2) und (3) - geht das eleganter, oder ist das ok?
Im Child komme ich eigentlich auch komplett ohne $hash aus, das brauche ich erst wieder beim Auswerten der Daten im Parent.

Jörg

Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL
70+ Homematic/HMIP, Diverse 433Mhz Sensoren und Schalter
Module: 52_I2C_ADS1x1x (offiziell), 50_Signalbot, 50_SPI_MAX31865

Offline rudolfkoenig

  • Administrator
  • Hero Member
  • *****
  • Beiträge: 23848
Antw:Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?
« Antwort #8 am: 25 Januar 2021, 14:27:09 »
Zitat
Mich stört jetzt die globale Variable zwischen (2) und (3) - geht das eleganter, oder ist das ok?
Statt \&msg_callback koenntest Du es mit einer inplace-Funktion versuchen: sub(){ msg_callback($hash) }

Offline herrmannj

  • Global Moderator
  • Hero Member
  • ****
  • Beiträge: 5803
Antw:Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?
« Antwort #9 am: 25 Januar 2021, 15:10:12 »
Hi,

die Funktionalität wird in 32_SiSi.pm mAn doch umgesetzt und zwar via fork. BlockingCall ist auch nichts anderes. Wenn Du Dich da selbst verwirklichen willst bist Du sicher gut bedient Dich an 32_SiSi.pm wenigsten zu orientieren.

Das tiefer liegende "Problem" liegt jedoch darin, dass Net::DBus eine eigene Eventloop definiert. (reactor.pm #321ff, #349ff).

Vergleiche jetzt mal Reactor.pm #372f

  my ($ro, $wo, $eo);
  my $n = select($ro=$ri,$wo=$wi,$eo=$ei, (defined $timeout ? ($timeout ? $timeout/1000 : 0) : undef));
fhem.pl #704
$nfound = select($rout=$rin, $wout=$win, $eout=$ein, $timeout) if(!$nfound);
Es wäre also problemlos möglich (mAn "richtig") die Funktionalität von Reactor.pm auf die Eventloop von fhem zu adaptieren (im eigenen modul). Entsprechende Aufrufe der CPAN Module sind ja dort sichtbar.

Dann erspart man sich das ganze forken und die Interprozesskommunikation und alle damit verbundenen Probleme.
smartVisu mit fronthem, einiges an HM, RFXTRX, Oregon, CUL, Homeeasy, ganz viele LED + Diverse

Offline Adimarantis

  • Developer
  • Full Member
  • ****
  • Beiträge: 268
Antw:Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?
« Antwort #10 am: 25 Januar 2021, 15:21:08 »
Hallo Rudi,

klappt so nicht ganz, da der Callback vom Framework bereits feste Übergabeparameter bekommt.
Hat mich aber auf eine Idee gebracht (und SiSi macht das wohl ähnlich, hatte das nur nicht ganz verstanden, @hermannj: Ist auch ein wenig "Lernprojekt"):
sub blockingCall {

     my $device=<Name übergeben von BlockingCall()>;

     my sub callback {
          my $localdevice=$device;
          ....
         BlockingInformParent("...",$localdevice,0);
    }
    ...
    my $sig1 = $object->connect_to_signal("ReceiptReceived", \&callback);

   reactor->run(); #Eventloop
}
   

Dadurch ist es keine globale Variable, sondern eine der sub selbst.
Musste ich mit "my sub" definieren, sonst bekomme ich ein Warning
 
PERL WARNING: Variable "$device" will not stay shared at ....
Kann das "my sub" Probleme machen? Falls die Eventloop abbricht, werden die Callbacks auch nicht mehr verwendet und sollte daher solange existieren wie man sie braucht.

@hermannj: den select() an FHEM zu delegieren hätte sicher was. Dafür müsste ich mir den "Net::DBus" code mehr zu gemüte führen (wie kommt man an die filehandles? wie kommt man an die Daten für den Callback?). Wenn es dafür keine API gibt und man da tief eingreifen muss, dann ist das auch nicht so gut (Kompatibilität bei updates).

Gruß
Jörg
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL
70+ Homematic/HMIP, Diverse 433Mhz Sensoren und Schalter
Module: 52_I2C_ADS1x1x (offiziell), 50_Signalbot, 50_SPI_MAX31865

Offline rudolfkoenig

  • Administrator
  • Hero Member
  • *****
  • Beiträge: 23848
Antw:Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?
« Antwort #11 am: 25 Januar 2021, 15:43:29 »
Zitat
Kann das "my sub" Probleme machen?
So ein Konstrukt hat bei mir zu einem Speicherloch gefuehrt.
Weiss nicht, ob das in deinem Fall auch zutrifft, bzw. ob das relevant ist.

Offline Adimarantis

  • Developer
  • Full Member
  • ****
  • Beiträge: 268
Antw:Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?
« Antwort #12 am: 25 Januar 2021, 16:17:39 »
Die Unterroutine welche die "my sub" enthält, ist ja im geforkten Process und wird nur einmalig aufgerufen. Der Prozess beendet sich mit der Beendigung der Eventloop, womit das Betriebssystem den Speicher aufräumen sollte. Da sehe ich jetzt in diesem Anwendungsfall eher keine Gefahr.
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL
70+ Homematic/HMIP, Diverse 433Mhz Sensoren und Schalter
Module: 52_I2C_ADS1x1x (offiziell), 50_Signalbot, 50_SPI_MAX31865

Offline Adimarantis

  • Developer
  • Full Member
  • ****
  • Beiträge: 268
Antw:Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?
« Antwort #13 am: 25 Januar 2021, 19:25:19 »
Es wäre also problemlos möglich (mAn "richtig") die Funktionalität von Reactor.pm auf die Eventloop von fhem zu adaptieren (im eigenen modul). Entsprechende Aufrufe der CPAN Module sind ja dort sichtbar.

Dann erspart man sich das ganze forken und die Interprozesskommunikation und alle damit verbundenen Probleme.

So klappt eine eigene Eventloop mit select:
$reactor->{running} = 1;
while ($reactor->{running}) {
print "starting select ".$reactor->{running}."\n";
my ($ri, $ric) = $reactor->_bits("read");
my ($ro);
my $n = select($ro=$ri,undef,undef,undef);
if ($n>0) { print "got something".$reactor->{running}."\n";}
$reactor->step();
}
$reactor->shutdown();

Unschön ist dass man dafür die interne "running" variable setzen muss (sonst kehrt step() ohne Funktion zurück und die interne Funktion _bits() aufrufen muss. D.h. der Autor kann das jederzeit ohne Rücksicht ändern.

Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL
70+ Homematic/HMIP, Diverse 433Mhz Sensoren und Schalter
Module: 52_I2C_ADS1x1x (offiziell), 50_Signalbot, 50_SPI_MAX31865

Offline Adimarantis

  • Developer
  • Full Member
  • ****
  • Beiträge: 268
Antw:Eventcallback Schleife für Dbus - Implementierungsmöglichkeiten?
« Antwort #14 am: 26 Januar 2021, 00:12:29 »
So, hab jetzt eine Version die Nachrichten ohne fork empfangen kann.

Wermutstropfen dabei ist dieses Code-Fragment:
my $count = 0;
my $fds=undef;
    foreach (keys %{$reactor->{fds}->{read}}) {
next unless $reactor->{fds}->{read}->{$_}->{enabled};
$fds=$_;
$count++;
    }
return "Error getting Dbus filehandler" unless defined $fds;

Das holt die Filehandle direkt aus den internen Strukturen (und geht davon aus es gibt nur eine - bei != 1 schmeisse ich aktuell einen Fehler).

Zweite Unschönheit: Ich rufe $reactor->step() vorsichtshalber zweimal auf. Teilweise wurde beim ersten Aufruf kein Callback getriggert. Es könnten aber auch mehrere Nachrichten in der Queue stehen.
Leider hab ich aber keinen Weg gefunden nachzusehen wie viele Nachrichten noch anstehen (um z.B. eine while Schleife zu machen, bis alles gelesen ist).
Damit das select() in der step() Funktion nicht blockiert wird noch ein sehr kurzer $reactor->add_timeout() installiert (der selbst nichts macht).

Jetzt aber Gute Nacht :) Jörg
Raspberry 4 + HM-MOD-RPI-PCB (pivCCU) + RfxTrx433XL
70+ Homematic/HMIP, Diverse 433Mhz Sensoren und Schalter
Module: 52_I2C_ADS1x1x (offiziell), 50_Signalbot, 50_SPI_MAX31865

 

decade-submarginal