package und device_id

zusätzlich einige Kleinigkeiten bereinigt, question mit zusätzlichem Testfür andere Clients außer Element.
This commit is contained in:
Manfred 2022-11-24 23:21:11 +01:00
parent b4b84ebe99
commit c9879d14be
2 changed files with 584 additions and 589 deletions

View File

@ -30,7 +30,7 @@ use strict;
use warnings;
use HttpUtils;
use FHEM::Meta;
use GPUtils qw(GP_Export GP_Import);
use GPUtils qw(GP_Export);
use JSON;
require FHEM::Devices::Matrix::Matrix;
@ -42,26 +42,22 @@ BEGIN {
GP_Export(qw(
Initialize
));
GP_Import(qw(
readingFnAttributes
));
}
sub Initialize {
my ($hash) = @_;
$hash->{DefFn} = \&FHEM::Matrix::Define;
$hash->{UndefFn} = \&FHEM::Matrix::Undef;
$hash->{SetFn} = \&FHEM::Matrix::Set;
$hash->{GetFn} = \&FHEM::Matrix::Get;
$hash->{AttrFn} = \&FHEM::Matrix::Attr;
$hash->{ReadFn} = \&FHEM::Matrix::Read;
$hash->{RenameFn} = \&FHEM::Matrix::Rename;
$hash->{NotifyFn} = \&FHEM::Matrix::Notify;
$hash->{DefFn} = \&FHEM::Devices::Matrix::Define;
$hash->{UndefFn} = \&FHEM::Devices::Matrix::Undef;
$hash->{Delete} = \&FHEM::Devices::Matrix::Delete;
$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} = $FHEM::Devices::Matrix::attr_list;
$hash->{AttrList} = Attr_List();
#$hash->{parseParams} = 1;
$hash->{AttrList} = FHEM::Devices::Matrix::Attr_List();
return FHEM::Meta::InitMod( __FILE__, $hash );
}

View File

