Nachrichten von FHEM zu Matrix Synapse senden

Begonnen von DecaTec, 03 Mai 2021, 12:42:21

Vorheriges Thema - Nächstes Thema

Torxgewinde

Hallo,
Das bekannte Problem, wenn der Longpoll noch aktiv ist und man dann eine Nachricht senden möchte, ist nun gelöst - man braucht also nicht zwei Devices einrichten.

Es wird das Attribut set01IExpr ein wenig ungewöhnlich genutzt um vor dem Senden ein wenig Perlcode auszuführen. So wird dann der longpoll-Aufruf vorzeitig beendet und das set01 kann seine Arbeit verrichten ohne extra warten zu müssen:
attr MatrixBot set01IExpr #cancel an active longpoll\
if ($hash->{BUSY}\
    && $hash->{HttpUtils}\
    && $hash->{HttpUtils}->{url} =~ m|^https://[^/]+/_matrix/client/v3/sync\?timeout=\d+&filter=| ) {\
    Log(3, "$name: longpoll active, cutting it off now");;\
    HttpUtils_Close($hash->{HttpUtils});;\
}\
\
#just return $val unteraltered\
$val

Warum das Probleme machte kann ich nur eingrenzen auf den Abschnitt aus der 98_HTTPMOD.pm:
    if ($hash->{BUSY}) {            # still waiting for reply to last request
        if ($now > $last + max(15, AttrVal($name, "timeout", 2) *2)) {
            Log3 $name, 5, "$name: HandleSendQueue - still waiting for reply, timeout is over twice - this should never happen. Stop waiting";
            $hash->{BUSY} = 0;      # waited long enough, clear busy flag and continue
        }
Obwohl das Timeout auf 65 Sekunden steht und auch .LASTSEND auf sinnvollen Werten steht, springt HTTPMOD in das Fehlerhandling, das einfach nur busy auf 0 setzt, ohne den ggf. noch aktiven longpoll darüber zu informieren. Als Reaktion darauf kann es passieren, dass die ReadCallback-Funktion dann zweimal aufgerufen wird, die Ergebnisse aber bei dem falschem Reading landen. Wie auch immer, so wie oben umschiffe ich das Problem.

Hier das ganze Device zum einfachen Einrichten:
defmod MatrixBot HTTPMOD none 0
attr MatrixBot userattr MatrixRoomID MatrixServer MatrixUser
attr MatrixBot MatrixRoomID !12345678901234:nope.chat
attr MatrixBot MatrixServer nope.chat
attr MatrixBot MatrixUser DeinUsername
attr MatrixBot bodyDecode utf-8
attr MatrixBot bodyEncode utf-8
attr MatrixBot comment "\
Create a room for FHEM.\
\
The room must not use encryption, a room that has encryption\
enabled, cannot be converted to a non-encrypted room anymore \
\
The room-id can be found in Element-Web at:\
Room Settings --> Advanced --> Internal room ID\
\
To store the password in FHEM in obfuscated way:\
set MatrixBot storeKeyValue MatrixPassword yourPassword123\
\
###\
To send a text:\
set MatrixBot sendText Bla Bla Bla\
\
\
###\
To longpoll for messages once:\
# 1. send special filter to Matrix:\
set MatrixBot sendFilter\
\
# 2. start one longPoll (waits up to 60 seconds\
#                        or until data is available)\
get MatrixBot longpoll\
\
#alternatively, to keep on longPolling (this also sets filter):\
set MatrixBot longpollCmd startTimer\
#to stop the timers:\
set MatrixBot longpollCmd stopTimer\
\
#############################################################\
https://spec.matrix.org/v1.14/client-server-api/#syncing\
"
attr MatrixBot get02AlwaysNum 0
attr MatrixBot get02HeaderAuthorization Authorization: Bearer $sid
attr MatrixBot get02Name longpoll
attr MatrixBot get02Regex \"next_batch\":\s*\"(?<next_batch>[^\"]+)\"(?:.*?\"timeline\":\s*{\s*\"events\":\s*(?<messages>\[.*?\])\s*)?
attr MatrixBot get02TextArg 0
attr MatrixBot get02URL https://[$name:MatrixServer]/_matrix/client/v3/sync?timeout=60000&filter=[$name:filter_id]%%next_batch_param%%
attr MatrixBot icon message_info
attr MatrixBot parseFunction1 handleAuthErrors
attr MatrixBot reAuthAlways 0
attr MatrixBot reAuthRegex M_UNKNOWN_TOKEN
attr MatrixBot replacement01Mode expression
attr MatrixBot replacement01Regex \[([^:\s\[\"\']+):([^\]\s]+)\]
attr MatrixBot replacement01Value my $device = $name if ($1 eq "\$name") // $1;;\
ReadingsVal($device, $2, undef) or AttrVal($device, $2, "???");;
attr MatrixBot replacement02Mode expression
attr MatrixBot replacement02Regex %%uuid%%
attr MatrixBot replacement02Value join("-", unpack("A8 A4 A4 A4 A12", unpack("H*", join("", map { chr(int rand 256) } 0..15))))
attr MatrixBot replacement03Mode key
attr MatrixBot replacement03Regex %%MatrixPassword%%
attr MatrixBot replacement03Value MatrixPassword
attr MatrixBot replacement04Mode expression
attr MatrixBot replacement04Regex %%next_batch_param%%
attr MatrixBot replacement04Value #is there a reading 'next_batch'?\
my $val = ReadingsVal($name, 'next_batch', '???');;\
\
#return the GET parameter 'sync=value' for /sync Endpoint\
return "&since=$val" if ($val ne '???');;\
\
#return neither since-key nor value for it:\
return "";;
attr MatrixBot set01Data {\
  "msgtype": "m.text",\
  "body": "$val"\
}
attr MatrixBot set01HeaderAuthorization Authorization: Bearer $sid
attr MatrixBot set01HeaderContent-Type application/json
attr MatrixBot set01IExpr #cancel an active longpoll\
if ($hash->{BUSY}\
    && $hash->{HttpUtils}\
    && $hash->{HttpUtils}->{url} =~ m|^https://[^/]+/_matrix/client/v3/sync\?timeout=\d+&filter=| ) {\
    Log(3, "$name: longpoll active, cutting it off now");;\
    HttpUtils_Close($hash->{HttpUtils});;\
}\
\
#just return $val unteraltered\
$val
attr MatrixBot set01Method POST
attr MatrixBot set01Name sendText
attr MatrixBot set01ParseResponse 1
attr MatrixBot set01Regex {\"event_id\":\"(.*)\"}
attr MatrixBot set01TextArg 1
attr MatrixBot set01URL https://[$name:MatrixServer]/_matrix/client/v3/rooms/[$name:MatrixRoomID]/send/m.room.message?txnId=%%uuid%%
attr MatrixBot set02Data {\
  "room": {\
    "rooms": ["[$name:MatrixRoomID]"],\
    "timeline": {\
      "limit": 10,\
      "types": ["m.room.message"]\
    },\
    "include_leave": false,\
    "include_join": false,\
    "include_account_data": false,\
    "include_state": false,\
    "state": {\
      "types": []\
    },\
    "ephemeral": {\
      "types": []\
    },\
    "account_data": {\
      "types": []\
    }\
  },\
  "event_fields": [\
    "content.body",\
    "sender",\
    "origin_server_ts"\
  ],\
  "event_format": "client",\
  "presence": {\
    "types": [],\
    "not_types": ["*"]\
  },\
  "account_data": {\
    "types": [],\
    "not_types": ["*"]\
  }\
}
attr MatrixBot set02HeaderAuthorization Authorization: Bearer $sid
attr MatrixBot set02HeaderContent-Type application/json
attr MatrixBot set02Method POST
attr MatrixBot set02Name sendFilter
attr MatrixBot set02NoArg 1
attr MatrixBot set02ParseResponse 1
attr MatrixBot set02Regex \"filter_id\":\s*\"(?<filter_id>\d+)\"
attr MatrixBot set02URL https://[$name:MatrixServer]/_matrix/client/v3/user/@[$name:MatrixUser]:[$name:MatrixServer]/filter
attr MatrixBot set03Local 1
attr MatrixBot set03Name longpollCmd
attr MatrixBot set03TextArg 1
attr MatrixBot showError 1
attr MatrixBot sid01Data {\
  "type": "m.login.password",\
  "identifier": {\
    "type": "m.id.user",\
    "user": "[$name:MatrixUser]"\
  },\
  "password": "%%MatrixPassword%%"\
}
attr MatrixBot sid01HeaderContent-Type application/json
attr MatrixBot sid01IdRegex "access_token"\s*:\s*"([^"]+)"
attr MatrixBot sid01URL https://[$name:MatrixServer]/_matrix/client/v3/login
attr MatrixBot timeout 65
attr MatrixBot userReadings longpollTimer:(next_batch|longpollCmd|LAST_ERROR|sendText):.* {\
  my $longpollCmd = ReadingsVal($name, 'longpollCmd', '???');;\
  my $delay = 1;;\
  my $timeout = AttrVal($name, 'timeout', 61) + $delay + 5;;\
  \
  # stop our timers:\
  if ($longpollCmd eq "stopTimer") {\
    fhem("cancel ${name}_longpollTimer quiet");;\
    fhem("cancel ${name}_longpollTimer2 quiet");;\
    return "stopped";;\
  }\
  \
  if ($longpollCmd ne "startTimer") {\
    return "no timer set, longpollCmd is not set to 'startTimer'";;\
  }\
  \
  #if startTimer cmd was given now, set filter as well:\
  if (ReadingsAge($name, 'longpollCmd', 0) <= 1) {\
    $delay = 5;; #delay to allow for sendFilter to be answered\
    #Log(1, "🪲 $name: >>". InternalVal($name, 'httpbody', '???') ."<<");;\
    fhem("sleep 0.1 quiet;; set $name sendFilter");;\
  }\
  \
  #we handle an error reported by http-utils:\
  if (ReadingsAge($name, 'LAST_ERROR', 0) <= 1) {\
    my $last_error = ReadingsVal($name, 'LAST_ERROR', '???');;\
    $delay = 10;; #delay to allow for error reasons to improve\
    #Log(1, "🪲 $name: Dealing with error: >>$last_error<<");;\
  }\
  \
  # for testing this: { $defs{MatrixBot}{sid} = 'bla' }\
  if (!defined &HTTPMOD::handleAuthErrors) {\
    *HTTPMOD::handleAuthErrors = sub {\
      my ($hash, $header, $body, $request) = @_;;\
      my $name = $hash->{NAME};;\
      my $status;;\
      \
      if ($header =~ m{^HTTP/\d\.\d\s+(\d+)}m) {\
        $status = $1;;\
      }\
      \
      Log3($name, 4, "$name: HTTP status code is $status");;\
      \
      if ( $status == 401 || $status == 403 || $status == 500 ) {\
        Log3($name, 3, "$name: auth-error or servererror ($status), calling doAuth()");;\
        HTTPMOD::DoAuth($hash);;\
      }\
    };;\
  }\
  \
  #set timers, one regular and one fallback:\
  fhem("sleep $delay ${name}_longpollTimer quiet;; get $name longpoll");;\
  fhem("sleep $timeout ${name}_longpollTimer2 quiet;; set $name longpollCmd startTimer");;\
  \
  return strftime("next longpoll at %H:%M:%S", localtime( time()+$delay ));;\
},\
messages_list:messages:.* {\
  my $this = ReadingsVal($name, $reading, '');;\
  my @timestampArray = split("\n", $this);;\
  my $messages_ref = decode_json(ReadingsVal($name, 'messages', ''));;\
  my $length = 20;;\
  \
  my %seen_messages = map { $_ => 1 } @timestampArray;;\
  \
  foreach my $msg (@$messages_ref) {\
    my $val = $msg->{content}{body};;\
    $val = Encode::decode('utf-8', $val) unless Encode::is_utf8($val);;\
    $val =~ s/\n/ /g;; #replace newlines with spaces\
    \
    my $sender = $msg->{sender};;\
    my $ts = strftime("%Y-%m-%d %H:%M:%S", localtime($msg->{origin_server_ts} / 1000));;\
    my $new_entry = "$ts: $sender: $val";;\
    \
    next if $seen_messages{$new_entry};;\
    \
    my $inserted = 0;;\
    for (my $i = 0;; $i < @timestampArray;; $i++) {\
      my ($existing_ts) = $timestampArray[$i] =~ /^([^:]+):/;;\
      if ($ts lt $existing_ts) {\
        splice(@timestampArray, $i, 0, $new_entry);;\
        $inserted = 1;;\
        last;;\
      }\
    }\
    push(@timestampArray, encode('utf-8', $new_entry)) unless $inserted;;\
    shift(@timestampArray) while @timestampArray > $length;;\
  }\
  \
  return join("\n", @timestampArray);;\
},\
process_messages:messages:.* {\
  my $val = ReadingsVal($name, 'messages_list', '');;\
  my $this = ReadingsVal($name, $reading, '');;\
  my $latest_ts = $this;;\
  \
  foreach my $line (split(/\n/, $val)) {\
    if ($line =~ /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}):\s*(.*)$/) {\
      my ($ts, $msg) = ($1, $2);;\
      \
      if ($ts gt $this) {\
        fhem("trigger $name msg: $line");;\
        $latest_ts = $ts if ($ts gt $latest_ts);;\
      }\
    }\
  }\
  return $latest_ts;;\
}
attr MatrixBot verbose 3
attr MatrixBot widgetOverride longpollCmd:uzsuSelectRadio,startTimer,stopTimer

Torxgewinde


riker1

#17
Hi
irgendwie bin ich zu blöd.
Matrix kenne ich auch wenig, mir scheint als ob ich laufend neue Access Token erhalte.

Wo muss ich denn im Device den Token angeben, ?

muss hier attr MatrixTRBot sid01IdRegex "access_token"\s*:\s*"([^"]+)"der token rein?

