MQTT2 userReadings wird mehrfach durchlaufen

Begonnen von ch.eick, 31 Januar 2026, 17:41:11

Vorheriges Thema - Nächstes Thema

ch.eick

Hallo zusammen,
solch einen Effekt hatte ich bisher noch nie.
Was ich nicht verstehe ist, dass das userReadings bei nur einer empfangenen Nachricht mehrfach durchlaufen wird.
Bei anderen MQTT2 Devices konnte ich sowas nicht feststellen.
Bei meinem ersten Test, bei dem nur ich alleine in der Gruppe war lief noch alles wie gewünscht. Als der zweite Benutzer nun in die Gruppe kam und ich dann im userReadings nach der Uuid unterscheiden musste, da trat dann diese Mehrfach Reaktion auf.

EDIT: Ich denke ein Problem wird sein, dass die readings, die ich verarbeite nicht alle zur gleichen Zeit geschrieben werden und auch vom zweiten MQTT Topic erneut geschrieben werden.
  Um die readings aus einer Nachricht z.B. in in_date_* schreiben zu können müsste ich innerhalb eines redingList Eintrages alle readings analysieren und schreiben.

  Wenn dieses Topic kommt, stehen im json alle zusammengehörigen Informationen drin. Wie müsste ich das denn als Perl schreiben, damit alle readings genau aus diesem json gelesen werden.
  Die parms_envelope Pfade sind bei dataMessage und syncMessage gleich und somit nicht eindeutig.

  $DEVICETOPIC:signal/in:.* { {in_message_data=>json2nameValue($EVENT)->{params_envelope_dataMessage_message} } }


readingList
$DEVICETOPIC:signal/in:.* { {in_message_sent=>json2nameValue($EVENT)->{params_envelope_syncMessage_sentMessage_message} } }
$DEVICETOPIC:signal/in:.* { {in_message_data=>json2nameValue($EVENT)->{params_envelope_dataMessage_message} } }
$DEVICETOPIC:signal/in:.* { {in_groupName=>json2nameValue($EVENT)->{params_envelope_syncMessage_sentMessage_groupInfo_groupName} } }
$DEVICETOPIC:signal/in:.* { {in_source=>json2nameValue($EVENT)->{params_envelope_source} } }
$DEVICETOPIC:signal/in:.* { {in_sourceNumber=>json2nameValue($EVENT)->{params_envelope_sourceNumber} } }
$DEVICETOPIC:signal/in:.* { {in_sourceUuid=>json2nameValue($EVENT)->{params_envelope_sourceUuid} } }
$DEVICETOPIC:signal/in:.* { {in_sourceName=>json2nameValue($EVENT)->{params_envelope_sourceName} } }
$DEVICETOPIC:signal/in:.* { {in_account=>json2nameValue($EVENT)->{params_account} } }

