Compare commits

...

25 Commits
main ... dev

Author SHA1 Message Date
c2140d0159 Merge pull request 'fix Meta Data Store' (#8) from patch-VariableIsNotImported into dev
Reviewed-on: #8
2023-01-04 19:34:35 +01:00
Marko Oldenburg
c7f2b07345 fix Meta Data Store 2023-01-04 19:33:51 +01:00
1659fdd270 Merge pull request 'patch-VariableIsNotImported' (#7) from patch-VariableIsNotImported into dev
Reviewed-on: #7
2023-01-04 19:04:46 +01:00
Marko Oldenburg
2c09928a5e fix $VERSION problems 2023-01-04 19:04:13 +01:00
1cc677d1e2 Merge pull request 'dev' (#6) from dev into patch-CoolTux
Reviewed-on: #6
2023-01-04 18:40:28 +01:00
eb7aa3f011 Merge pull request 'patch-addControlfile' (#5) from patch-addControlfile into dev
Reviewed-on: #5
2023-01-04 18:36:53 +01:00
Marko Oldenburg
1961d02f10 change README 2023-01-04 18:36:06 +01:00
Marko Oldenburg
e64e71ba17 remove gitignore file 2023-01-04 18:34:10 +01:00
Marko Oldenburg
9460fb059c remove perlcritic and github actions 2023-01-04 18:32:21 +01:00
Marko Oldenburg
d24ada08f5 remove not supported files 2023-01-04 18:30:23 +01:00
Marko Oldenburg
2937e0ce90 add control file 2023-01-04 18:25:30 +01:00
b1d8603721 Merge pull request 'dev' (#4) from dev into patch-CoolTux
Reviewed-on: #4
2023-01-04 18:07:05 +01:00
bffdf597c2 Merge pull request 'change version, add Meta Data' (#3) from patch-changeMetaVersion into dev
Reviewed-on: #3
2023-01-04 17:57:25 +01:00
Marko Oldenburg
60f6b3aa78 change version, add Meta Data 2023-01-04 17:53:01 +01:00
132530bb0b Merge pull request 'add rewoke token then Access token has expired' (#2) from patch-relogin into dev
Reviewed-on: #2
2023-01-04 16:16:32 +01:00
Marko Oldenburg
31f2a85fe9 add rewoke token then Access token has expired
and send message
2023-01-04 16:09:34 +01:00
Marko Oldenburg
e21ff5a462 parted ParseHttpResponse fn 2023-01-03 13:42:10 +01:00
Marko Oldenburg
396d69c3f6 redesign all condition and switches of
_PerformHttpRequest fn
2023-01-02 13:58:03 +01:00
Marko Oldenburg
87ae5607ae Consider refactoring because high complexity score 2022-12-29 10:51:19 +01:00
Marko Oldenburg
fa1cf5d5bd fix specialcharacrter in messages 2022-12-26 19:40:51 +01:00
Marko Oldenburg
005ca1b852 remove high complexity score by create functions
first run of outsourced most of condition code in new functions
2022-12-26 15:49:10 +01:00
Marko Oldenburg
ed34e21d4e next step to rewrite 2022-12-26 05:51:54 +01:00
Marko Oldenburg
af9d97e686 first ready version after rewrite 2022-12-25 17:56:52 +01:00
GitHub Action
87f0427eda Automatic updated controls and CHANGED 2022-11-24 22:21:41 +00:00
Manfred
c9879d14be package und device_id
zusätzlich einige Kleinigkeiten bereinigt, question mit zusätzlichem Testfür andere Clients außer Element.
2022-11-24 23:21:11 +01:00
18 changed files with 1726 additions and 1088 deletions

14
.gitattributes vendored
View File

@ -1,14 +0,0 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto eol=lf
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.pm text eol=lf
*.pl text eol=lf
*.hash text eol=lf
*.txt text eol=lf
*.sh text eol=lf
# Denote all files that are truly binary and should not be modified.
*.hex binary
*.bin binary

View File

@ -1,7 +0,0 @@
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View File

@ -1,97 +0,0 @@
name: Fhem UnitTest
on:
push:
branches:
paths:
- 'FHEM/**'
- 'UnitTest/**'
- 't/**'
- '.github/workflows/fhem_test.yml'
schedule:
- cron: '43 17 * * 1'
jobs:
update_controls:
env:
CONTROLS_FILENAME: controls_${{ github.event.repository.name }}.txt
runs-on: ubuntu-latest
steps:
- name: Extract branch name
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/*/})"
id: extract_branch
- name: Checkout Repostory
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: update controls files
uses: fhem/fhem-controls-actions@v2
with:
filename: ${{env.CONTROLS_FILENAME}}
- name: update CHANGED
run: |
LOG=$(date +"%Y-%m-%d")
LOG+=" - $(git log -1 --pretty=%B)"
echo "$LOG" | cat - CHANGED 2>/dev/null >> temp || true && mv temp CHANGED
- name: git commit back
run: |
git config --global user.email "action@github.com"
git config --local user.name "GitHub Action"
git add CHANGED ${{env.CONTROLS_FILENAME}} || true
git log -1 --name-only --pretty=format: | grep -Eo '[0-9]{2}_.*.pm$' && git commit CHANGED ${{env.CONTROLS_FILENAME}} -m "Automatic updated controls and CHANGED" || true
- name: git push
uses: ad-m/github-push-action@v0.6.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ steps.extract_branch.outputs.branch }}
# test:
# runs-on: ubuntu-latest
# if: github.event_name == 'push'
# strategy:
# matrix:
# os: ['ubuntu-latest']
# perl: [ '5.22', '5.28', '5.30', '5.32' ]
#
# name: Perl ${{ matrix.perl }} on ${{ matrix.os }}
# steps:
# - uses: actions/checkout@v3
# - uses: shogo82148/actions-setup-perl@v1.18.0
# with:
# perl-version: ${{ matrix.perl }}
# install-modules-with: cpanm
# install-modules-args: --notest
# - name: install fhem via deb package
# run: |
# wget -qO - http://debian.fhem.de/archive.key | sudo apt-key add -
# echo "deb http://debian.fhem.de/nightly/ /" | sudo tee -a /etc/apt/sources.list
# sudo apt-get update -qq
# sudo apt-get install fhem -y
# sudo systemctl stop fhem
# sudo chown -R --reference=README.md /opt/fhem
## - name: run prove on perl modules (testscripts)
## run: prove --exec 'perl -MDevel::Cover=-silent,1 -I FHEM ' -I FHEM -r -vv t/FHEM/<packagename>
## - uses: codecov/codecov-action@v1
## with:
## token: ${{ secrets.CODECOV_TOKEN }}
## file: ./cover_db/clover.xml
## flags: unittests,perl,modules
## name: perl modules (testscripts) ${{ matrix.perl }}
# - name: run prove fhem testsuite ${{ matrix.perl }} on modules
# run: |
# cp -r FHEM/* ${FHEM_DIR}/FHEM/
# cd ${FHEM_DIR}
# prove --exec 'perl -MDevel::Cover=-silent,1 fhem.pl -t' -I FHEM -r -vv ${GITHUB_WORKSPACE}/t/FHEM/98_Matrix/[0-9][0-9]_*/
# sleep 3
# cp -R /opt/fhem/cover_db ${GITHUB_WORKSPACE}/
# ls -l ${GITHUB_WORKSPACE}
# env:
# FHEM_DIR: /opt/fhem
# - name: Create clover report
# run: cover -report clover
## - uses: codecov/codecov-action@v1
## with:
## token: ${{ secrets.CODECOV_TOKEN }}
## file: ./cover_db/clover.xml
## flags: unittests,fhem,modules
## name: fhem (testscripts) ${{ matrix.perl }}

View File

@ -1,34 +0,0 @@
name: Perlcritic check
on:
pull_request:
types: [opened, synchronize]
jobs:
critic:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout repository
uses: actions/checkout@v3
- uses: shogo82148/actions-setup-perl@v1.18.0
with:
perl-version: 5.32
install-modules-with: cpanm
install-modules: Perl::Critic Task::PerlCriticAllPolicies
install-modules-args: --notest
- uses: reviewdog/action-setup@v1
with:
reviewdog_version: latest # Optional. [latest,nightly,v.X.Y.Z]
- name: run perlcritic and send report via reviewdog
env:
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
(perlcritic --verbose 1 --profile .perlcritic ./FHEM; perlcritic --verbose 1 --profile .perlcritic ./lib; ) | \
reviewdog -efm '%f:%l:%c:%m' \
-name="perlcritic" \
-reporter="github-pr-check" \
-filter-mode="added" \
-fail-on-error="false" \
-level="warning" \

35
.gitignore vendored
View File

@ -1,35 +0,0 @@
!Build/
.last_cover_stats
/META.yml
/META.json
/MYMETA.*
*.o
*.pm.tdy
*.bs
# Devel::Cover
cover_db/
# Devel::NYTProf
nytprof.out
# Dizt::Zilla
/.build/
# Module::Build
_build/
Build
Build.bat
# Module::Install
inc/
# ExtUtils::MakeMaker
/blib/
/_eumm/
/*.gz
/Makefile
/Makefile.old
/MANIFEST.bak
/pm_to_blib
/*.zip

View File

@ -1,2 +0,0 @@
severity = 5
color = 1

View File

@ -1,3 +1,6 @@
2022-11-24 - package und device_id
zusätzlich einige Kleinigkeiten bereinigt, question mit zusätzlichem Testfür andere Clients außer Element.
2022-11-23 - Anpassungen nach merge von Cooltux
2022-11-22 - autologin when matrixPoll=1

View File

@ -23,51 +23,48 @@
# Usage:
#
##########################################################################
# $Id: 98_Matrix.pm 14063 2022-11-12 12:52:00Z Man-fred $
# $Id$
package FHEM::Matrix;
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;
require FHEM::Devices::Matrix::Client;
#-- Run before package compilation
BEGIN {
#-- Export to main context with different name
GP_Export(qw(
Initialize
));
GP_Import(qw(
readingFnAttributes
));
sub ::Matrix_Initialize { goto &Initialize }
}
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->{AttrList} = $FHEM::Devices::Matrix::attr_list;
$hash->{AttrList} = Attr_List();
#$hash->{parseParams} = 1;
$hash->{DefFn} = \&FHEM::Devices::Matrix::Client::Define;
$hash->{UndefFn} = \&FHEM::Devices::Matrix::Client::Undef;
$hash->{Delete} = \&FHEM::Devices::Matrix::Client::Delete;
$hash->{SetFn} = \&FHEM::Devices::Matrix::Client::Set;
$hash->{GetFn} = \&FHEM::Devices::Matrix::Client::Get;
$hash->{AttrFn} = \&FHEM::Devices::Matrix::Client::Attr;
$hash->{ReadFn} = \&FHEM::Devices::Matrix::Client::Read;
$hash->{RenameFn} = \&FHEM::Devices::Matrix::Client::Rename;
$hash->{NotifyFn} = \&FHEM::Devices::Matrix::Client::Notify;
$hash->{AttrList} = FHEM::Devices::Matrix::Client::Attr_List();
$hash->{parseParams} =
1; # wir verwenden parseParams für Set und Get (CoolTux)
return FHEM::Meta::InitMod( __FILE__, $hash );
}
1;
__END__
=pod
=item summary Provides a Matrix-Chatbot.
=item summary_DE Stellt einen Matrix-Chatbot bereit.
@ -364,4 +361,48 @@ sub Initialize {
</ul>
=end html_DE
=for :application/json;q=META.json 70_Matrix.pm
{
"abstract": "Provides a Matrix-Chatbot",
"x_lang": {
"de": {
"abstract": "Stellt einen Matrix-Chatbot bereit"
}
},
"version": "v0.15.4",
"author": [
"Manfred Bielemeier"
],
"x_fhem_maintainer": [
"<a href=https://forum.fhem.de/index.php?action=profile;u=41965>mBielemeier </a>"
],
"x_fhem_maintainer_github": [
"Man-fred"
],
"prereqs": {
"runtime": {
"requires": {
"FHEM::Meta": 0,
"HttpUtils": 0,
"strict": 0,
"warnings": 0,
"experimental": 0,
"carp": 0,
"POSIX": 0,
"JSON::PP": 0,
"encode": 0
},
"recommends": {
"JSON": 0
},
"suggests": {
"JSON::XS": 0,
"Cpanel::JSON::XS": 0
}
}
}
}
=end :application/json;q=META.json
=cut

View File

@ -1,4 +1,4 @@
# FHEM/98_Matrix.pm
# FHEM/70_Matrix.pm
## Vorwort
Ich habe seit gefühlten Ewigkeiten FHEM im Einsatz und jetzt neu auch Matrix, was bei mir Telegram als Meldungszentrale ablösen soll. Ich bin dabei einen Bot als FHEM-Modul aufzubauen der sowohl Meldungen absetzen kann als auch Befehle empfangen kann.
@ -32,51 +32,4 @@ https://wiki.fhem.de/wiki/DevelopmentModuleIntro
### lib/
Put any libs(pure perl modules) you provide in a own package (not main) create in here
## automated Testing
### t/FHEM/98_Matrix/*
Unittests for the fhem mdoule run via github actions if needed you have to write them into folder t/FHEM/<modulename>/
### t/FHEM/<packagename>/*
Unittests for the perl mdoule run via github actions if needed you have to write them into folder t/FHEM/<PACKAGENAME>/
Unittests (run prove on perl modules (testscripts)) needs to be enabled in the fhem_test.yml workflow
```
- name: run prove on perl modules (testscripts)
run: prove --exec 'perl -MDevel::Cover=-silent,1 -I FHEM ' -I FHEM -r -vv t/FHEM/<packagename>
```
### cpanfile
Cpan modules needed for running your module and your tests, they will be installed after perl is set up and running
### .github/workflows/update.yml
This is a github action workflow which creates a controls file which is needed for fhem update command.
You are then able to install your new module
`update all https://raw.githubusercontent.com/fhem/<reponame>/<branch>/controls_<reponame>.txt`
### .github/workflows/fhem_test.yml
This is a github action workflow which runs all your tests in t/xx_<Module> folder with different perl versions.
### .github/dependabot.yml
Dependabot will check if there are new versions form used actions you are using in your worflows and inform you.
### Code coverage
You can use codecov (https://about.codecov.io/) to monitor your test code coveage.
Simply enable the coverage action an provide a token vom codecov.io via github secrets
- uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./cover_db/clover.xml
flags: unittests,fhem,modules
name: fhem (testscripts) ${{ matrix.perl }}
Put any libs(pure perl modules) you provide in a own package (not main) create in here

2
controls_Matrix.txt Normal file
View File

@ -0,0 +1,2 @@
UPD 2023-01-04_19:32:50 16955 FHEM/70_Matrix.pm
UPD 2023-01-04_19:32:46 51750 lib/FHEM/Devices/Matrix/Client.pm

View File

@ -1 +0,0 @@
UPD 2022-11-23_21:57:49 16111 FHEM/98_Matrix.pm

View File

@ -1 +0,0 @@
UPD 2022-01-07_00:05:45 4688 FHEM/98_Matrix.pm

View File

@ -1,4 +0,0 @@
requires 'Test2::Suite';
requires 'Devel::Cover';
requires 'Devel::Cover::Report::Clover';
recommends 'Pod::Usage';

View File

@ -1,20 +1,20 @@
parseParams#!/usr/bin/perl -w
#!/usr/bin/perl -w
use File::Basename;
use POSIX qw(strftime);
use strict;
my @filenames = ( 'FHEM/98_Matrix.pm',
'lib/FHEM/Devices/Matrix.pm'
);
my @filenames = ( 'FHEM/70_Matrix.pm',
'lib/FHEM/Devices/Matrix/Client.pm',
);
my $controlsfile = 'controls_Matrix.txt';
my $controlsfile = 'controls_Matrix.txt';
open(FH, ">$controlsfile") || return("Can't open $controlsfile: $!");
for my $filename (@filenames) {
my @statOutput = stat($filename);
if (scalar @statOutput != 13) {
printf 'error: stat has unexpected return value for ' . $filename . "\n";
next;

File diff suppressed because it is too large Load Diff

View File

@ -1,782 +0,0 @@
##########################################################################
# Usage:
#
##########################################################################
# $Id: Matrix.pm 22821 2022-11-12 12:52:00Z Man-fred $
#
# from the developerpages:
# Verwendung von lowerCamelCaps für a) die Bezeichnungen der Behälter für Readings, Fhem und Helper und der Untereintraege,
# b) die Bezeichnungen der Readings,
# c) die Bezeichnungen der Attribute.
#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;
use strict;
use warnings;
use HttpUtils;
use JSON;
use FHEM::Core::Authentication::Passwords qw(:ALL);
use experimental qw /switch/; #(CoolTux) - als Ersatz für endlos lange elsif Abfragen
BEGIN {
GP_Import(qw(
readingsBeginUpdate
readingsBulkUpdate
readingsEndUpdate
readingsSingleUpdate
Log3
defs
init_done
IsDisabled
deviceEvents
AttrVal
ReadingsVal
HttpUtils_NonblockingGet
InternalTimer
data
gettimeofday
fhem
))
};
my $Module_Version = '0.0.9';
my $language = 'EN';
sub Attr_List{
return "matrixLogin:password matrixRoom matrixPoll:0,1 matrixSender matrixMessage matrixQuestion_ matrixQuestion_[0-9]+ matrixAnswer_ matrixAnswer_[0-9]+ $readingFnAttributes";
}
sub Define {
#(CoolTux) bei einfachen übergaben nimmt man die Daten mit shift auf
my $hash = shift;
my $def = shift;
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 <name> Matrix <server> <user>";
}
$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->{helper}->{i18} = Get_I18n();
$hash->{NOTIFYDEV} = "global";
Startproc($hash) if($init_done); #(CoolTux) Wie startet Startproc() wenn $init_done 0 ist. Dann bleibt das Modul stehen und macht nichts mehr
# es empfiehlt sich hier in der NotifyFn das globale Event INITIALIZED abzufangen.
# Ok gerade gesehen hast Du gemacht!!!
return ;
}
sub Undef {
my $hash = shift;
my $arg = shift;
my $name = $hash->{NAME};
# undef $data
# $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}
$hash->{helper}->{passwdobj}->setDeletePassword($name); #(CoolTux) das ist nicht nötig,
# du löschst jedesmal den Eintrag wenn FHEM beendet wird.
# Es sollte eine DeleteFn geben da kannst Du das rein machen
return ;
}
sub Startproc {
my $hash = shift;
my $name = $hash->{NAME};
Log3($name, 4, "$name : Matrix::Startproc $hash ".AttrVal($name,'matrixPoll','-1'));
# Update necessary?
Log3($name, 1, "$name: Start V".$hash->{ModuleVersion}." -> V".$Module_Version) if ($hash->{ModuleVersion});
$hash->{ModuleVersion} = $Module_Version;
$language = AttrVal('global','language','EN');
$hash->{helper}->{"softfail"} = 1;
Login($hash) if (AttrVal($name,'matrixPoll',0) == 1);
return;
}
sub Login {
my $hash = shift;
Log3($hash->{NAME}, 4, "$hash->{NAME} : Matrix::Login $hash");
return PerformHttpRequest($hash, 'login', '');
}
##########################
# sub Notify($$)
#(CoolTux) Subroutine prototypes used. See page 194 of PBP (Subroutines::ProhibitSubroutinePrototypes)
# Contrary to common belief, subroutine prototypes do not enable
# compile-time checks for proper arguments. Don't use them.
sub Notify
{
my $hash = shift;
my $dev = shift;
my $name = $hash->{NAME};
my $devName = $dev->{NAME};
return "" if(IsDisabled($name));
my $events = deviceEvents($dev,1);
return if( !$events );
#if(($devName eq "global") && grep(m/^INITIALIZED|REREADCFG$/, @{$events}))
#(CoolTux) unnötige Klammern, und vielleicht bisschen übersichtlicher versuchen :-)
if ( $devName eq "global"
&& grep(m/^INITIALIZED|REREADCFG$/, @{$events}))
{
Log3($name, 4, "$name : Matrix::Notify $hash");
Startproc($hash);
}
#(CoolTux) bin mir nicht sicher wieso die Schleife. Nötig ist sie aber egal wofür gedacht nicht.
#(Man-Fred) die Schleife ist vom Debugging, ich wollte wissen was im Notify ankommt.
# kann raus in einer späteren Version
foreach my $event (@{$events}) {
$event = "" if(!defined($event));
### Writing log entry
Log3($name, 4, "$name : Matrix::Notify $devName - $event");
$language = AttrVal('global','language','EN') if ($event =~ /ATTR global language.*/);
# Examples:
# $event = "ATTR global language DE"
# $event = "readingname: value"
# or
# $event = "INITIALIZED" (for $devName equal "global")
#
# processing $event with further code
}
return; #(CoolTux) es reicht nur return. Wichtig jede sub muss immer mit return enden
}
#############################################################################################
# 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 = shift;
my $old = shift;
my $hash = $defs{$new};
my $name = $hash->{NAME};
my ($passResp,$passErr);
$data{MATRIX}{"$new"} = $data{MATRIX}{"$old"};
$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"}
($passResp,$passErr) = $hash->{helper}->{passwdobj}->setRename($new,$old); #(CoolTux) Es empfiehlt sich ab zu fragen ob der Wechsel geklappt hat
Log3($name, 1, "$name : Matrix::Rename - error while change the password hash after rename - $passErr")
if ( !defined($passResp)
&& defined($passErr) );
Log3($name, 1, "$name : Matrix::Rename - change password hash after rename successfully")
if ( defined($passResp)
&& !defined($passErr) );
#my $nhash = $defs{$new};
return;
}
sub I18N {
my $value = shift;
my $def = {
'EN' => {
'require2' => 'requires 2 arguments'
},
'DE' => {
'require2' => 'benötigt 2 Argumente'
},
};
my $result = $def->{$language}->{$value};
return ($result ? $result : $value);
}
sub Get {
my ( $hash, $name, $cmd, @args ) = @_;
my $value = join(" ", @args);
#$cmd = '?' if (!$cmd);
#(CoolTux) Eine endlos Lange elsif Schlange ist nicht zu empfehlen, besser mit switch arbeiten
# Im Modulkopf use experimental qw /switch/; verwenden
given ($cmd) {
when ('wellknown') {
return PerformHttpRequest($hash, $cmd, '');
}
when ('logintypes') {
return PerformHttpRequest($hash, $cmd, '');
}
when ('sync') {
$hash->{helper}->{"softfail"} = 0; #(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}
$hash->{helper}->{"hardfail"} = 0;
return PerformHttpRequest($hash, $cmd, '');
}
when ('filter') {
return qq("get Matrix $cmd" needs a filterId to request);
return PerformHttpRequest($hash, $cmd, $value);
}
default { return "Unknown argument $cmd, choose one of logintypes filter sync wellknown"; }
}
}
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') {
return PerformHttpRequest($hash, $cmd, $value);
}
when ('pollFullstate') {
readingsSingleUpdate($hash, $cmd, $value, 1); # Readings erzeugen
}
when ('password') {
my ($erg,$err) = $hash->{helper}->{passwdobj}->setStorePassword($name,$value);
return;
}
when ('filter') {
return PerformHttpRequest($hash, $cmd, '');
}
when ('question') {
return PerformHttpRequest($hash, $cmd, $value);
}
when ('questionEnd') {
return PerformHttpRequest($hash, $cmd, $value);
}
when ('register') {
return PerformHttpRequest($hash, $cmd, ''); # 2 steps (ToDo: 3 steps empty -> dummy -> registration_token o.a.)
}
when ('login') {
return PerformHttpRequest($hash, $cmd, '');
}
when ('refresh') {
return PerformHttpRequest($hash, $cmd, '');
}
default {
return "Unknown argument $cmd, choose one of filter:noArg password question questionEnd pollFullstate:0,1 msg register login:noArg refresh:noArg";
}
}
return;
}
sub Attr {
my ($cmd,$name,$attr_name,$attr_value) = @_;
Log3($name, 4, "Attr - $cmd - $name - $attr_name - $attr_value");
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]/);
$_[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]+/);
$_[2] = "matrixAnswer_$erg[0]";
$_[3] = $erg[1];
}
}
return ;
}
sub Get_Message {
my $name = shift;
my $def = shift;
my $message = shift;
Log3($name, 3, "$name - $def - $message");
my $q = AttrVal($name, "matrixQuestion_$def", "");
my $a = AttrVal($name, "matrixAnswer_$def", "");
my @questions = split(':',$q);
shift @questions if ($def ne '99');
my @answers = split(':', $a);
Log3($name, 3, "$name - $q - $a");
my $pos = 0;
#my ($question, $answer);
my $answer;
# foreach my $question (@questions){
foreach my $question (@questions){ #(CoolTux) - Loop iterator is not lexical. See page 108 of PBP (Variables::RequireLexicalLoopIterators)perlcritic
# This policy asks you to use `my'-style lexical loop iterator variables:
# foreach my $zed (...) {
# ...
# }
Log3($name, 3, "$name - $question - $answers[$pos]");
$answer = $answers[$pos] if ($message eq $question);
if ($answer){
Log3($name, 3, "$name - $pos - $answer");
fhem($answer);
last;
}
$pos++;
}
return;
}
sub PerformHttpRequest
{
#(CoolTux) hier solltest Du überlegen das Du die einzelnen Anweisung nach der Bedingung in einzelne Funktionen auslagerst
# Subroutine "PerformHttpRequest" with high complexity score
#(Man-Fred) da ich noch nicht wusste wie ähnlich die Ergebnisse sind habe ich erst mal alles zusammen ausgewertet
my $hash = shift;
my $def = shift;
my $value = shift;
my $now = gettimeofday();
my $name = $hash->{NAME};
my $passwd = "";
Log3($name, 4, "$name : Matrix::PerformHttpRequest $hash");
if ($def eq "login" || $def eq "reg2"){
$passwd = $hash->{helper}->{passwdobj}->getReadPassword($name) ;
}
$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).'"' : "";
$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"});
$hash->{helper}->{'LASTSEND'} = $now; # remember when last sent
if ($def eq "sync" && $hash->{helper}->{"next_refresh"} < $now && AttrVal($name,'matrixLogin','') eq 'password'){
$def = "refresh";
Log3($name, 5, qq($name $hash->{helper}->{"access_token"} sync2refresh - $hash->{helper}->{"next_refresh"} < $now) );
$hash->{helper}->{"next_refresh"} = $now + 300;
}
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
msgnumber => $msgnumber # lfd. Nummer Request
};
if ($def eq "logintypes"){
$param->{'url'} = $hash->{server}."/_matrix/client/r0/login";
$param->{'method'} = 'GET';
}
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 "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"){
$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"){
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"});
#$param->{'method'} = 'GET';
} else {
$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.'"'.$deviceId.'}';
}
}
if ($def eq "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"){
$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"){
$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='.$hash->{helper}->{"access_token"};
$param->{'data'} = '{"msgtype":"m.text", "body":"'.$value.'"}';
}
if ($def eq "question"){
$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'} = '{"org.matrix.msc3381.poll.start": {"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"}});
} else {
Log3($name, 5, "question: $value $size $question[0]");
return;
}
}
if ($def eq "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"){
my $since = ReadingsVal($name, "since", undef) ? '&since='.ReadingsVal($name, "since", undef) : "";
my $full_state = ReadingsVal($name, "pollFullstate",undef);
if ($full_state){
$full_state = "&full_state=true";
readingsSingleUpdate($hash, "pollFullstate", 0, 1);
} else {
$full_state = "";
}
$param->{'url'} = $hash->{server}.'/_matrix/client/r0/sync?access_token='.$hash->{helper}->{"access_token"}.$since.$full_state.'&timeout=50000&filter='.ReadingsVal($name, 'filterId',0);
$param->{'method'} = 'GET';
$param->{'timeout'} = 60;
$hash->{helper}->{"sync"}++;
Log3($name, 5, qq($name $hash->{helper}->{"access_token"} syncBeg $param->{'msgnumber'}: $hash->{helper}->{"next_refresh"} > $now) );
}
if ($def eq "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';
} else {
$param->{'url'} = $hash->{server}.'/_matrix/client/v3/user/'.ReadingsVal($name, "userId",0).'/filter?access_token='.$hash->{helper}->{"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);
Log3($name, 3, qq($name $param->{'msgnumber'} $def Request Busy/Sync $hash->{helper}->{"busy"} / $hash->{helper}->{"sync"}) );
HttpUtils_NonblockingGet($param); # Starten der HTTP Abfrage. Es gibt keinen Return-Code.
return;
}
sub ParseHttpResponse
{
#(CoolTux) hier solltest Du überlegen das Du die einzelnen Anweisung nach der Bedingung in einzelne Funktionen auslagerst
# Subroutine "PerformHttpRequest" with high complexity score
#(Man-Fred) da ich noch nicht wusste wie ähnlich die Ergebnisse sind habe ich erst mal alles zusammen ausgewertet
my $param = shift;
my $err = shift;
my $data = shift;
my $hash = $param->{hash};
my $def = $param->{def};
my $value = $param->{value};
my $name = $hash->{NAME};
my $now = gettimeofday();
my $nextRequest = "";
Log3($name, 3, qq($name $param->{'msgnumber'} $def Result $param->{code}) );
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, 2, "error while requesting ".$param->{url}." - $err"); # Eintrag fürs Log
readingsBulkUpdate($hash, "responseError", $err); # Reading erzeugen
$hash->{helper}->{"softfail"} = 3;
$hash->{helper}->{"hardfail"}++;
}
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){
$hash->{helper}->{"softfail"} = 0;
$hash->{helper}->{"hardfail"} = 0;
} else {
$hash->{helper}->{"softfail"}++;
$hash->{helper}->{"hardfail"}++ if ($hash->{helper}->{"softfail"} > 3);
readingsBulkUpdate($hash, "responseError", qq(S$data{MATRIX}{$name}{'softfail'}: $data) );
Log3($name, 5, qq($name $hash->{helper}->{"access_token"} ${def}End $param->{'msgnumber'}: $hash->{helper}->{"next_refresh"} > $now) );
}
# 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"){
$hash->{helper}->{"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"){
$hash->{helper}->{"session"} = $decoded->{'session'};
$nextRequest = "";#"reg2";
}
$hash->{helper}->{"session"} = $decoded->{'session'} if ($decoded->{'session'});
readingsBulkUpdate($hash, "session", $decoded->{'session'}) if ($decoded->{'session'});
if ($def eq "reg2" || $def eq "login" || $def eq "refresh") {
readingsBulkUpdate($hash, "lastRegister", $param->{code}) if $def eq "reg2";
readingsBulkUpdate($hash, "lastLogin", $param->{code}) if $def eq "login";
readingsBulkUpdate($hash, "lastRefresh", $param->{code}) if $def eq "refresh";
if ($param->{code} == 200){
readingsBulkUpdate($hash, "userId", $decoded->{'user_id'}) if ($decoded->{'user_id'});
readingsBulkUpdate($hash, "homeServer", $decoded->{'homeServer'}) if ($decoded->{'homeServer'});
readingsBulkUpdate($hash, "deviceId", $decoded->{'device_id'}) if ($decoded->{'device_id'});
$hash->{helper}->{"expires"} = $decoded->{'expires_in_ms'} if ($decoded->{'expires_in_ms'});
$hash->{helper}->{"refresh_token"} = $decoded->{'refresh_token'} if ($decoded->{'refresh_token'});
$hash->{helper}->{"access_token"} = $decoded->{'access_token'} if ($decoded->{'access_token'});
$hash->{helper}->{"next_refresh"} = $now + $hash->{helper}->{"expires"}/1000 - 60; # refresh one minute before end
}
Log3($name, 5, qq($name $hash->{helper}->{"access_token"} refreshEnd $param->{'msgnumber'}: $hash->{helper}->{"next_refresh"} > $now) );
}
if ($def eq "wellknown"){
# https://spec.matrix.org/unstable/client-server-api/
}
if ($param->{code} == 200 && $def eq "sync"){
Log3($name, 5, qq($name $hash->{helper}->{"access_token"} syncEnd $param->{'msgnumber'}: $hash->{helper}->{"next_refresh"} > $now) );
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'};
my $message = $tl->{'content'}->{'body'};
if (AttrVal($name, 'matrixSender', '') =~ $sender){
readingsBulkUpdate($hash, "message", $message);
readingsBulkUpdate($hash, "sender", $sender);
# command
Get_Message($name, '99', $message);
}
#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'};
my $message = $tl->{'content'}->{'org.matrix.msc3381.poll.response'}->{'answers'}[0];
if ($tl->{'content'}->{'m.relates_to'}){
if ($tl->{'content'}->{'m.relates_to'}->{'rel_type'} eq 'm.reference'){
readingsBulkUpdate($hash, "questionId", $tl->{'content'}->{'m.relates_to'}->{'event_id'})
}
}
if (AttrVal($name, 'matrixSender', '') =~ $sender){
readingsBulkUpdate($hash, "message", $message);
readingsBulkUpdate($hash, "sender", $sender);
$nextRequest = "questionEnd" ;
# command
Get_Message($name, $hash->{helper}->{"question"}, $message);
}
}
}
#push(@roomlist,"$id: ";
}
}
}
if ($def eq "logintypes"){
my $types = '';
foreach my $flow ( $decoded->{'flows'}->@* ) {
if ($flow->{'type'} =~ /m\.login\.(.*)/) {
#$types .= "$flow->{'type'} ";
$types .= "$1 ";# if ($flow->{'type'} );
}
}
readingsBulkUpdate($hash, "logintypes", $types);
}
if ($def eq "filter"){
readingsBulkUpdate($hash, "filterId", $decoded->{'filter_id'}) if ($decoded->{'filter_id'});
}
if ($def eq "msg" ){
readingsBulkUpdate($hash, "eventId", $decoded->{'event_id'}) if ($decoded->{'event_id'});
#m.relates_to
}
if ($def eq "question"){
readingsBulkUpdate($hash, "questionId", $decoded->{'event_id'}) if ($decoded->{'event_id'});
#m.relates_to
}
if ($def eq "questionEnd"){
readingsBulkUpdate($hash, "eventId", $decoded->{'event_id'}) if ($decoded->{'event_id'});
readingsBulkUpdate($hash, "questionId", "") if ($decoded->{'event_id'});
#m.relates_to
}
}
readingsEndUpdate($hash, 1);
$hash->{helper}->{"busy"}--; # = $hash->{helper}->{"busy"} - 1; # queue is busy until response is received
$hash->{helper}->{"sync"}-- if ($def eq "sync"); # possible next sync
$nextRequest = "" if ($nextRequest eq "sync" && $hash->{helper}->{"sync"} > 0); # only one sync at a time!
# PerformHttpRequest or InternalTimer if FAIL >= 3
Log3($name, 4, "$name : Matrix::ParseHttpResponse $hash");
if (AttrVal($name,'matrixPoll',0) == 1){
if ($nextRequest ne "" && $hash->{helper}->{"softfail"} < 3) {
if ($nextRequest eq "sync" && $hash->{helper}->{"repeat"}){
$def = $hash->{helper}->{"repeat"}->{"def"};
$value = $hash->{helper}->{"repeat"}->{"value"};
$hash->{helper}->{"repeat"} = undef;
PerformHttpRequest($hash, $def, $value);
} else {
PerformHttpRequest($hash, $nextRequest, '');
}
} else {
my $pauseLogin;
if ($hash->{helper}->{"hardfail"} >= 3){
$pauseLogin = 300;
} elsif ($hash->{helper}->{"softfail"} >= 3){
$pauseLogin = 30;
} elsif ($hash->{helper}->{"softfail"} > 0){
$pauseLogin = 10;
} else {
$pauseLogin = 0;
}
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;
}
1; #(CoolTux) ein Modul endet immer mit 1;
__END__ #(CoolTux) Markiert im File das Ende des Programms. Danach darf beliebiger Text stehen. Dieser wird vom Perlinterpreter nicht berücksichtigt.

View File

@ -1,31 +0,0 @@
use strict;
use warnings;
use Test2::V0;
use Test2::Tools::Compare qw{is U};
InternalTimer(time()+1, sub() {
my %hash;
$hash{TEMPORARY} = 1;
$hash{NAME} = q{dummyMatrix};
$hash{TYPE} = q{Matrix server user};
$hash{STAE} = q{???};
subtest "Matrix Test checking define" => sub {
$hash{DEF} = "pass";
plan(2);
my $ret = Matrix_Define(\%hash,qq{$hash{NAME} $hash{TYPE}});
like ($ret, qr/too few parameters: define <name> Matrix <greet>/, 'check error message Matrix_Define');
$ret = Matrix_Define(\%hash,qq{$hash{NAME} $hash{TYPE} $hash{DEF}});
is ($ret, U(), 'check returnvalue Matrix_Define');
};
done_testing();
exit(0);
}, 0);
1;

View File

@ -1 +0,0 @@
define dummyMatrix Matrix matrix.web05.de