laufend die meldung falscher Token
der user muss doch mit @user:server eingegeben werden? richtig?

muss der Server als matrix.tchncs.de     oder nur   tchncs.de  eingegeben werden?

Danke für die Klarstellung
FHEM    5.26.1 Ubuntu 18, FHEM    5.26.1 RPI 3 , Actoren: IT ,Tasmota, ESPEasy,
MAX CUBE, MAX HT, MAX WT, Selbstbau nanoCULs, FS 20,Tasmota, Homematic, FTK, SW. DIM, Smoke,KODI,Squeezebox

Torxgewinde

Hi,
Den Token musst du garnicht selbst erstellen, das macht das Device für dich.

Nutzername und Server werden getrennt angegeben:
- attr MatrixUser FHEM_Nutzername_WieBeimServerOhneDoppelpunktUndOhneAt
- attr MatrixServer nope.chat (oder wo auch immer dein Matrix-Synapse-Server läuft)

Bezüglich des servers (ob mit Matrix. oder ohne) musste bitte einfach probieren. Ich meine es muss mit, da es auf eine andere IP verweist:

;; ANSWER SECTION:
matrix.tchncs.de. 110 IN CNAME h2.tchncs.de.
h2.tchncs.de. 423 IN A 135.181.232.169

;; ANSWER SECTION:
tchncs.de. 600 IN A 89.58.62.32