Der MQTT2_FHEM_Server empfängt auch nur eine Nachricht mit dem gewünschten Inhalt.
Warum jedes mal vom user2 noch eine delivery Nachricht hinterher kommt verstehe ich ebenfalls noch nicht.
18:11:46.102 signal_receiver signal/in {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source < persönliche Daten user1> "}}
18:11:46.134 signal_receiver signal/in/method/receive/source_number/%2B49xxxxxx
18:11:46.899 signal_receiver signal/in {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source < persönliche Daten user2 delivery Information> "}}
18:11:46.930 signal_receiver signal/in/method/receive/delivered/true

Event log
2026-01-31 18:00:56.368 MQTT2_DEVICE signal_receiver in_source: +49
2026-01-31 18:00:56.368 MQTT2_DEVICE signal_receiver in_message_sent: 3
2026-01-31 18:00:56.368 MQTT2_DEVICE signal_receiver in_sourceUuid: 925814d3-cxxx8bdd
2026-01-31 18:00:56.368 MQTT2_DEVICE signal_receiver in_sourceNumber: +49
2026-01-31 18:00:56.368 MQTT2_DEVICE signal_receiver in_sourceName: user1

2026-01-31 18:00:57.225 MQTT2_DEVICE signal_receiver in_source: 984fad9d-3yyy239
2026-01-31 18:00:57.225 MQTT2_DEVICE signal_receiver in_sourceUuid: 984fad9d-3yyy239
2026-01-31 18:00:57.225 MQTT2_DEVICE signal_receiver in_sourceName: user2

FHEM Log
2026.01.31 18:00:56.349 3: signal_receiver      ur_02 : in_sourceUuid  : 984fad9d-3yyy239
2026.01.31 18:00:56.349 3: signal_receiver      ur_02 : in_message_sent: 3
2026.01.31 18:00:56.352 3: signal_receiver      ur_02 : in_sourceUuid  : 984fad9d-3yyy239
2026.01.31 18:00:56.352 3: signal_receiver      ur_02 : in_message_sent: 3
2026.01.31 18:00:56.355 3: signal_receiver      ur_02 : in_sourceUuid  : 925814d3-cxxx8bd
2026.01.31 18:00:56.355 3: signal_receiver      ur_02 : in_message_sent: 3
2026.01.31 18:00:56.356 3: signal_receiver      ur_02 : in_command      : null
2026.01.31 18:00:56.359 3: signal_receiver      ur_02 : in_sourceUuid  : 925814d3-cxxx8bd
2026.01.31 18:00:56.359 3: signal_receiver      ur_02 : in_message_sent: 3
2026.01.31 18:00:56.359 3: signal_receiver      ur_02 : in_command      : null
2026.01.31 18:00:56.362 3: signal_receiver      ur_02 : in_sourceUuid  : 925814d3-cxxx8bd
2026.01.31 18:00:56.362 3: signal_receiver      ur_02 : in_message_sent: 3
2026.01.31 18:00:56.362 3: signal_receiver      ur_02 : in_command      : null
2026.01.31 18:00:56.365 3: signal_receiver      ur_02 : in_sourceUuid  : 925814d3-cxxx8bd
2026.01.31 18:00:56.365 3: signal_receiver      ur_02 : in_message_sent: 3
2026.01.31 18:00:56.365 3: signal_receiver      ur_02 : in_command      : null

Attribute
event-on-change-reading in_message.*
event-on-update-reading in_analyse,in_source.*

userreading
in_analyse_mapping_sent:in_message_sent.* {
  my $in_source = ReadingsVal("$NAME","in_sourceUuid","null");
  Log3($name,3,sprintf("%-20s ur_02 : ", $name)."in_sourceUuid  : $in_source");
  my $in_analyse = lc(ReadingsVal("$NAME","in_message_sent","null"));
  Log3($name,3,sprintf("%-20s ur_02 : ", $name)."in_message_sent: $in_analyse ");
  if (   $in_source eq "925814d3-c417-4848-bfbf-aaf306b978bd" ) {
    my $in_command = "null";
    if ( $in_analyse ne "null") {
      my %h=eval "(".(AttrVal("$NAME","in_commands","n/a")).")";
      $in_command = $h{$in_analyse} if defined $h{$in_analyse};
#      fhem("$in_command");
     Log3($name,3,sprintf("%-20s ur_02 : ", $name)."in_command     : $in_command");
     return $in_command;
    }
  }
  return "null";
}

VG  Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

rudolfkoenig

Das oben gezeigt readingList ist ineffizient, unter anderem weil das JSON parsen mehrfach durchgelaufen wird.
Ich empfehle stattdessen sowas:
$DEVICETOPIC:signal/in:.* {
    my $r = json2nameValue($EVENT);
    return { in_message_sent => $r->{params_envelope_syncMessage_sentMessage_message},
            in_message_data => $r->{params_envelope_dataMessage_message},
            in_groupName    => $r->{params_envelope_syncMessage_sentMessage_groupInfo_groupName},
            ...
          } }
Alternativ setzt man das jsonMap Attribut, was genau fuer dieses Problem implementiert wurde.

Um das Problem mit userReading zu untersuchen haette ich gerne eine komplette Nachricht.
Die Werte gerne anonymisiert, aber mit allen Schluesseln.

ch.eick

#2
Okay, das Trennen war schon mal eine gute Idee.
Mit diesen Definitionen ist nun auch im Log wieder Ruhe und es wird nur das richtige json genommen.

Payload
18:20:13.202 signal_receiver signal/in  
{"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"+49","sourceNumber":"+49","sourceUuid":"925814xxx8bd","sourceName":"user1","sourceDevice":1,"timestamp":1769880013437,"serverReceivedTimestamp":1769880013113,"serverDeliveredTimestamp":1769880013115,"syncMessage":{"sentMessage":{"destination":null,"destinationNumber":null,"destinationUuid":null,"timestamp":1769880013437,"message":"2","expiresInSeconds":3600,"viewOnce":false,"groupInfo":{"groupId":"ik32NK0yeJc=","groupName":"FHEM cli","revision":5,"type":"DELIVER"}}}},"account":"+49"}}


18:20:15.202 signal_receiver signal/in
{"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"984fadyyyyy35e76239","sourceNumber":null,"sourceUuid":"984fad9yyy5e76239","sourceName":"user2","sourceDevice":1,"timestamp":1769873304823,"serverReceivedTimestamp":1769873305096,"serverDeliveredTimestamp":1769873305097,"dataMessage":{"timestamp":1769873304823,"message":"Test","expiresInSeconds":30,"viewOnce":false,"groupInfo":{"groupId":"ik32NK0y9+ereJc=","groupName":"FHEM cli","revision":4,"type":"DELIVER"}}},"account":"+49"}}

redingList
  Das wird leider nur einzeilig angenommen, gibt es da noch einen Trick?
  Wichtig ist besonders das "my $ret = $j->{params_envelope_syncMessage_sentMessage_message}; return if(!$ret);", da ansonsten die Payload auch für das andere json verwendet wird.
$DEVICETOPIC:signal/in:.* {my $j = json2nameValue($EVENT);my $ret = $j->{params_envelope_syncMessage_sentMessage_message}; return if(!$ret) ;return {in_sync_message_sent => $j->{params_envelope_syncMessage_sentMessage_message},in_sync_source => $j->{params_envelope_source},in_sync_sourceUuid => $j->{params_envelope_sourceUuid},in_sync_sourceNumber => $j->{params_envelope_sourceNumber},in_sync_sourceName => $j->{params_envelope_sourceName}};}

userReadings
in_sync_analyse_mapping_sent:in_sync_message_sent.* {
  my $in_source = ReadingsVal("$NAME","in_sync_sourceUuid","null");
  Log3($name,3,sprintf("%-20s ur_02 : ", $name)."in_sync_sourceUuid   : $in_source");
  my $in_analyse = lc(ReadingsVal("$NAME","in_sync_message_sent","null"));
  Log3($name,3,sprintf("%-20s ur_02 : ", $name)."in_sync_message_sent : $in_analyse ");
  if (   $in_source eq "925814dxxxxxxxxxf306b978bd" ) {
    my $in_command = "null";
    if ( $in_analyse ne "null") {
      my %h=eval "(".(AttrVal("$NAME","in_commands","n/a")).")";
      $in_command = $h{$in_analyse} if defined $h{$in_analyse};
      if ($in_command ne "null") {
#        fhem("$in_command");
          Log3($name,3,sprintf("%-20s ur_02 : ", $name)."in_sync_command      : $in_command");
      } else {
          Log3($name,3,sprintf("%-20s ur_02 : ", $name)."in_sync_command      : Not found");
      }
      return $in_command;
    }
  }
  return "null";
}
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

rudolfkoenig

ZitatOkay, das Trennen war schon mal eine gute Idee.
Ich wuesste gerne, worauf diese Bemerkung sich bezieht.

ZitatDas wird leider nur einzeilig angenommen, gibt es da noch einen Trick?
Sogar mehrere: als Funktion in 99_myUtils.pm auslagern, oder, noch besser: jsonMap verwenden.

Beim Absetzen der ersten Nachricht wird userReading einmal aufgerufen:
2026.02.01 11:59:09.803 3: m2d                  ur_02 : in_sync_sourceUuid  : 925814xxx8bd
2026.02.01 11:59:09.803 3: m2d                  ur_02 : in_sync_message_sent : 2
beim Aufruf der zweiten Nachricht nicht. Letzteres ist dem ReadingList zu verdanken.

Ich habe die o.g. event-on-* Attribute weggelassen: die passen nicht zum zweiten Beitrag (und filtern damit alles weg), und ich verstehe auch nicht, wozu sie gut sein sollen.