@ -12,12 +12,13 @@
#package FHEM::Devices::Matrix;
#(Man-Fred) geh ich Recht in der Annahme, dass hier das gleiche package hin gehört
# wie im Modul 98_Matrix?
package FHEM::Matrix;
package FHEM::Devices::Matrix;
use strict;
use warnings;
use HttpUtils;
use JSON;
use GPUtils qw(GP_Import);
use FHEM::Core::Authentication::Passwords qw(:ALL);
use experimental qw /switch/; #(CoolTux) - als Ersatz für endlos lange elsif Abfragen
@ -25,6 +26,7 @@ use experimental qw /switch/; #(CoolTux) - als Ersatz für endlos lange elsif A
BEGIN {
GP_Import(qw(
readingFnAttributes
readingsBeginUpdate
readingsBulkUpdate
readingsEndUpdate
@ -38,7 +40,6 @@ BEGIN {
ReadingsVal
HttpUtils_NonblockingGet
InternalTimer
data
gettimeofday
fhem
))
@ -82,13 +83,20 @@ sub Define {
sub Undef {
my $hash = shift;
my $arg = shift;
my $name = shift;
my $name = $hash->{NAME};
# undef $data
#my $name = $hash->{NAME};
# $data{MATRIX}{"$name"} = undef; #(CoolTux) Bin mir gerade nicht sicher woher das $data kommt
# meinst Du das %data aus main? Das ist für User. Wenn Du als Modulentwickler
# etwas zwischenspeichern möchtest dann in $hash->{helper}
RemoveInternalTimer($hash->{myTimer}) if($hash->{myTimer});
$hash->{myTimer} = undef;
return ;
}
sub Delete {
my $hash = shift;
my $name = shift;
$hash->{helper}->{passwdobj}->setDeletePassword($name); #(CoolTux) das ist nicht nötig,
# du löschst jedesmal den Eintrag wenn FHEM beendet wird.
@ -184,9 +192,9 @@ sub Rename {
my ($passResp,$passErr);
$data{MATRIX}{"$new"} = $data{MATRIX}{"$old"};
#$data{MATRIX}{"$new"} = $data{MATRIX}{"$old"};
$data{MATRIX}{"$old"} = undef; #(CoolTux) Wenn ein Hash nicht mehr benötigt wird dann delete
#$data{MATRIX}{"$old"} = undef; #(CoolTux) Wenn ein Hash nicht mehr benötigt wird dann delete
# Fehler in der nächsten Zeile:
# delete argument is not a HASH or ARRAY element or slice at lib/FHEM/Devices/Matrix/Matrix.pm line 197.
# delete $data{MATRIX}{"$old"}
@ -210,10 +218,14 @@ sub I18N {
my $def = {
'EN' => {
'require2' => 'requires 2 arguments'
'require2' => 'requires 2 arguments',
'beginWithNumber' => 'must begin with a number',
'question' => 'a new question'
},
'DE' => {
'require2' => 'benötigt 2 Argumente'
'require2' => 'benötigt 2 Argumente',
'beginWithNumber' => 'muss mit einer Ziffer beginnen',
'question' => 'Eine neue Frage'
},
};
my $result = $def->{$language}->{$value};
@ -257,45 +269,6 @@ sub Get {
sub Set {
my ( $hash, $name, $cmd, @args ) = @_;
my $value = join(" ", @args);
#$opt = '?' if (!$opt);
#Log3($name, 5, "Set $hash->{NAME}: $name - $cmd - $value");
#return "set $name needs at least one argument" if (int(@$param) < 3);
#(CoolTux) Eine endlos Lange elsif Schlange ist nicht zu empfehlen, besser mit switch arbeiten
# Im Modulkopf use experimental qw /switch/; verwenden
# if ($cmd eq "msg") {
# return PerformHttpRequest($hash, $cmd, $value);
# }
# elsif ($cmd eq "pollFullstate") {
# readingsSingleUpdate($hash, $cmd, $value, 1); # Readings erzeugen
# }
# elsif ($cmd eq "password") {
# my ($erg,$err) = $hash->{helper}->{passwdobj}->setStorePassword($name,$value);
# return undef;
# }
# elsif ($cmd eq "filter") {
# return PerformHttpRequest($hash, $cmd, '');
# }
# elsif ($cmd eq "question") {
# return PerformHttpRequest($hash, $cmd, $value);
# }
# elsif ($cmd eq "questionEnd") {
# return PerformHttpRequest($hash, $cmd, $value);
# }
# elsif ($cmd eq "register") {
# return PerformHttpRequest($hash, $cmd, ''); # 2 steps (ToDo: 3 steps empty -> dummy -> registration_token o.a.)
# }
# elsif ($cmd eq "login") {
# return PerformHttpRequest($hash, $cmd, '');
# }
# elsif ($cmd eq "refresh") {
# return PerformHttpRequest($hash, $cmd, '');
# }
# else {
# return "Unknown argument $cmd, choose one of filter:noArg password question questionEnd pollFullstate:0,1 msg register login:noArg refresh:noArg";
# }
given ($cmd) {
when ('msg') {
@ -344,13 +317,15 @@ sub Attr {
if($cmd eq "set") {
if ($attr_name eq "matrixQuestion_") {
my @erg = split(/ /, $attr_value, 2);
return qq("attr $name $attr_name" ).I18N('require2') if (!$erg[1] || $erg[0] !~ /[0-9]/);
return qq("attr $name $attr_name" ).I18N('require2') if (!$erg[1]);
return qq("attr $name $attr_name" ).I18N('question').' '.I18N('beginWithNumber') if ($erg[0] !~ /[0-9]/);
$_[2] = "matrixQuestion_$erg[0]";
$_[3] = $erg[1];
}
if ($attr_name eq "matrixAnswer_") {
my @erg = split(/ /, $attr_value, 2);
return qq(wrong arguments $attr_name") if (!$erg[1] || $erg[0] !~ /[0-9]+/);
return qq("attr $name $attr_name" ).I18N('require2') if (!$erg[1]);
return qq("attr $name $attr_name" ).I18N('question').' '.I18N('beginWithNumber') if ($erg[0] !~ /[0-9]/);
$_[2] = "matrixAnswer_$erg[0]";
$_[3] = $erg[1];
}
@ -414,7 +389,7 @@ sub PerformHttpRequest
}
$hash->{helper}->{"msgnumber"} = $hash->{helper}->{"msgnumber"} ? $hash->{helper}->{"msgnumber"} + 1 : 1;
my $msgnumber = $hash->{helper}->{"msgnumber"};
my $deviceId = ReadingsVal($name, 'deviceId', undef) ? ', "deviceId":"'.ReadingsVal($name, 'deviceId', undef).'"' : "";
my $deviceId = ReadingsVal($name, 'deviceId', undef) ? ', "device_id":"'.ReadingsVal($name, 'deviceId', undef).'"' : "";
$hash->{helper}->{"busy"} = $hash->{helper}->{"busy"} ? $hash->{helper}->{"busy"} + 1 : 1; # queue is busy until response is received
$hash->{helper}->{"sync"} = 0 if (!$hash->{helper}->{"sync"});
@ -437,23 +412,24 @@ sub PerformHttpRequest
msgnumber => $msgnumber # lfd. Nummer Request
};
if ($def eq "logintypes"){
given ($def) {
when ('logintypes') {
$param->{'url'} = $hash->{server}."/_matrix/client/r0/login";
$param->{'method'} = 'GET';
}
if ($def eq "register"){
when ('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 "reg1"){
when ('reg1'){
$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"){
when ('reg2'){
$param->{'url'} = $hash->{server}."/_matrix/client/v3/register";
$param->{'data'} = '{"username":"'.$hash->{user}.'", "password":"'.$passwd.'", "auth": {"session":"'.$hash->{helper}->{"session"}.'","type":"m.login.dummy"}}';
}
if ($def eq "login"){
when ('login'){
if (AttrVal($name,'matrixLogin','') eq 'token'){
$param->{'url'} = $hash->{server}."/_matrix/client/v3/login";
$param->{'data'} = qq({"type":"m.login.token", "token":"$passwd", "user": "$hash->{user}", "txn_id": "z4567gerww", "session":"1234"});
@ -463,26 +439,52 @@ sub PerformHttpRequest
$param->{'data'} = '{"type":"m.login.password", "refresh_token": true, "identifier":{ "type":"m.id.user", "user":"'.$hash->{user}.'" }, "password":"'.$passwd.'"'.$deviceId.'}';
}
}
if ($def eq "login2"){
when ('login2'){
$param->{'url'} = $hash->{server}."/_matrix/client/v3/login";
if (AttrVal($name,'matrixLogin','') eq 'token'){
$param->{'data'} = qq({"type":"m.login.token", "token":"$passwd", "user": "\@$hash->{user}:matrix.org", "txn_id": "z4567gerww"});
#$param->{'data'} = qq({"type":"m.login.token", "token":"$passwd"});
}
}
if ($def eq "refresh"){
when ('refresh'){
$param->{'url'} = $hash->{server}.'/_matrix/client/v1/refresh';
$param->{'data'} = '{"refresh_token": "'.$hash->{helper}->{"refresh_token"}.'"}';
Log3($name, 5, qq($name $hash->{helper}->{"access_token"} refreshBeg $param->{'msgnumber'}: $hash->{helper}->{"next_refresh"} > $now) );
}
if ($def eq "wellknown"){
when ('wellknown'){
$param->{'url'} = $hash->{server}."/.well-known/matrix/client";
}
if ($def eq "msg"){
when ('msg'){
$param->{'url'} = $hash->{server}.'/_matrix/client/r0/rooms/'.AttrVal($name, 'matrixMessage', '!!').'/send/m.room.message?access_token='.$hash->{helper}->{"access_token"};
$param->{'data'} = '{"msgtype":"m.text", "body":"'.$value.'"}';
}
if ($def eq "question"){
when ('questionX'){
$hash->{helper}->{"question"}=$value;
$value = AttrVal($name, "matrixQuestion_$value",""); # if ($value =~ /[0-9]/);
my @question = split(':',$value);
my $size = @question;
my $answer;
my $q = shift @question;
$value =~ s/:/<br>/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='.$hash->{helper}->{"access_token"};
$param->{'data'} = '{"type":"m.poll.start", "content":{"m.poll": {"max_selections": 1,'.
'"question": {"org.matrix.msc1767.text": "'.$q.'"},'.
'"kind": "org.matrix.msc3381.poll.undisclosed","answers": [';
my $comma = '';
foreach $answer (@question){
$param->{'data'} .= qq($comma {"id": "$answer", "org.matrix.msc1767.text": "$answer"});
$comma = ',';
}
$param->{'data'} .= qq(],"org.matrix.msc1767.text": "$value"}, "m.markup": [{"mimetype": "text/plain", "body": "$value"}]}});
} else {
Log3($name, 5, "question: $value $size $question[0]");
return;
}
}
when ('question'){
$hash->{helper}->{"question"}=$value;
$value = AttrVal($name, "matrixQuestion_$value",""); # if ($value =~ /[0-9]/);
my @question = split(':',$value);
@ -502,19 +504,19 @@ sub PerformHttpRequest
$param->{'data'} .= qq($comma {"id": "$answer", "org.matrix.msc1767.text": "$answer"});
$comma = ',';
}
$param->{'data'} .= qq(],"org.matrix.msc1767.text": "$value"}});
$param->{'data'} .= qq(],"org.matrix.msc1767.text": "$value"}, "m.markup": [{"mimetype": "text/plain", "body": "$value"}]});
} else {
Log3($name, 5, "question: $value $size $question[0]");
return;
}
}
if ($def eq "questionEnd"){
when ('questionEnd'){
$value = ReadingsVal($name, "questionId", "") if (!$value);
$param->{'url'} = $hash->{server}.'/_matrix/client/v3/rooms/'.AttrVal($name, 'matrixMessage', '!!').'/send/m.poll.end?access_token='.$hash->{helper}->{"access_token"};
$param->{'data'} = '{"m.relates_to": {"rel_type": "m.reference","eventId": "'.$value.'"},"org.matrix.msc3381.poll.end": {},'.
'"org.matrix.msc1767.text": "Antort '.ReadingsVal($name, "answer", "").' erhalten von '.ReadingsVal($name, "sender", "").'"}';
}
if ($def eq "sync"){
when ('sync'){
my $since = ReadingsVal($name, "since", undef) ? '&since='.ReadingsVal($name, "since", undef) : "";
my $full_state = ReadingsVal($name, "pollFullstate",undef);
if ($full_state){
@ -529,7 +531,7 @@ sub PerformHttpRequest
$hash->{helper}->{"sync"}++;
Log3($name, 5, qq($name $hash->{helper}->{"access_token"} syncBeg $param->{'msgnumber'}: $hash->{helper}->{"next_refresh"} > $now) );
}
if ($def eq "filter"){
when ('filter'){
if ($value){ # get
$param->{'url'} = $hash->{server}.'/_matrix/client/v3/user/'.ReadingsVal($name, "userId",0).'/filter/'.$value.'?access_token='.$hash->{helper}->{"access_token"};
$param->{'method'} = 'GET';
@ -543,6 +545,7 @@ sub PerformHttpRequest
$param->{'data'} .= '}';
}
}
}
my $test = "$param->{url}, "
. ( $param->{data} ? "\r\ndata: $param->{data}, " : "" )
@ -597,7 +600,7 @@ sub ParseHttpResponse
} else {
$hash->{helper}->{"softfail"}++;
$hash->{helper}->{"hardfail"}++ if ($hash->{helper}->{"softfail"} > 3);
readingsBulkUpdate($hash, "responseError", qq(S$data{MATRIX}{$name}{'softfail'}: $data) );
readingsBulkUpdate($hash, "responseError", qq(S $hash->{helper}->{'softfail'}: $data) );
Log3($name, 5, qq($name $hash->{helper}->{"access_token"} ${def}End $param->{'msgnumber'}: $hash->{helper}->{"next_refresh"} > $now) );
}
# readingsBulkUpdate($hash, "fullResponse", $data);
@ -750,28 +753,24 @@ sub ParseHttpResponse
} else {
PerformHttpRequest($hash, $nextRequest, '');
}
} elsif ($hash->{helper}->{"softfail"} == 0){
# nichts tun, doppelter sync verhindert
} else {
my $pauseLogin;
if ($hash->{helper}->{"hardfail"} >= 3){
$pauseLogin = 300;
$pauseLogin = 300; # lange Pause wenn zu viele Fehler
} elsif ($hash->{helper}->{"softfail"} >= 3){
$pauseLogin = 30;
} elsif ($hash->{helper}->{"softfail"} > 0){
$pauseLogin = 10;
$pauseLogin = 30; # kurze Pause nach drei Fehlern oder einem 400
} else {
$pauseLogin = 0;
$pauseLogin = 10; # nach logischem Fehler ganz kurze Pause
}
if ($pauseLogin > 0){
my $timeToStart = gettimeofday() + $pauseLogin;
RemoveInternalTimer($hash->{myTimer}) if($hash->{myTimer});
$hash->{myTimer} = { hash=>$hash };
InternalTimer($timeToStart, \&FHEM::Devices::Matrix::Login, $hash->{myTimer});
} else {
Login($hash);
}
}
}
# Damit ist die Abfrage zuende.
return;
}