riker1

Zitat von: Torxgewinde am 23 Juli 2025, 11:22:47Hi,
Den Token musst du garnicht selbst erstellen, das macht das Device für dich.

Nutzername und Server werden getrennt angegeben:
- attr MatrixUser FHEM_Nutzername_WieBeimServerOhneDoppelpunktUndOhneAt
- attr MatrixServer nope.chat (oder wo auch immer dein Matrix-Synapse-Server läuft)

Bezüglich des servers (ob mit Matrix. oder ohne) musste bitte einfach probieren. Ich meine es muss mit, da es auf eine andere IP verweist:

;; ANSWER SECTION:
matrix.tchncs.de. 110 IN CNAME h2.tchncs.de.
h2.tchncs.de. 423 IN A 135.181.232.169

;; ANSWER SECTION:
tchncs.de. 600 IN A 89.58.62.32

alles klar danke, aber irgendwie schaffe ich es nicht.
habe mal parallel die andere sendefunktoin mit myutils eingebunden, da klappt das senden.

Habe hier aber noch andere Fehler, eventuell ist das das Problem:
als Server habe ich : https://matrix.tchncs.de
errors:
2025.07.24 10:35:50.386 5: MatrixTRBot: calling parseFunction1 as handleAuthErrors via attr for HTTP Response to set02
2025.07.24 10:35:50.386 1: PERL ERROR: Undefined subroutine &HTTPMOD::handleAuthErrors called at ./FHEM/98_HTTPMOD.pm line 1469.

