From db19349628c72f7849323c7ac73ed7e8c1abbfac Mon Sep 17 00:00:00 2001 From: Manfred Date: Sat, 5 Nov 2022 12:30:17 +0100 Subject: [PATCH] changes completed --- FHEM/98_Matrix.pm | 126 +++++--- lib/FHEM/Devices/Matrix/Matrix.pm | 483 ++++++++++++++++++++++++++++++ 2 files changed, 565 insertions(+), 44 deletions(-) create mode 100644 lib/FHEM/Devices/Matrix/Matrix.pm diff --git a/FHEM/98_Matrix.pm b/FHEM/98_Matrix.pm index 71306ab..54e0bd8 100644 --- a/FHEM/98_Matrix.pm +++ b/FHEM/98_Matrix.pm @@ -23,64 +23,68 @@ # Usage: # ########################################################################## -# $Id: 98_Matrix.pm 28158 2022-11-02 19:56:00Z Man-fred $ +# $Id: 98_Matrix.pm 11656 2022-11-05 12:26:00Z Man-fred $ -package FHEM::Matrix; +package FHEM::Devices::Matrix; use strict; use warnings; use HttpUtils; use FHEM::Meta; -use GPUtils qw(GP_Export); +use GPUtils qw(GP_Export GP_Import); -require FHEM::Device::Matrix; +use JSON; +use vars qw(%data); +use FHEM::Core::Authentication::Passwords qw(:ALL); +#use FHEM::Core::Authentication::Passwords qw(&setStorePassword); +require FHEM::Devices::Matrix::Matrix; #-- Run before package compilation BEGIN { #-- Export to main context with different name - GP_Export( - qw( - Initialize - ) - ); + GP_Export(qw( + Initialize + )); + GP_Import(qw( + readingFnAttributes + )); } -sub Matrix_Initialize { +sub Initialize { my ($hash) = @_; - $hash->{DefFn} = \&FHEM::Device::Matrix::Define; - $hash->{UndefFn} = \&FHEM::Device::Matrix::Undef; - $hash->{SetFn} = \&FHEM::Device::Matrix::Set; - $hash->{GetFn} = \&FHEM::Device::Matrix::Get; - $hash->{AttrFn} = \&FHEM::Device::Matrix::Attr; - $hash->{ReadFn} = \&FHEM::Device::Matrix::Read; - $hash->{RenameFn} = \&FHEM::Device::Matrix::Rename; - $hash->{NotifyFn} = \&FHEM::Device::Matrix::Notify; - - $hash->{AttrList} = "MatrixRoom MatrixSender MatrixQuestion_0 MatrixQuestion_1 MatrixMessage " . $::readingFnAttributes; + $hash->{DefFn} = \&FHEM::Devices::Matrix::Define; + $hash->{UndefFn} = \&FHEM::Devices::Matrix::Undef; + $hash->{SetFn} = \&FHEM::Devices::Matrix::Set; + $hash->{GetFn} = \&FHEM::Devices::Matrix::Get; + $hash->{AttrFn} = \&FHEM::Devices::Matrix::Attr; + $hash->{ReadFn} = \&FHEM::Devices::Matrix::Read; + $hash->{RenameFn} = \&FHEM::Devices::Matrix::Rename; + $hash->{NotifyFn} = \&FHEM::Devices::Matrix::Notify; + $hash->{AttrList} = "MatrixRoom MatrixSender MatrixMessage MatrixQuestion_0 MatrixQuestion_1 " . $readingFnAttributes; $hash->{parseParams} = 1; - return FHEM::Meta::InitMod( __FILE__, $hash ); } + 1; =pod =item summary Provides a Matrix-Chatbot. =item summary_DE Stellt einen Matrix-Chatbot bereit. =begin html - +

Matrix

=end html =begin html_DE - +

Matrix