modulversion: 98_HTTPMOD.pm:0.291590/2024-09-23  ein update ergab alles ok


Wo kann ich noch schauen? was mache ich falsch?
Danke

log 2025.07.24 10:35:37.402 4: MatrixTRBot: Read callback: request type was set02 retry 0, header: HTTP/1.1 401 Unauthorized Server: openresty Date: Thu, 24 Jul 2025 08:35:33 GMT Content-Type: application/json Connection: close Content-Encoding: gzip Cache-Control: no-cache, no-store, must-revalidate Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: X-Requested-With, Content-Type, Authorization, Date Access-Control-Expose-Headers: Synapse-Trace-Id, Server Strict-Transport-Security: max-age=31536000; includeSubdomains; preload, body length 88
2025.07.24 10:35:37.403 5: MatrixTRBot: Read callback: body {"errcode":"M_UNKNOWN_TOKEN","error":"Invalid access token passed.","soft_logout":false}
2025.07.24 10:35:37.403 4: MatrixTRBot: BodyDecode is decoding the response body as utf-8 but charset header is not found
2025.07.24 10:35:37.403 5: MatrixTRBot: GetCookies is looking for Cookies
2025.07.24 10:35:37.404 5: MatrixTRBot: ExtractSid called, context set, num 02
2025.07.24 10:35:37.404 4: MatrixTRBot: checking for redirects, code=401, ignore=0
2025.07.24 10:35:37.404 4: MatrixTRBot: no redirects to handle
2025.07.24 10:35:37.404 5: MatrixTRBot: Read callback sets LAST_REQUEST to set02
2025.07.24 10:35:37.405 5: MatrixTRBot: CheckAuth is checking buffer with ReAuthRegex (?^:M_UNKNOWN_TOKEN)
2025.07.24 10:35:37.405 4: MatrixTRBot: CheckAuth decided new authentication required
2025.07.24 10:35:37.405 5: MatrixTRBot: AddToQueue prepends type set02 to URL https://[$name:MatrixServer]/_matrix/client/v3/user/@[$name:MatrixUser]:[$name:MatrixServer]/filter, data { "room": { "rooms": ["[$name:MatrixRoomID]"], "timeline": { "limit": 10, "types": ["m.room.message"] }, "include_leave": false, "include_join": false, "include_account_data": false, "include_state": false, "state": { "types": [] }, "ephemeral": { "types": [] }, "account_data": { "types": [] } }, "event_fields": [ "content.body", "sender", "origin_server_ts" ], "event_format": "client", "presence": { "types": [], "not_types": ["*"] }, "account_data": { "types": [], "not_types": ["*"] } }, header Authorization: Bearer $sid application/json, retry 1, initial queue len: 0
2025.07.24 10:35:37.405 4: MatrixTRBot: CheckAuth prepended request set02 again before auth, retryCount 0 ...
2025.07.24 10:35:37.406 4: MatrixTRBot: DoAuth called with Steps: 01
2025.07.24 10:35:37.406 5: MatrixTRBot: AddToQueue prepends type auth01 to URL https://[$name:MatrixServer]/_matrix/client/v3/login, data { "type": "m.login.password", "identifier": { "type": "m.id.user", "user": "[$name:MatrixUser]" }, "password": "%%MatrixPassword%%" }, header application/json, retry 0, initial queue len: 1
2025.07.24 10:35:37.407 5: MatrixTRBot: HandleSendQueue called from DoAuth, qlen = 2
2025.07.24 10:35:37.407 5: MatrixTRBot: Replace called for type auth01, regex (?^:\[([^:\s\[\"\']+):([^\]\s]+)\]), mode expression, value my $device = $name if ($1 eq "\$name") // $1; ReadingsVal($device, $2, undef) or AttrVal($device, $2, "???"); input: application/json
2025.07.24 10:35:37.407 5: MatrixTRBot: Replace called for type auth01, regex (?^:%%uuid%%), mode expression, value join("-", unpack("A8 A4 A4 A4 A12", unpack("H*", join("", map { chr(int rand 256) } 0..15)))) input: application/json
2025.07.24 10:35:37.407 5: MatrixTRBot: Replace called for type auth01, regex (?^:%%MatrixPassword%%), mode key, value MatrixPassword input: application/json
2025.07.24 10:35:37.408 5: MatrixTRBot: ReadKeyValue tries to read value for MatrixPassword from file
2025.07.24 10:35:37.409 5: MatrixTRBot: Replace called for type auth01, regex (?^:%%next_batch_param%%), mode expression, value #is there a reading 'next_batch'? my $val = ReadingsVal($name, 'next_batch', '???'); #return the GET parameter 'sync=value' for /sync Endpoint return "&since=$val" if ($val ne '???'); #return neither since-key nor value for it: return ""; input: application/json
2025.07.24 10:35:37.409 5: MatrixTRBot: Replace called for type auth01, regex (?^:\[([^:\s\[\"\']+):([^\]\s]+)\]), mode expression, value my $device = $name if ($1 eq "\$name") // $1; ReadingsVal($device, $2, undef) or AttrVal($device, $2, "???"); input: { "type": "m.login.password", "identifier": { "type": "m.id.user", "user": "[$name:MatrixUser]" }, "password": "%%MatrixPassword%%" }
2025.07.24 10:35:37.409 5: MatrixTRBot: Replace: match for type auth01, regex (?^:\[([^:\s\[\"\']+):([^\]\s]+)\]), mode expression, value package main; my $device = $name if ($1 eq "\$name") // $1; ReadingsVal($device, $2, undef) or AttrVal($device, $2, "???");, input: { "type": "m.login.password", "identifier": { "type": "m.id.user", "user": "[$name:MatrixUser]" }, "password": "%%MatrixPassword%%" }, result is { "type": "m.login.password", "identifier": { "type": "m.id.user", "user": "fhemtrbotmatrix" }, "password": "%%MatrixPassword%%" }
2025.07.24 10:35:37.410 5: MatrixTRBot: Replace called for type auth01, regex (?^:%%uuid%%), mode expression, value join("-", unpack("A8 A4 A4 A4 A12", unpack("H*", join("", map { chr(int rand 256) } 0..15)))) input: { "type": "m.login.password", "identifier": { "type": "m.id.user", "user": "fhemtrbotmatrix" }, "password": "%%MatrixPassword%%" }
2025.07.24 10:35:37.410 5: MatrixTRBot: Replace called for type auth01, regex (?^:%%MatrixPassword%%), mode key, value MatrixPassword input: { "type": "m.login.password", "identifier": { "type": "m.id.user", "user": "fhemtrbotmatrix" }, "password": "%%MatrixPassword%%" }
2025.07.24 10:35:37.410 5: MatrixTRBot: ReadKeyValue tries to read value for MatrixPassword from file
2025.07.24 10:35:37.411 5: MatrixTRBot: Replace: key MatrixPassword value is xxxxx
2025.07.24 10:35:37.411 5: MatrixTRBot: Replace: match for type auth01, regex (?^:%%MatrixPassword%%), mode key, value MatrixPassword, input: { "type": "m.login.password", "identifier": { "type": "m.id.user", "user": "[$name:MatrixUser]" }, "password": "%%MatrixPassword%%" }, result is { "type": "m.login.password", "identifier": { "type": "m.id.user", "user": "fhemtrbotmatrix" }, "password": "myPassWDMatrix" }
2025.07.24 10:35:37.411 5: MatrixTRBot: Replace called for type auth01, regex (?^:%%next_batch_param%%), mode expression, value #is there a reading 'next_batch'? my $val = ReadingsVal($name, 'next_batch', '???'); #return the GET parameter 'sync=value' for /sync Endpoint return "&since=$val" if ($val ne '???'); #return neither since-key nor value for it: return ""; input: { "type": "m.login.password", "identifier": { "type": "m.id.user", "user": "fhemtrbotmatrix" }, "password": "myPassWDMatrix" }
2025.07.24 10:35:37.411 5: MatrixTRBot: Replace called for type auth01, regex (?^:\[([^:\s\[\"\']+):([^\]\s]+)\]), mode expression, value my $device = $name if ($1 eq "\$name") // $1; ReadingsVal($device, $2, undef) or AttrVal($device, $2, "???"); input: https://[$name:MatrixServer]/_matrix/client/v3/login
2025.07.24 10:35:37.412 5: MatrixTRBot: Replace: match for type auth01, regex (?^:\[([^:\s\[\"\']+):([^\]\s]+)\]), mode expression, value package main; my $device = $name if ($1 eq "\$name") // $1; ReadingsVal($device, $2, undef) or AttrVal($device, $2, "???");, input: https://[$name:MatrixServer]/_matrix/client/v3/login, result is https://matrix.tchncs.de/_matrix/client/v3/login
2025.07.24 10:35:37.412 5: MatrixTRBot: Replace called for type auth01, regex (?^:%%uuid%%), mode expression, value join("-", unpack("A8 A4 A4 A4 A12", unpack("H*", join("", map { chr(int rand 256) } 0..15)))) input: https://matrix.tchncs.de/_matrix/client/v3/login
2025.07.24 10:35:37.412 5: MatrixTRBot: Replace called for type auth01, regex (?^:%%MatrixPassword%%), mode key, value MatrixPassword input: https://matrix.tchncs.de/_matrix/client/v3/login
2025.07.24 10:35:37.412 5: MatrixTRBot: ReadKeyValue tries to read value for MatrixPassword from file
2025.07.24 10:35:37.413 5: MatrixTRBot: Replace called for type auth01, regex (?^:%%next_batch_param%%), mode expression, value #is there a reading 'next_batch'? my $val = ReadingsVal($name, 'next_batch', '???'); #return the GET parameter 'sync=value' for /sync Endpoint return "&since=$val" if ($val ne '???'); #return neither since-key nor value for it: return ""; input: https://matrix.tchncs.de/_matrix/client/v3/login
2025.07.24 10:35:37.413 5: MatrixTRBot: no separator for multiple values (Context auth01, 01)
2025.07.24 10:35:37.413 4: MatrixTRBot: HandleSendQueue sends auth01 with timeout 65 to https://matrix.tchncs.de/_matrix/client/v3/login, data: { "type": "m.login.password", "identifier": { "type": "m.id.user", "user": "fhemtrbotmatrix" }, "password": "myPassWDMatrix" }, header: application/json
2025.07.24 10:35:37.415 5: MatrixTRBot: StartQueueTimer called from HandleSendQueue sets internal timer to process queue in 1.000 seconds

2025.07.24 10:35:50.383 4: MatrixTRBot: Read callback: request type was set02 retry 1, header: HTTP/1.1 401 Unauthorized Server: openresty Date: Thu, 24 Jul 2025 08:35:48 GMT Content-Type: application/json Connection: close Content-Encoding: gzip Cache-Control: no-cache, no-store, must-revalidate Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: X-Requested-With, Content-Type, Authorization, Date Access-Control-Expose-Headers: Synapse-Trace-Id, Server Strict-Transport-Security: max-age=31536000; includeSubdomains; preload, body length 88
2025.07.24 10:35:50.383 5: MatrixTRBot: Read callback: body {"errcode":"M_UNKNOWN_TOKEN","error":"Invalid access token passed.","soft_logout":false}
2025.07.24 10:35:50.383 4: MatrixTRBot: BodyDecode is decoding the response body as utf-8 but charset header is not found
2025.07.24 10:35:50.383 5: MatrixTRBot: GetCookies is looking for Cookies
2025.07.24 10:35:50.384 5: MatrixTRBot: ExtractSid called, context set, num 02
2025.07.24 10:35:50.384 4: MatrixTRBot: checking for redirects, code=401, ignore=0
2025.07.24 10:35:50.384 4: MatrixTRBot: no redirects to handle
2025.07.24 10:35:50.384 5: MatrixTRBot: Read callback sets LAST_REQUEST to set02
2025.07.24 10:35:50.384 5: MatrixTRBot: CheckAuth is checking buffer with ReAuthRegex (?^:M_UNKNOWN_TOKEN)
2025.07.24 10:35:50.385 4: MatrixTRBot: CheckAuth decided new authentication required
2025.07.24 10:35:50.385 4: MatrixTRBot: Authentication still required but no retries left - did last authentication fail?
2025.07.24 10:35:50.385 5: MatrixTRBot: ExtractReading sendFilter with regex /(?^:\"filter_id\":\s*\"(?<filter_id>\d+)\")/...
2025.07.24 10:35:50.385 5: MatrixTRBot: ExtractReading sendFilter did not match
2025.07.24 10:35:50.385 4: MatrixTRBot: Read response to set02 didn't match any Reading
2025.07.24 10:35:50.386 5: MatrixTRBot: calling parseFunction1 as handleAuthErrors via attr for HTTP Response to set02
2025.07.24 10:35:50.386 1: PERL ERROR: Undefined subroutine &HTTPMOD::handleAuthErrors called at ./FHEM/98_HTTPMOD.pm line 1469.
2025.07.24 10:35:50.386 1: stacktrace:
2025.07.24 10:35:50.386 1: main::__ANON__ called by ./FHEM/98_HTTPMOD.pm (1469)
2025.07.24 10:35:50.386 1: (eval) called by ./FHEM/98_HTTPMOD.pm (1469)
2025.07.24 10:35:50.386 1: HTTPMOD::HandleParseFunctions called by ./FHEM/98_HTTPMOD.pm (2529)
2025.07.24 10:35:50.386 1: HTTPMOD::ReadCallback called by FHEM/HttpUtils.pm (756)
2025.07.24 10:35:50.387 1: main::__ANON__ called by fhem.pl (786)
2025.07.24 10:35:50.387 3: MatrixTRBot: error calling handleAuthErrors: Undefined subroutine &HTTPMOD::handleAuthErrors called at ./FHEM/98_HTTPMOD.pm line 1469.
2025.07.24 10:35:50.387 5: MatrixTRBot: HandleSendQueue called from ReadCallback, qlen = 0
2025.07.24 10:35:50.387 5: MatrixTRBot: HandleSendQueue found no usable entry in queue



FHEM    5.26.1 Ubuntu 18, FHEM    5.26.1 RPI 3 , Actoren: IT ,Tasmota, ESPEasy,
MAX CUBE, MAX HT, MAX WT, Selbstbau nanoCULs, FS 20,Tasmota, Homematic, FTK, SW. DIM, Smoke,KODI,Squeezebox

Torxgewinde

Danke für das ausführliche Log, ich jubel HTTPMOD eine eigene Parsefunction unter, aber das scheint nicht in der Reihenfolge zu passieren, wie ich es beabsichtigte.

Kannst du testweise bitte in myUtils folgende Funktion packen:
sub handleAuthErrorsAusMyUtils {
    my ($hash, $header, $body, $request) = @_;
    my $name = $hash->{NAME};
    my $status;

    if ($header =~ m{^HTTP/\d\.\d\s+(\d+)}m) {
        $status = $1;
    }

    Log3($name, 4, "$name: HTTP status code is $status");

    if ($status == 401 || $status == 403 || $status == 500) {
        Log3($name, 3, "$name: auth-error or servererror ($status), calling doAuth()");
        HTTPMOD::DoAuth($hash);
    }
}

Und im HTTPMOD device dann:
attr MatrixBot parseFunction1 handleAuthErrorsAusMyUtils
Wenn das so nichts wird, dann muss ich mal auf einem "frischem" FHEM debuggen.