=end html_DE =cut diff --git a/lib/FHEM/Devices/Matrix/Matrix.pm b/lib/FHEM/Devices/Matrix/Matrix.pm new file mode 100644 index 0000000..35aa31f --- /dev/null +++ b/lib/FHEM/Devices/Matrix/Matrix.pm @@ -0,0 +1,483 @@ +########################################################################## +# Usage: +# +########################################################################## +# $Id: Matrix.pm 20020 2022-11-05 12:26:00Z Man-fred $ + +package FHEM::Devices::Matrix; +use strict; +use warnings; +use HttpUtils; +use JSON; +#use GPUtils qw(GP_Import); +#use vars qw(%data); +use FHEM::Core::Authentication::Passwords qw(:ALL); + +# InternalTimer +# strftime +# RemoveInternalTimer +# readingFnAttributes +# notifyRegexpChanged +# HttpUtils_BlockingGet + +BEGIN { + + GP_Import(qw( + readingsBeginUpdate + readingsBulkUpdate + readingsEndUpdate + readingsSingleUpdate + Log3 + defs + init_done + IsDisabled + deviceEvents + AttrVal + ReadingsVal + HttpUtils_NonblockingGet + data + gettimeofday + )) +}; + +my $Module_Version = '0.0.7'; + +sub Define { + my ($hash, $param) = @_; + # my @param = split('[ \t]+', $def); + my $name = $param->[0]; #$param[0]; + + Log3($name, 1, "$name: Define: $param->[2] ".int(@$param)); + + if(int(@$param) < 1) { + return "too few parameters: define Matrix "; + } + $hash->{name} = $param->[0]; + $hash->{server} = $param->[2]; + $hash->{user} = $param->[3]; + $hash->{password} = $param->[4]; + $hash->{helper}->{passwdobj} = FHEM::Core::Authentication::Passwords->new($hash->{TYPE}); + + $hash->{NOTIFYDEV} = "global"; + Startproc($hash) if($init_done); + return ; +} + +sub Undef { + my ($hash, $arg) = @_; + my $name = $hash->{NAME}; + # undef $data + $data{MATRIX}{"$name"} = undef; + $hash->{helper}->{passwdobj}->setDeletePassword($name); + return ; +} + +sub Startproc { + my ($hash) = @_; + my $name = $hash->{NAME}; + Log3($name, 1, "$name: Startproc V".$hash->{ModuleVersion}." -> V".$Module_Version) if ($hash->{ModuleVersion}); + # Update necessary? + $hash->{ModuleVersion} = $Module_Version; +} + +########################## +sub Notify($$) +{ + my ($hash, $dev) = @_; + my $name = $hash->{NAME}; + my $devName = $dev->{NAME}; + return "" if(IsDisabled($name)); + Log3($name, 1, "$name : X_Notify $devName"); + my $events = deviceEvents($dev,1); + return if( !$events ); + + if($devName eq "global" && grep(m/^INITIALIZED|REREADCFG$/, @{$events})) + { + Startproc($hash); + } + + foreach my $event (@{$events}) { + $event = "" if(!defined($event)); + ### Writing log entry + Log3($name, 4, "$name : X_Notify $devName - $event"); + # Examples: + # $event = "readingname: value" + # or + # $event = "INITIALIZED" (for $devName equal "global") + # + # processing $event with further code + } + return undef; +} + +############################################################################################# +# called when the device gets renamed, copy from telegramBot +# in this case we then also need to rename the key in the token store and ensure it is recoded with new name +sub Rename($$) { + my ($new,$old) = @_; + my $hash = $defs{$new}; + + $data{MATRIX}{"$new"} = $data{MATRIX}{"$old"}; + $data{MATRIX}{"$old"} = undef; + $hash->{helper}->{passwdobj}->setRename($new,$old); + + #my $nhash = $defs{$new}; +} + +sub Get { + my $hash = shift; + my $aArg = shift; + + my $name = shift @$aArg; + my $cmd = shift @$aArg; + my $value = shift @$aArg; + + if ($cmd eq "wellknown") { + return PerformHttpRequest($hash, $cmd, ''); + } + elsif ($cmd eq "sync") { + $data{MATRIX}{"$name"}{"FAILS"} = 0; + return PerformHttpRequest($hash, $cmd, ''); + } + elsif ($cmd eq "filter") { + return qq("get Matrix $cmd" needs a filter_id to request); + return PerformHttpRequest($hash, $cmd, $value); + } + return "Unknown argument $cmd, choose one of filter sync wellknown"; +} + +sub Set { + my $hash = shift; + my $param = shift; + my $hArg = shift; + + my $name = shift @$param; + my $opt = shift @$param; + my $value = join("", @$param); + + #Log3($name, 5, "Set $name - $opt - $value - $hash->{NAME}"); + #return "set $name needs at least one argument" if (int(@$param) < 3); + + if ($opt eq "msg") { + return PerformHttpRequest($hash, $opt, $value); + } + elsif ($opt eq "poll" || $opt eq "poll.fullstate") { + readingsSingleUpdate($hash, $opt, $value, 1); # Readings erzeugen + } + elsif ($opt eq "password") { + my ($erg,$err) = $hash->{helper}->{passwdobj}->setStorePassword($name,$value); + return undef; + } + elsif ($opt eq "filter") { + return PerformHttpRequest($hash, $opt, ''); + } + elsif ($opt eq "question") { + return PerformHttpRequest($hash, $opt, $value); + } + elsif ($opt eq "question.end") { + return PerformHttpRequest($hash, $opt, $value); + } + elsif ($opt eq "register") { + return PerformHttpRequest($hash, $opt, ''); # 2 steps (ToDo: 3 steps empty -> dummy -> registration_token o.a.) + } + elsif ($opt eq "login") { + return PerformHttpRequest($hash, $opt, ''); + } + elsif ($opt eq "refresh") { + return PerformHttpRequest($hash, $opt, ''); + } + else { + return "Unknown argument $opt, choose one of filter:noArg password question question.end poll:0,1 poll.fullstate:0,1 msg register login:noArg refresh:noArg"; + } + + #return "$opt set to $value. Try to get it."; +} + + +sub Attr { + my ($cmd,$name,$attr_name,$attr_value) = @_; + if($cmd eq "set") { + if($attr_name eq "xxMatrixRoom") { + $attr_value =~ tr/: /~:/; + addToDevAttrList("mt", "MatrixMessage:".$attr_value); + } elsif($attr_name eq "xxMatrixMessage") { + $_[3] =~ tr/~/:/; + } else { + return ; + } + } + return ; +} + +sub PerformHttpRequest($$$) +{ + my ($hash, $def, $value) = @_; + my $now = gettimeofday(); + my $name = $hash->{NAME}; + my $passwd = ""; + $passwd = $hash->{helper}->{passwdobj}->getReadPassword($name) if ($def == "login" || $def == "reg2"); + #Log3($name, 5, "PerformHttpRequest - $name - $passwd"); + + + my $param = { + timeout => 10, + hash => $hash, # Muss gesetzt werden, damit die Callback funktion wieder $hash hat + def => $def, # sichern für eventuelle Wiederholung + value => $value, # sichern für eventuelle Wiederholung + method => "POST", # standard, sonst überschreiben + header => "User-Agent: HttpUtils/2.2.3\r\nAccept: application/json", # Den Header gemäß abzufragender Daten setzen + callback => \&ParseHttpResponse # Diese Funktion soll das Ergebnis dieser HTTP Anfrage bearbeiten + }; + $data{MATRIX}{"$name"}{"busy"} = $data{MATRIX}{"$name"}{"busy"} ? $data{MATRIX}{"$name"}{"busy"} + 1 : 1; # queue is busy until response is received + $data{MATRIX}{"$name"}{'LASTSEND'} = $now; # remember when last sent + if ($def eq "sync" && $data{MATRIX}{"$name"}{"next_refresh"} < $now){ + $def = "refresh"; + $data{MATRIX}{"$name"}{"next_refresh"} = $now + 300; + } + + my $device_id = ReadingsVal($name, 'device_id', undef) ? ', "device_id":"'.ReadingsVal($name, 'device_id', undef).'"' : ""; + if ($def eq "register"){ + $param->{'url'} = $hash->{server}."/_matrix/client/v3/register"; + $param->{'data'} = '{"type":"m.login.password", "identifier":{ "type":"m.id.user", "user":"'.$hash->{user}.'" }, "password":"'.$passwd.'"}'; + } + if ($def eq"reg2"){ + $param->{'url'} = $hash->{server}."/_matrix/client/v3/register"; + $param->{'data'} = '{"username":"'.$hash->{user}.'", "password":"'.$passwd.'", "auth": {"session":"'.$data{MATRIX}{"$name"}{"session"}.'","type":"m.login.dummy"}}'; + } + if ($def eq "login"){ + $param->{'url'} = $hash->{server}."/_matrix/client/v3/login"; + $param->{'data'} = '{"type":"m.login.password", "refresh_token": true, "identifier":{ "type":"m.id.user", "user":"'.$hash->{user}.'" }, "password":"'.$passwd.'"' + .$device_id.'}'; + } + if ($def eq "refresh"){ + $param->{'url'} = $hash->{server}.'/_matrix/client/v1/refresh'; + $param->{'data'} = '{"refresh_token": "'.$data{MATRIX}{"$name"}{"refresh_token"}.'"}'; + } + if ($def eq "wellknown"){ + $param->{'url'} = $hash->{server}."/.well-known/matrix/client"; + } + if ($def eq "msg"){ + $param->{'url'} = $hash->{server}.'/_matrix/client/r0/rooms/'.AttrVal($name, 'MatrixMessage', '!!').'/send/m.room.message?access_token='.$data{MATRIX}{"$name"}{"access_token"}; + $param->{'data'} = '{"msgtype":"m.text", "body":"'.$value.'"}'; + } + if ($def eq "question"){ + $value = AttrVal($name, "MatrixQuestion_$value",$value); # if ($value =~ /[0-9]/); + my @question = split(':',$value); + my $size = @question; + $value =~ s/:/
/g; + # min. question and one answer + if (int(@question) >= 2){ + $param->{'url'} = $hash->{server}.'/_matrix/client/v3/rooms/'.AttrVal($name, 'MatrixMessage', '!!').'/send/m.poll.start?access_token='.$data{MATRIX}{"$name"}{"access_token"}; + $param->{'data'} = '{"org.matrix.msc3381.poll.start": {"max_selections": 1,'. + '"question": {"org.matrix.msc1767.text": "'.$question[0].'"},'. + '"kind": "org.matrix.msc3381.poll.undisclosed",'. + '"answers": [{"id": "'.$question[1].'", "org.matrix.msc1767.text": "'.$question[1].'"},{"id":"'.$question[2].'","org.matrix.msc1767.text": "'.$question[2].'"}],'. + '"org.matrix.msc1767.text": "'.$value.'"}}'; + } else { + Log3($name, 5, "question: $value $size $question[0]"); + return; + } + } + if ($def eq "question.end"){ + $value = ReadingsVal($name, "question_id", "") if (!$value); + $param->{'url'} = $hash->{server}.'/_matrix/client/v3/rooms/'.AttrVal($name, 'MatrixMessage', '!!').'/send/m.poll.end?access_token='.$data{MATRIX}{"$name"}{"access_token"}; + # ""'.ReadingsVal($name, 'questionEventId', '!!').' + $param->{'data'} = '{"m.relates_to": {"rel_type": "m.reference","event_id": "'.$value.'"},"org.matrix.msc3381.poll.end": {},'. + '"org.matrix.msc1767.text": "Antort '.ReadingsVal($name, "answer", "").' erhalten von '.ReadingsVal($name, "sender", "").'"}'; + } + if ($def eq "sync"){ + my $since = ReadingsVal($name, "since", undef) ? '&since='.ReadingsVal($name, "since", undef) : ""; + my $full_state = ReadingsVal($name, "poll.fullstate",undef); + if ($full_state){ + $full_state = "&full_state=true"; + readingsSingleUpdate($hash, "poll.fullstate", 0, 1); + } else { + $full_state = ""; + } + $param->{'url'} = $hash->{server}.'/_matrix/client/r0/sync?access_token='.$data{MATRIX}{"$name"}{"access_token"}.$since.$full_state.'&timeout=50000&filter='.ReadingsVal($name, 'filter_id',0); + $param->{'method'} = 'GET'; + $param->{'timeout'} = 60; + } + if ($def eq "filter"){ + if ($value){ # get + $param->{'url'} = $hash->{server}.'/_matrix/client/v3/user/'.ReadingsVal($name, "user_id",0).'/filter/'.$value.'?access_token='.$data{MATRIX}{"$name"}{"access_token"}; + $param->{'method'} = 'GET'; + } else { + $param->{'url'} = $hash->{server}.'/_matrix/client/v3/user/'.ReadingsVal($name, "user_id",0).'/filter?access_token='.$data{MATRIX}{"$name"}{"access_token"}; + $param->{'data'} = '{'; + $param->{'data'} .= '"event_fields": ["type","content","sender"],'; + $param->{'data'} .= '"event_format": "client", '; + $param->{'data'} .= '"presence": { "senders": [ "@xx:example.com"]}'; # no presence + #$param->{'data'} .= '"room": { "ephemeral": {"rooms": ["'.AttrVal($name, 'MatrixRoom', '!!').'"],"types": ["m.receipt"]}, "state": {"types": ["m.room.*"]},"timeline": {"types": ["m.room.message"] } }'; + $param->{'data'} .= '}'; + } + } + + my $test = "$param->{url}, " + . ( $param->{data} ? "\r\ndata: $param->{data}, " : "" ) + . ( $param->{header} ? "\r\nheader: $param->{header}" : "" ); + #readingsSingleUpdate($hash, "fullRequest", $test, 1); # Readings erzeugen + $test = "$name: Matrix sends with timeout $param->{timeout} to ".$test; + Log3($name, 5, $test); + + HttpUtils_NonblockingGet($param); # Starten der HTTP Abfrage. Es gibt keinen Return-Code. + return undef; +} + +sub ParseHttpResponse($) +{ + my ($param, $err, $data) = @_; + my $hash = $param->{hash}; + my $def = $param->{def}; + my $value = $param->{value}; + my $name = $hash->{NAME}; + my $now = gettimeofday(); + my $nextRequest = ""; + + readingsBeginUpdate($hash); + ###readingsBulkUpdate($hash, "httpHeader", $param->{httpheader}); + readingsBulkUpdate($hash, "httpStatus", $param->{code}); + $hash->{STATE} = $def.' - '.$param->{code}; + if($err ne "") { # wenn ein Fehler bei der HTTP Abfrage aufgetreten ist + Log3($name, 3, "error while requesting ".$param->{url}." - $err"); # Eintrag fürs Log + readingsBulkUpdate($hash, "fullResponse", "ERROR ".$err); # Readings erzeugen + $data{MATRIX}{"$name"}{"FAILS"} = 3; + } + elsif($data ne "") { # wenn die Abfrage erfolgreich war ($data enthält die Ergebnisdaten des HTTP Aufrufes) + Log3($name, 4, $def." returned: $data"); # Eintrag fürs Log + my $decoded = eval { JSON::decode_json($data) }; + Log3($name, 2, "$name: json error: $@ in data") if( $@ ); + if ($param->{code} == 200){ + $data{MATRIX}{"$name"}{"FAILS"} = 0; + } else { + $data{MATRIX}{"$name"}{"FAILS"}++; + } + # readingsBulkUpdate($hash, "fullResponse", $data); + + # default next request + $nextRequest = "sync" ; + # An dieser Stelle die Antwort parsen / verarbeiten mit $data + + # "errcode":"M_UNKNOWN_TOKEN: login or refresh + my $errcode = $decoded->{'errcode'} ? $decoded->{'errcode'} : ""; + if ($errcode eq "M_UNKNOWN_TOKEN"){ + $data{MATRIX}{"$name"}{"repeat"} = $param if ($def ne "sync"); + if ($decoded->{'error'} eq "Access token has expired"){ + if ($decoded->{'soft_logout'} eq "true"){ + $nextRequest = 'refresh'; + }else{ + $nextRequest = 'login'; + } + } elsif ($decoded->{'error'} eq "refresh token does not exist"){ + $nextRequest = 'login'; + } + } + + if ($def eq "register"){ + $data{MATRIX}{"$name"}{"session"} = $decoded->{'session'}; + $nextRequest = "reg2"; + } + if ($param->{code} == 200 && ($def eq "reg2" || $def eq "login" || $def eq "refresh")){ + readingsBulkUpdate($hash, "user_id", $decoded->{'user_id'}) if ($decoded->{'user_id'}); + readingsBulkUpdate($hash, "home_server", $decoded->{'home_server'}) if ($decoded->{'home_server'}); + readingsBulkUpdate($hash, "device_id", $decoded->{'device_id'}) if ($decoded->{'device_id'}); + readingsBulkUpdate($hash, "last_register", $param->{code}) if $def eq "reg2"; + readingsBulkUpdate($hash, "last_login", $param->{code}) if $def eq "login"; + readingsBulkUpdate($hash, "last_refresh", $param->{code}) if $def eq "refresh"; + + $data{MATRIX}{"$name"}{"expires"} = $decoded->{'expires_in_ms'} if ($decoded->{'expires_in_ms'}); + $data{MATRIX}{"$name"}{"refresh_token"} = $decoded->{'refresh_token'} if ($decoded->{'refresh_token'}); + $data{MATRIX}{"$name"}{"access_token"} = $decoded->{'access_token'} if ($decoded->{'access_token'}); + $data{MATRIX}{"$name"}{"next_refresh"} = $now + $data{MATRIX}{"$name"}{"expires"}/1000 - 60; # refresh one minute before end + } + if ($def eq "wellknown"){ + # https://spec.matrix.org/unstable/client-server-api/ + } + if ($param->{code} == 200 && $def eq "sync"){ + readingsBulkUpdate($hash, "since", $decoded->{'next_batch'}) if ($decoded->{'next_batch'}); + # roomlist + my $list = $decoded->{'rooms'}->{'join'}; + #my @roomlist = (); + my $pos = 0; + foreach my $id ( keys $list->%* ) { + if (ref $list->{$id} eq ref {}) { + my $member = ""; + #my $room = $list->{$id}; + $pos = $pos + 1; + # MatrixRoom ? + readingsBulkUpdate($hash, "room$pos.id", $id); + #foreach my $id ( $decoded->{'rooms'}->{'join'}->{AttrVal($name, 'MatrixRoom', '!!')}->{'timeline'}->{'events'}->@* ) { + foreach my $ev ( $list->{$id}->{'state'}->{'events'}->@* ) { + readingsBulkUpdate($hash, "room$pos.topic", $ev->{'content'}->{'topic'}) if ($ev->{'type'} eq 'm.room.topic'); + readingsBulkUpdate($hash, "room$pos.name", $ev->{'content'}->{'name'}) if ($ev->{'type'} eq 'm.room.name'); + $member .= "$ev->{'sender'} " if ($ev->{'type'} eq 'm.room.member'); + } + readingsBulkUpdate($hash, "room$pos.member", $member); + foreach my $tl ( $list->{$id}->{'timeline'}->{'events'}->@* ) { + readingsBulkUpdate($hash, "room$pos.topic", $tl->{'content'}->{'topic'}) if ($tl->{'type'} eq 'm.room.topic'); + readingsBulkUpdate($hash, "room$pos.name", $tl->{'content'}->{'name'}) if ($tl->{'type'} eq 'm.room.name'); + if ($tl->{'type'} eq 'm.room.message' && $tl->{'content'}->{'msgtype'} eq 'm.text'){ + my $sender = $tl->{'sender'}; + if (AttrVal($name, 'MatrixSender', '') =~ $sender){ + readingsBulkUpdate($hash, "message", $tl->{'content'}->{'body'}); + readingsBulkUpdate($hash, "sender", $sender); + # command + + } + #else { + # readingsBulkUpdate($hash, "message", 'ignoriert, nicht '.AttrVal($name, 'MatrixSender', '')); + # readingsBulkUpdate($hash, "sender", $sender); + #} + } elsif ($tl->{'type'} eq "org.matrix.msc3381.poll.response"){ + my $sender = $tl->{'sender'}; + if (AttrVal($name, 'MatrixSender', '') =~ $sender){ + readingsBulkUpdate($hash, "answer", $tl->{'content'}->{'org.matrix.msc3381.poll.response'}->{'answers'}[0]); + readingsBulkUpdate($hash, "sender", $sender); + # poll.end and + $nextRequest = "question.end" ; + # command + + } + } + } + #push(@roomlist,"$id: "; + } + } + } + if ($def eq "filter"){ + readingsBulkUpdate($hash, "filter_id", $decoded->{'filter_id'}) if ($decoded->{'filter_id'}); + } + if ($def eq "msg" ){ + readingsBulkUpdate($hash, "event_id", $decoded->{'event_id'}) if ($decoded->{'event_id'}); + #m.relates_to + } + if ($def eq "question"){ + readingsBulkUpdate($hash, "question_id", $decoded->{'event_id'}) if ($decoded->{'event_id'}); + #m.relates_to + } + if ($def eq "question.end"){ + readingsBulkUpdate($hash, "event_id", $decoded->{'event_id'}) if ($decoded->{'event_id'}); + readingsBulkUpdate($hash, "question_id", "") if ($decoded->{'event_id'}); + #m.relates_to + } + } + readingsEndUpdate($hash, 1); + $data{MATRIX}{"$name"}{"busy"} = $data{MATRIX}{"$name"}{"busy"} - 1; # queue is busy until response is received + $data{MATRIX}{"$name"}{"sync"} = 0 if ($def eq "sync" || !$data{MATRIX}{"$name"}{"sync"}); # possible next sync + $nextRequest = "" if ($nextRequest eq "sync" && $data{MATRIX}{"$name"}{"sync"} == 1); # only one sync at a time! + + #if ($def eq "sync" && $nextRequest eq "sync" && ReadingsVal($name,'poll',0) == 1 && $data{MATRIX}{"$name"}{"FAILS"} < 3){ + # PerformHttpRequest($hash, $nextRequest, ''); + #} els + if ($nextRequest ne "" && ReadingsVal($name,'poll',0) == 1 && $data{MATRIX}{"$name"}{"FAILS"} < 3) { + if ($nextRequest eq "sync" && $data{MATRIX}{"$name"}{"repeat"}){ + $def = $data{MATRIX}{"$name"}{"repeat"}->{"def"}; + $value = $data{MATRIX}{"$name"}{"repeat"}->{"value"}; + $data{MATRIX}{"$name"}{"repeat"} = undef; + PerformHttpRequest($hash, $def, $value); + } else { + PerformHttpRequest($hash, $nextRequest, ''); + } + } + # Damit ist die Abfrage zuende. +}