mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-10 09:16:53 +00:00
98_Modbus: updated tests
git-svn-id: https://svn.fhem.de/fhem/trunk@23501 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
d3f368e7cd
commit
197d9a220a
@ -23,7 +23,6 @@ package FHEM::Modbus::TestUtils;
|
|||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use GPUtils qw(:all);
|
use GPUtils qw(:all);
|
||||||
use Time::HiRes qw(gettimeofday);
|
use Time::HiRes qw(gettimeofday);
|
||||||
|
|
||||||
@ -70,33 +69,37 @@ BEGIN {
|
|||||||
our $testStep = 0;
|
our $testStep = 0;
|
||||||
our %testOptions;
|
our %testOptions;
|
||||||
our %results;
|
our %results;
|
||||||
our $nextStepMode = 'auto';
|
|
||||||
|
|
||||||
sub SimRead {
|
|
||||||
my $name = shift;
|
|
||||||
my $readFn = shift;
|
|
||||||
my $text = shift;
|
|
||||||
my $option = shift;
|
|
||||||
my $hash = $defs{$name};
|
|
||||||
my $data;
|
|
||||||
Log3 undef, 1, "Test simulate reception of $text";
|
|
||||||
if ($option && $option eq 'ASCII') {
|
|
||||||
$data = $text; # ascii
|
|
||||||
} else {
|
|
||||||
$data = pack ('H*', $text); # hex coded binary
|
|
||||||
}
|
|
||||||
$hash->{TestInput} = $data;
|
|
||||||
eval { &{$readFn}($hash) };
|
|
||||||
if ($@) {
|
|
||||||
Log3 undef, 1, "Test step $testStep call to readFn created error: $@";
|
|
||||||
} else {
|
|
||||||
Log3 undef, 1, "Test step $testStep readFn done.";
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
#
|
||||||
|
# NextStep
|
||||||
|
# - GetNextStep
|
||||||
|
# - set timer for CallStep or end Testing
|
||||||
|
#
|
||||||
|
# InternalTimer -> CallStep
|
||||||
|
# - step via eval
|
||||||
|
# - NextStep -> Timer for CallStep
|
||||||
|
# - step via eval
|
||||||
|
# - NextStep
|
||||||
|
#
|
||||||
|
# LogInform -> ReactOnLogRegex ->
|
||||||
|
# - InternalTimer for SimResponseRead
|
||||||
|
#
|
||||||
|
# InternalTimer -> SimResponseRead
|
||||||
|
# - SimResponseRead
|
||||||
|
# - NextStep -> Timer for CallStep
|
||||||
|
# - step via eval
|
||||||
|
# - send -> LogInform -> SimResponseRead ...
|
||||||
|
# - NextStep?? (don't set timer for next step in this case)
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
##################################################################
|
||||||
|
# find the next test step number
|
||||||
|
# internal function, called from NextStep
|
||||||
sub GetNextStep {
|
sub GetNextStep {
|
||||||
#Log3 undef, 1, "Test GetNextStep: look for next step";
|
Log3 undef, 1, "Test GetNextStep: look for next step";
|
||||||
my $next = $testStep;
|
my $next = $testStep;
|
||||||
FINDSTEP:
|
FINDSTEP:
|
||||||
while (1) {
|
while (1) {
|
||||||
@ -110,43 +113,144 @@ sub GetNextStep {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# set internalTimer to call the next test step after an optional delay
|
||||||
|
# normally in tests to have the first step called and
|
||||||
|
# also internally by CallStep and SimResponseRead
|
||||||
sub NextStep {
|
sub NextStep {
|
||||||
my $delay = shift // 0;
|
my $delay = shift // 0;
|
||||||
my $next = GetNextStep();
|
my $next = GetNextStep();
|
||||||
|
if (!$next || ($delay && $delay eq 'end')) { # done if no more steps
|
||||||
InternalTimer(gettimeofday() + $delay, \&CallStep, "main::testStep$next");
|
|
||||||
#Log3 undef, 1, "Test NextStep: done.";
|
|
||||||
$testStep = $next;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub CallStep {
|
|
||||||
my $func = shift;
|
|
||||||
Log3 undef, 1, "----------------------------------------------------";
|
|
||||||
Log3 undef, 1, "Test step $testStep";
|
|
||||||
|
|
||||||
no strict "refs"; ## no critic - function name needs to be string
|
|
||||||
my $delay = eval { &{$func}() };
|
|
||||||
if ($@) {
|
|
||||||
Log3 undef, 1, "Test step $testStep call created error: $@";
|
|
||||||
} else {
|
|
||||||
Log3 undef, 1, "Test step $testStep done.";
|
|
||||||
}
|
|
||||||
|
|
||||||
my $next = GetNextStep();
|
|
||||||
if (!$next) { # done if no more steps
|
|
||||||
Log3 undef, 1, "Test NextStep: no more steps found - exiting";
|
Log3 undef, 1, "Test NextStep: no more steps found - exiting";
|
||||||
done_testing;
|
done_testing;
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
if ($nextStepMode eq 'auto') {
|
if (!$delay || $delay ne 'wait') { # set timer to next step unless waiting for reception of data
|
||||||
NextStep($delay); # set timer to go to next step with delay returned by last
|
Log3 undef, 1, "Test NextStep: set timer to call step $next with delay $delay";
|
||||||
|
InternalTimer(gettimeofday() + $delay, \&CallStep, "main::testStep$next");
|
||||||
|
$testStep = $next;
|
||||||
|
}
|
||||||
|
Log3 undef, 1, "Test NextStep: done.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Call the Test step and then set the timer for the next one
|
||||||
|
# called by internalTimer
|
||||||
|
sub CallStep {
|
||||||
|
my $func = shift;
|
||||||
|
$func =~ /^(.*[A-Za-z]+)(\d+)$/;
|
||||||
|
my $step = $2;
|
||||||
|
Log3 undef, 1, "----------------------------------------------------";
|
||||||
|
Log3 undef, 1, "Test step $step ($func)";
|
||||||
|
|
||||||
|
no strict "refs"; ## no critic - function name needs to be string
|
||||||
|
my $delay = eval { &{$func}() }; # call the next step and check for errors
|
||||||
|
if ($@) {
|
||||||
|
Log3 undef, 1, "Test step $step call created error: $@";
|
||||||
|
} else {
|
||||||
|
Log3 undef, 1, "Test step $step ($func) done, delay before next step is $delay";
|
||||||
|
}
|
||||||
|
# if step function returns 'wait' then do not set timer for next step but wait for ReactOnLogRegex or similar
|
||||||
|
NextStep($delay); # check for next step and set timer or end testing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# check if a regex is found in logs (typically the sending of a request)
|
||||||
|
# and call SmResponseRead via timer to simulate the reception of a response
|
||||||
|
# called via logInform
|
||||||
|
sub ReactOnLogRegex {
|
||||||
|
my $name = shift;
|
||||||
|
my $line = shift;
|
||||||
|
#die "line got: $line";
|
||||||
|
if ($line =~ /$testOptions{RespondTo}/) {
|
||||||
|
my $send = $1;
|
||||||
|
my $id = substr ($send, 0, 2);
|
||||||
|
my $recv = $testOptions{ResponseHash}{$send}; # simulate broken error response by default
|
||||||
|
if (!$recv) {
|
||||||
|
$recv = ($id . '800041c0');
|
||||||
|
Log3 undef, 1, "Test: request $send is not in Reply hash, respond with default error instead";
|
||||||
|
}
|
||||||
|
my $delay = $testOptions{ResponseDelay} // 0.05;
|
||||||
|
Log3 undef, 1, "------------------------------------------------------------------------";
|
||||||
|
Log3 undef, 1, "Test saw sending $send, id $id, set timer to simulate receiving $recv in $delay";
|
||||||
|
InternalTimer(gettimeofday() + $delay, \&SimResponseRead, $recv); # set timer to simulate response and go to next step
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################################################
|
||||||
|
# simulate the reception of a response by calling SimRead
|
||||||
|
# and then setting the timer for the next step.
|
||||||
|
# todo: delay should be definable
|
||||||
|
sub SimResponseRead {
|
||||||
|
my $data = shift;
|
||||||
|
Log3 undef, 1, "Test now simulates reception of response and then checks for next step";
|
||||||
|
SimRead($testOptions{IODevice}, $data);
|
||||||
|
NextStep($testOptions{delayAfterResponse} // 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# interface to set options hash
|
||||||
|
# used options:
|
||||||
|
# - delayAfterResponse : time in seconds to wait after a simualted response before the next step function is called
|
||||||
|
# - IODevice : name of the device for sending and receiving
|
||||||
|
# - RespondTo : Regex to be used when monitoring the Fhem log and reacting on a "sending" log with a simulated reception
|
||||||
|
# - ResponseHash : Hash that maps from data sent (as found in log) to a valid response for the simulation
|
||||||
|
# - ResponseDelay : delay before the reception of a response is sumulated
|
||||||
|
# - Time1Regex and Time1Name : name and regex to be searched in log to find the time when it was logged, used by calcDelays
|
||||||
|
# - Time2Regex and Time2Name : name and regex to be searched in log to find the time when it was logged, used by calcDelays
|
||||||
|
sub SetTestOptions {
|
||||||
|
my $opt = shift;
|
||||||
|
foreach my $k (keys %{$opt}) {
|
||||||
|
$testOptions{$k} = $opt->{$k};
|
||||||
|
}
|
||||||
|
if ($testOptions{RespondTo}) {
|
||||||
|
$logInform{$testOptions{IODevice}} = \&ReactOnLogRegex;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
# simulate reading from a device.
|
||||||
|
# the device should be defined with 'none' as interface
|
||||||
|
# and the readFn should take data from $hash->{TestInput}
|
||||||
|
# in this case
|
||||||
|
sub SimRead {
|
||||||
|
my $name = shift; # Name of the io device that should read data
|
||||||
|
my $input = shift; # binary input string (coded as hex-string) to be read
|
||||||
|
my $option = shift; # further otions (so far only 'ASCII' to treat the input string as text instead of hex)
|
||||||
|
my $hash = $defs{$name};
|
||||||
|
my $data;
|
||||||
|
Log3 undef, 1, "Test simulate reception of $input";
|
||||||
|
if ($option && $option eq 'ASCII') {
|
||||||
|
$data = $input; # ascii
|
||||||
|
} else {
|
||||||
|
$data = pack ('H*', $input); # hex coded binary
|
||||||
|
}
|
||||||
|
$hash->{TestInput} = $data;
|
||||||
|
my $type = $defs{$name}{TYPE};
|
||||||
|
my $modHash = $modules{$type};
|
||||||
|
my $readFn = $modHash->{ReadFn};
|
||||||
|
eval { &{$readFn}($hash) };
|
||||||
|
if ($@) {
|
||||||
|
Log3 undef, 1, "Test step $testStep call to readFn created error: $@";
|
||||||
|
} else {
|
||||||
|
Log3 undef, 1, "Test step $testStep readFn done.";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################
|
||||||
|
# wrapper for Log3 to be used in tests
|
||||||
sub LogStep {
|
sub LogStep {
|
||||||
my $msg = shift // '';
|
my $msg = shift // '';
|
||||||
Log3 undef, 1, "Test step $testStep: $msg";
|
Log3 undef, 1, "Test step $testStep: $msg";
|
||||||
@ -154,43 +258,8 @@ sub LogStep {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub ReactOnSendingLog {
|
###########################################################################
|
||||||
my $name = shift;
|
# find the time of two regexes in the log
|
||||||
my $line = shift;
|
|
||||||
#die "line got: $line";
|
|
||||||
if ($line =~ /$testOptions{RespondTo}/) {
|
|
||||||
my $send = $1;
|
|
||||||
my $id = substr ($send, 0, 2);
|
|
||||||
my $recv = $testOptions{ReplyHash}{$send} // (($id . '800041c0')); # simulate broken error response by default
|
|
||||||
my $delay = $testOptions{ResponseDelay} // 0.05;
|
|
||||||
Log3 undef, 1, "------------------------------------------------------------------------";
|
|
||||||
Log3 undef, 1, "Test saw sending $send, id $id, set timer to simulate receiving $recv in $delay";
|
|
||||||
InternalTimer(gettimeofday() + $delay, \&SimResponseRead, $recv);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub SimResponseRead {
|
|
||||||
my $data = shift;
|
|
||||||
Log3 undef, 1, "Test now simulate reception of response and then call next step";
|
|
||||||
SimRead($testOptions{IODevice}, $testOptions{ReadFn}, $data);
|
|
||||||
NextStep();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub SetTestOptions {
|
|
||||||
my $opt = shift;
|
|
||||||
foreach my $k (keys %{$opt}) {
|
|
||||||
$testOptions{$k} = $opt->{$k};
|
|
||||||
}
|
|
||||||
if ($testOptions{RespondTo}) {
|
|
||||||
$nextStepMode = 'reception';
|
|
||||||
$logInform{$testOptions{IODevice}} = \&ReactOnSendingLog;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub findTimesInLog {
|
sub findTimesInLog {
|
||||||
$results{$testOptions{Time1Name}.$testStep} = FhemTestUtils_getLogTime($testOptions{Time1Regex});
|
$results{$testOptions{Time1Name}.$testStep} = FhemTestUtils_getLogTime($testOptions{Time1Regex});
|
||||||
$results{$testOptions{Time2Name}.$testStep} = FhemTestUtils_getLogTime($testOptions{Time2Regex});
|
$results{$testOptions{Time2Name}.$testStep} = FhemTestUtils_getLogTime($testOptions{Time2Regex});
|
||||||
@ -202,6 +271,8 @@ sub findTimesInLog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# calculate and log the time differences found by calling findTimesInLog
|
||||||
sub calcDelays {
|
sub calcDelays {
|
||||||
my ($lastDelay, $commDelay, $sendDelay);
|
my ($lastDelay, $commDelay, $sendDelay);
|
||||||
if (defined ($results{$testOptions{Time1Name} . $testStep}) &&
|
if (defined ($results{$testOptions{Time1Name} . $testStep}) &&
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
##############################################
|
##############################################
|
||||||
# test update timer
|
# test update timer
|
||||||
##############################################
|
##############################################
|
||||||
|
package main;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Test::More;
|
use Test::More;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
##############################################
|
##############################################
|
||||||
# test request parsing
|
# test communication delays
|
||||||
##############################################
|
##############################################
|
||||||
package main;
|
package main;
|
||||||
use strict;
|
use strict;
|
||||||
@ -35,20 +35,19 @@ my %rData = (
|
|||||||
fhem 'attr global mseclog 1';
|
fhem 'attr global mseclog 1';
|
||||||
|
|
||||||
SetTestOptions(
|
SetTestOptions(
|
||||||
{ IODevice => 'MS', # for loginform
|
{ IODevice => 'MS', # for loginform
|
||||||
RespondTo => 'MS: Simulate sending to none: (.*)', # auto reponder / go to next step at reception
|
RespondTo => 'MS: Simulate sending to none: (.*)', # auto reponder / go to next step at reception
|
||||||
ReadFn => \&Modbus::ReadFn, # call for reception
|
ResponseHash => \%rData, # to find the right response
|
||||||
ReplyHash => \%rData, # to find the right response
|
|
||||||
|
|
||||||
Time1Name => 'Sending',
|
Time1Name => 'Sending',
|
||||||
Time1Regex => qr{MS:\sSimulate\ssending},
|
Time1Regex => qr{MS:\sSimulate\ssending},
|
||||||
Time2Name => 'Reception',
|
Time2Name => 'Reception',
|
||||||
Time2Regex => qr{ParseFrameStart\s\(RTU\)\sextracted\sid},
|
Time2Regex => qr{ParseFrameStart\s\(RTU\)\sextracted\sid},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
fhem 'get M1 SolarTemp';
|
fhem 'get M1 SolarTemp'; # will cause step 1 to be called when send is detected and response is simulated
|
||||||
|
|
||||||
sub testStep1 {
|
sub testStep1 {
|
||||||
findTimesInLog();
|
findTimesInLog();
|
||||||
@ -59,7 +58,7 @@ sub testStep1 {
|
|||||||
fhem 'get M1 HeatOff';
|
fhem 'get M1 HeatOff';
|
||||||
# read simulation is triggered when sending is seen in the log.
|
# read simulation is triggered when sending is seen in the log.
|
||||||
# next step is called when read simulation is done.
|
# next step is called when read simulation is done.
|
||||||
return;
|
return 'wait';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -73,7 +72,7 @@ sub testStep2 {
|
|||||||
|
|
||||||
fhem 'attr M1 dev-timing-sendDelay 0.2'; # send in step2 should be 0.2 after send in step1
|
fhem 'attr M1 dev-timing-sendDelay 0.2'; # send in step2 should be 0.2 after send in step1
|
||||||
fhem 'get M1 HeatOff';
|
fhem 'get M1 HeatOff';
|
||||||
return;
|
return 'wait';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -84,10 +83,10 @@ sub testStep3 {
|
|||||||
|
|
||||||
# check send delay between read (get HeatOff) after Step 1 and send (get HeatOff) in step 2
|
# check send delay between read (get HeatOff) after Step 1 and send (get HeatOff) in step 2
|
||||||
ok($sendDelay >= 0.2, 'defined send delay from read HeatOff to next send get HeatOff big enough');
|
ok($sendDelay >= 0.2, 'defined send delay from read HeatOff to next send get HeatOff big enough');
|
||||||
ok($sendDelay < 0.22, 'defined send delay from read HeatOff to next send get HeatOff not too big');
|
ok($sendDelay < 0.25, 'defined send delay from read HeatOff to next send get HeatOff not too big');
|
||||||
|
|
||||||
fhem 'get M5 TempWasserEin';
|
fhem 'get M5 TempWasserEin';
|
||||||
return;
|
return 'wait';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -97,11 +96,11 @@ sub testStep4 {
|
|||||||
my ($commDelay, $sendDelay) = calcDelays();
|
my ($commDelay, $sendDelay) = calcDelays();
|
||||||
|
|
||||||
# check no send delay between read (get HeatOff) after Step 2 and send (get TempWasserEin to id 5) in step 3
|
# check no send delay between read (get HeatOff) after Step 2 and send (get TempWasserEin to id 5) in step 3
|
||||||
ok($sendDelay < 0.1, 'defined send delay on id 1 from read HeatOff to send get TempWasserEin not used for id 5');
|
ok($sendDelay < 0.15, 'defined send delay on id 1 from read HeatOff to send get TempWasserEin not used for id 5');
|
||||||
|
|
||||||
fhem 'attr MS busDelay 0.2';
|
fhem 'attr MS busDelay 0.2';
|
||||||
fhem 'get M5 TempWasserAus';
|
fhem 'get M5 TempWasserAus'; # new request, go to next step when response is simulated
|
||||||
return;
|
return 'wait';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -117,8 +116,8 @@ sub testStep5 {
|
|||||||
fhem 'attr MS busDelay 0';
|
fhem 'attr MS busDelay 0';
|
||||||
fhem 'attr M1 dev-timing-sendDelay 0';
|
fhem 'attr M1 dev-timing-sendDelay 0';
|
||||||
fhem 'attr MS clientSwitchDelay 0';
|
fhem 'attr MS clientSwitchDelay 0';
|
||||||
fhem 'get M1 SolarTemp';
|
fhem 'get M1 SolarTemp'; # new request, go to next step when response is simulated
|
||||||
return;
|
return 'wait';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -129,8 +128,8 @@ sub testStep6 {
|
|||||||
|
|
||||||
ok($sendDelay < 0.2, 'no delay');
|
ok($sendDelay < 0.2, 'no delay');
|
||||||
fhem 'attr MS clientSwitchDelay 0.2';
|
fhem 'attr MS clientSwitchDelay 0.2';
|
||||||
fhem 'get M5 TempWasserEin';
|
fhem 'get M5 TempWasserEin'; # new request, go to next step when response is simulated
|
||||||
return;
|
return 'wait';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -142,8 +141,8 @@ sub testStep7 {
|
|||||||
ok($commDelay >= 0.2, 'defined clsw delay big enough');
|
ok($commDelay >= 0.2, 'defined clsw delay big enough');
|
||||||
ok($commDelay < 0.3, 'defined clsw delay not too big');
|
ok($commDelay < 0.3, 'defined clsw delay not too big');
|
||||||
|
|
||||||
fhem 'get M5 TempWasserAus';
|
fhem 'get M5 TempWasserAus'; # new request, go to next step when response is simulated
|
||||||
return;
|
return 'wait';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -152,11 +151,11 @@ sub testStep8 {
|
|||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
my ($commDelay, $sendDelay) = calcDelays();
|
my ($commDelay, $sendDelay) = calcDelays();
|
||||||
|
|
||||||
ok($sendDelay < 0.1, 'no delay for same id');
|
ok($sendDelay < 0.2, 'no delay for same id');
|
||||||
|
|
||||||
fhem 'attr M5 dev-timing-commDelay 0.2';
|
fhem 'attr M5 dev-timing-commDelay 0.2';
|
||||||
fhem 'get M5 TempWasserEin';
|
fhem 'get M5 TempWasserEin'; # new request, go to next step when response is simulated
|
||||||
return;
|
return 'wait';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -169,8 +168,8 @@ sub testStep9 {
|
|||||||
ok($commDelay < 0.22, 'defined comm delay not too big');
|
ok($commDelay < 0.22, 'defined comm delay not too big');
|
||||||
|
|
||||||
fhem 'attr M5 dev-timing-commDelay 0';
|
fhem 'attr M5 dev-timing-commDelay 0';
|
||||||
fhem 'get M5 TempWasserEin';
|
fhem 'get M5 TempWasserEin'; # new request, go to next step when response is simulated
|
||||||
return;
|
return 'wait';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -183,8 +182,8 @@ sub testStep10 {
|
|||||||
|
|
||||||
fhem 'attr M5 dev-timing-commDelay 0.2';
|
fhem 'attr M5 dev-timing-commDelay 0.2';
|
||||||
fhem 'attr M5 verbose 4';
|
fhem 'attr M5 verbose 4';
|
||||||
fhem 'set M5 o1 on';
|
fhem 'set M5 o1 on'; # new request, go to next step when response is simulated
|
||||||
return;
|
return 'wait';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ define D1 dummy
|
|||||||
|
|
||||||
define Slave ModbusAttr 5 slave global:5501
|
define Slave ModbusAttr 5 slave global:5501
|
||||||
attr Slave obj-h256-reading TempWasserEin
|
attr Slave obj-h256-reading TempWasserEin
|
||||||
attr Slave obj-h258-reading D1:TempWasserAus
|
attr Slave obj-h258-reading TempWasserAus
|
||||||
|
|
||||||
attr Slave obj-h100-reading Test1
|
attr Slave obj-h100-reading Test1
|
||||||
attr Slave obj-h100-setexpr $val * 4
|
attr Slave obj-h100-setexpr $val * 4
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
##############################################
|
##############################################
|
||||||
# test master slave end to end
|
# test open delays
|
||||||
# attr disable
|
|
||||||
# and set inactive / set active
|
|
||||||
##############################################
|
##############################################
|
||||||
package main;
|
package main;
|
||||||
use strict;
|
use strict;
|
||||||
@ -9,14 +7,14 @@ use warnings;
|
|||||||
use Test::More;
|
use Test::More;
|
||||||
use Time::HiRes qw( gettimeofday tv_interval); # return time as float, not just full seconds
|
use Time::HiRes qw( gettimeofday tv_interval); # return time as float, not just full seconds
|
||||||
use FHEM::HTTPMOD::Utils qw(:all);
|
use FHEM::HTTPMOD::Utils qw(:all);
|
||||||
|
use FHEM::Modbus::TestUtils qw(:all);
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
||||||
my $closeTime;
|
my $closeTime;
|
||||||
my $openTime;
|
my $openTime;
|
||||||
my $startTime;
|
my $startTime;
|
||||||
|
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep1", 0);
|
NextStep();
|
||||||
|
|
||||||
|
|
||||||
sub getLogTime {
|
sub getLogTime {
|
||||||
my $regex = shift;
|
my $regex = shift;
|
||||||
@ -27,51 +25,42 @@ sub getLogTime {
|
|||||||
return $time;
|
return $time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub testStep1 { # preparation of slave content, enable devices
|
sub testStep1 { # preparation of slave content, enable devices
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
#is(FhemTestUtils_gotLog('attribute'), 0, "no unknown attributes"); # logs during init are not collected.
|
#is(FhemTestUtils_gotLog('attribute'), 0, "no unknown attributes"); # logs during init are not collected.
|
||||||
Log3 undef, 1, "TestStep1: enable Master and set value at Slave";
|
LogStep "TestStep1: enable Master and set value at Slave";
|
||||||
fhem ('attr Master disable 0');
|
fhem ('attr Master disable 0');
|
||||||
fhem ('setreading Slave TempWasserEin 12');
|
fhem ('setreading Slave TempWasserEin 12');
|
||||||
|
fhem ('setreading Slave TempWasserAus 23');
|
||||||
fhem ('setreading Slave Test1 1');
|
fhem ('setreading Slave Test1 1');
|
||||||
fhem ('setreading Slave Test2 2.123');
|
fhem ('setreading Slave Test2 2.123');
|
||||||
fhem ('setreading Slave Test3 abcdefg');
|
fhem ('setreading Slave Test3 abcdefg');
|
||||||
fhem ('setreading Slave Test4 40');
|
fhem ('setreading Slave Test4 40');
|
||||||
|
return 0.1;
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep2", 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep2 { # get holding registers
|
sub testStep2 { # get holding registers
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep2: get TempWasserEin";
|
|
||||||
fhem ('attr Master verbose 5');
|
fhem ('attr Master verbose 5');
|
||||||
fhem ('attr Slave verbose 3');
|
fhem ('attr Slave verbose 3');
|
||||||
fhem ('get Master TempWasserEin');
|
fhem ('get Master TempWasserEin');
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep3", 0);
|
return 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep3 { # check first result, disable and request again
|
sub testStep3 { # check first result, disable and request again
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep3: check result, disable master and request again";
|
|
||||||
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 1, "Retrieve integer value from local slave");
|
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 1, "Retrieve integer value from local slave");
|
||||||
FhemTestUtils_resetEvents();
|
FhemTestUtils_resetEvents();
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
fhem ('attr Master disable 1');
|
fhem ('attr Master disable 1');
|
||||||
fhem ('get Master TempWasserEin');
|
fhem ('get Master TempWasserEin');
|
||||||
|
return;
|
||||||
InternalTimer(gettimeofday(), "testStep4", 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep4 {
|
sub testStep4 {
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep4: check that master disable worked";
|
|
||||||
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 0, "no Retrieve for disabled");
|
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 0, "no Retrieve for disabled");
|
||||||
is(FhemTestUtils_gotEvent(qr/Master:disabled/xms), 1, "state disabled");
|
is(FhemTestUtils_gotEvent(qr/Master:disabled/xms), 1, "state disabled");
|
||||||
fhem ('attr Master disable 0');
|
fhem ('attr Master disable 0');
|
||||||
FhemTestUtils_resetEvents();
|
FhemTestUtils_resetEvents();
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep5", 0);
|
return 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep5 {
|
sub testStep5 {
|
||||||
@ -80,44 +69,38 @@ sub testStep5 {
|
|||||||
$startTime = getLogTime ('Master device opened');
|
$startTime = getLogTime ('Master device opened');
|
||||||
fhem ('attr Master enableSetInactive 1');
|
fhem ('attr Master enableSetInactive 1');
|
||||||
fhem ('set Master inactive');
|
fhem ('set Master inactive');
|
||||||
InternalTimer(gettimeofday(), "testStep6", 0);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep6 {
|
sub testStep6 {
|
||||||
Log3 undef, 1, "----------------";
|
Log3 undef, 1, "----------------";
|
||||||
Log3 undef, 1, "TestStep6: now try to get reading again";
|
Log3 undef, 1, "TestStep6: now try to get reading again";
|
||||||
fhem ('get Master TempWasserEin');
|
fhem ('get Master TempWasserEin');
|
||||||
InternalTimer(gettimeofday(), "testStep7a", 0);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep7a {
|
sub testStep7 {
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep7a: check if reading was not requested and then set master to active again";
|
|
||||||
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 0, "no Retrieve for inactive");
|
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 0, "no Retrieve for inactive");
|
||||||
FhemTestUtils_resetEvents();
|
FhemTestUtils_resetEvents();
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
fhem ('attr Master nextOpenDelay2 0'); # don't wait with open
|
fhem ('attr Master nextOpenDelay2 0'); # don't wait with open
|
||||||
fhem ('set Master active');
|
fhem ('set Master active');
|
||||||
InternalTimer(gettimeofday(), "testStep7b", 0);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep7b {
|
sub testStep8 {
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep7b: try retrieve again";
|
|
||||||
$openTime = getLogTime ('Master device opened');
|
$openTime = getLogTime ('Master device opened');
|
||||||
Log3 undef, 1, "TestStep7b: Time diff is " . sprintf ('%.3f', $openTime - $startTime);
|
Log3 undef, 1, "Test: Time diff is " . sprintf ('%.3f', $openTime - $startTime);
|
||||||
ok($openTime - $startTime < 0.25, 'time between two open calls is smaller than 0.25');
|
ok($openTime - $startTime < 0.25, 'time between two open calls is smaller than 0.25');
|
||||||
FhemTestUtils_resetEvents();
|
FhemTestUtils_resetEvents();
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
fhem ('get Master TempWasserEin');
|
fhem ('get Master TempWasserAus');
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep8", 0);
|
return 0.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub testStep8 {
|
sub testStep9 {
|
||||||
Log3 undef, 1, "----------------";
|
is(FhemTestUtils_gotEvent(qr/Master:TempWasserAus:\s23/xms), 1, "Retrieve integer value again from local slave");
|
||||||
Log3 undef, 1, "TestStep8: check result and then set slave to inactive and try again";
|
|
||||||
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 1, "Retrieve integer value again from local slave");
|
|
||||||
fhem ('set Slave inactive');
|
fhem ('set Slave inactive');
|
||||||
FhemTestUtils_resetEvents();
|
FhemTestUtils_resetEvents();
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
@ -126,94 +109,53 @@ sub testStep8 {
|
|||||||
fhem ('attr Master nextOpenDelay2 0.1'); #
|
fhem ('attr Master nextOpenDelay2 0.1'); #
|
||||||
fhem ('attr Master nextOpenDelay 1'); # can not be smaller than 1
|
fhem ('attr Master nextOpenDelay 1'); # can not be smaller than 1
|
||||||
fhem ('get Master TempWasserEin'); # should run into timeout
|
fhem ('get Master TempWasserEin'); # should run into timeout
|
||||||
InternalTimer(gettimeofday()+0.5, "testStep8b", 0);
|
return 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep8b {
|
sub testStep10 {
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep8b: check that request was not answered and get last open time";
|
|
||||||
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 0, "no Retrieve for inactive Slave");
|
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 0, "no Retrieve for inactive Slave");
|
||||||
#is(FhemTestUtils_gotLog('Master: Timeout waiting for a modbus response'), 1, "saw timeout");
|
#is(FhemTestUtils_gotLog('Master: Timeout waiting for a modbus response'), 1, "saw timeout");
|
||||||
$startTime = getLogTime ('HttpUtils url=http://localhost:5501'); # time of first try
|
$startTime = getLogTime ('HttpUtils url=http://localhost:5501'); # time of first try
|
||||||
fhem ('set Slave active');
|
fhem ('set Slave active');
|
||||||
InternalTimer(gettimeofday()+1, "testStep8c", 0);
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub testStep8c {
|
sub testStep11 {
|
||||||
Log3 undef, 1, "----------------";
|
return 1.0;
|
||||||
Log3 undef, 1, "TestStep8c: ";
|
|
||||||
InternalTimer(gettimeofday()+1, "testStep9a", 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub testStep9a {
|
sub testStep12 {
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep9a: check nextOpenDelay";
|
|
||||||
$openTime = getLogTime ('5501 reappeared');
|
$openTime = getLogTime ('5501 reappeared');
|
||||||
Log3 undef, 1, "TestStep7b: Time diff is " . sprintf ('%.3f', $openTime - $startTime);
|
Log3 undef, 1, "TestStep12: Time diff is " . sprintf ('%.3f', $openTime - $startTime);
|
||||||
ok($openTime - $startTime >= 1, 'time between two open calls is bigger than 1');
|
ok($openTime - $startTime >= 1, 'time between two open calls is bigger than 1');
|
||||||
ok($openTime - $startTime < 2, 'time between two open calls is smaller than 2');
|
ok($openTime - $startTime < 2, 'time between two open calls is smaller than 2');
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep9b", 0);
|
return 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep9b {
|
sub testStep13 {
|
||||||
Log3 undef, 1, "----------------";
|
return;
|
||||||
Log3 undef, 1, "TestStep9b: ";
|
|
||||||
InternalTimer(gettimeofday(), "testStep9c", 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep9c {
|
sub testStep14 {
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep9b: retrieve value and then let Slave close after inactivity timeout";
|
|
||||||
# now open should happen and event should come
|
# now open should happen and event should come
|
||||||
fhem('attr Slave dev-timing-serverTimeout 1');
|
fhem('attr Slave dev-timing-serverTimeout 1');
|
||||||
fhem('attr Slave dev-timing-serverTimeout 1');
|
fhem('attr Slave dev-timing-serverTimeout 1');
|
||||||
FhemTestUtils_resetEvents();
|
FhemTestUtils_resetEvents();
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
fhem ('get Master TempWasserEin');
|
fhem ('get Master TempWasserEin');
|
||||||
InternalTimer(gettimeofday() + 1.1, "testStep10", 0);
|
return 1.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep10 {
|
sub testStep15 {
|
||||||
# check that we now got the value
|
# check that we now got the value
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep10: check successful retrieve after slave is active again and master did open connection";
|
|
||||||
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 1, "Retrieve integer value again from local slave");
|
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 1, "Retrieve integer value again from local slave");
|
||||||
InternalTimer(gettimeofday() + 0.5, "testStep11", 0);
|
return 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep11 {
|
sub testStep16 {
|
||||||
Log3 undef, 1, "----------------";
|
return;
|
||||||
Log3 undef, 1, "TestStep11:";
|
|
||||||
InternalTimer(gettimeofday() + 1, "testStep12", 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep12 {
|
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep12:";
|
|
||||||
InternalTimer(gettimeofday() + 1, "testStep13", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub testStep13 {
|
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep13:";
|
|
||||||
InternalTimer(gettimeofday(), "testStepEnd", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub testStepX {
|
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStepX: ";
|
|
||||||
#fhem ('get ');
|
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStepEnd", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub testStepEnd {
|
|
||||||
done_testing;
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
##############################################
|
##############################################
|
||||||
# test request parsing
|
# test queue delays
|
||||||
##############################################
|
##############################################
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
@ -13,7 +13,6 @@ fhem 'attr global mseclog 1';
|
|||||||
|
|
||||||
SetTestOptions(
|
SetTestOptions(
|
||||||
{ IODevice => 'MS', # for loginform
|
{ IODevice => 'MS', # for loginform
|
||||||
#RespondTo => 'MS: Simulate sending to none: (.*)', # auto reponder / go to next step at reception
|
|
||||||
Time1Name => 'busy',
|
Time1Name => 'busy',
|
||||||
Time1Regex => qr{Fhem is still waiting},
|
Time1Regex => qr{Fhem is still waiting},
|
||||||
Time2Name => 'queue run',
|
Time2Name => 'queue run',
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
##############################################
|
##############################################
|
||||||
# test master slave end to end
|
# test attr disable
|
||||||
# attr disable
|
|
||||||
# and set inactive / set active
|
# and set inactive / set active
|
||||||
##############################################
|
##############################################
|
||||||
use strict;
|
use strict;
|
||||||
@ -8,102 +7,62 @@ use warnings;
|
|||||||
use Test::More;
|
use Test::More;
|
||||||
use Time::HiRes qw(gettimeofday tv_interval); # return time as float, not just full seconds
|
use Time::HiRes qw(gettimeofday tv_interval); # return time as float, not just full seconds
|
||||||
use FHEM::HTTPMOD::Utils qw(:all);
|
use FHEM::HTTPMOD::Utils qw(:all);
|
||||||
|
use FHEM::Modbus::TestUtils qw(:all);
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep1", 0);
|
NextStep();
|
||||||
|
|
||||||
|
|
||||||
sub testStep1 {
|
sub testStep1 {
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep1: define Master over MS";
|
|
||||||
|
|
||||||
fhem ('define Master ModbusAttr 5 0');
|
fhem ('define Master ModbusAttr 5 0');
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep2", 0);
|
return 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep2 {
|
sub testStep2 {
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep2: ";
|
|
||||||
is(FhemTestUtils_gotLog('registers Master at MS with id 5, MODE master, PROTOCOL RTU'), 1, "Master registered");
|
is(FhemTestUtils_gotLog('registers Master at MS with id 5, MODE master, PROTOCOL RTU'), 1, "Master registered");
|
||||||
fhem ('define Master2 ModbusAttr 4 0');
|
fhem ('define Master2 ModbusAttr 4 0');
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep3", 0);
|
return 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep3 {
|
sub testStep3 {
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep3: ";
|
|
||||||
is(FhemTestUtils_gotLog('registers Master2 at MS with id 4, MODE master, PROTOCOL RTU'), 1, "Master2 registered");
|
is(FhemTestUtils_gotLog('registers Master2 at MS with id 4, MODE master, PROTOCOL RTU'), 1, "Master2 registered");
|
||||||
fhem ('define Master3 ModbusAttr 4 0 ASCII');
|
fhem ('define Master3 ModbusAttr 4 0 ASCII');
|
||||||
fhem ('attr Master3 enableSetInactive 1');
|
fhem ('attr Master3 enableSetInactive 1');
|
||||||
fhem ('attr Master3 verbose 5');
|
fhem ('attr Master3 verbose 5');
|
||||||
fhem ('attr Master3 obj-h100-reading test');
|
fhem ('attr Master3 obj-h100-reading test');
|
||||||
fhem ('attr Master3 obj-h100-showGet 1');
|
fhem ('attr Master3 obj-h100-showGet 1');
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep4", 0);
|
return 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep4 {
|
sub testStep4 {
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep4: ";
|
|
||||||
is(FhemTestUtils_gotLog('Master3: SetIODev found no usable physical modbus device'), 1, "No IODev for Master3 (MS already locked as RTU)");
|
is(FhemTestUtils_gotLog('Master3: SetIODev found no usable physical modbus device'), 1, "No IODev for Master3 (MS already locked as RTU)");
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
fhem ('attr Master disable 1');
|
fhem ('attr Master disable 1');
|
||||||
fhem ('get Master3 test');
|
fhem ('get Master3 test');
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep5", 0);
|
return 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep5 {
|
sub testStep5 {
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep5: ";
|
|
||||||
is(FhemTestUtils_gotLog('Master3: SetIODev found no usable physical modbus device'), 1, "No IODev for Master3 (MS still locked as RTU)");
|
is(FhemTestUtils_gotLog('Master3: SetIODev found no usable physical modbus device'), 1, "No IODev for Master3 (MS still locked as RTU)");
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
fhem ('attr Master2 disable 1');
|
fhem ('attr Master2 disable 1');
|
||||||
fhem ('get Master3 test');
|
fhem ('get Master3 test');
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep6", 0);
|
return 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep6 {
|
sub testStep6 {
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep6: ";
|
|
||||||
is(FhemTestUtils_gotLog('registers Master3 at MS with id 4, MODE master, PROTOCOL ASCII'), 1, "Now MS is locked as ASCII");
|
is(FhemTestUtils_gotLog('registers Master3 at MS with id 4, MODE master, PROTOCOL ASCII'), 1, "Now MS is locked as ASCII");
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
fhem ('define Slave1 ModbusAttr 10 slave ASCII');
|
fhem ('define Slave1 ModbusAttr 10 slave ASCII');
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep7", 0);
|
return 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep7 {
|
sub testStep7 {
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep7: ";
|
|
||||||
is(FhemTestUtils_gotLog('Slave1: SetIODev found no usable physical modbus device'), 1, "no io device for slave");
|
is(FhemTestUtils_gotLog('Slave1: SetIODev found no usable physical modbus device'), 1, "no io device for slave");
|
||||||
fhem ('delete Slave1');
|
fhem ('delete Slave1');
|
||||||
fhem ('attr Master3 disable 1');
|
fhem ('attr Master3 disable 1');
|
||||||
fhem ('define Slave1 ModbusAttr 10 slave ASCII');
|
fhem ('define Slave1 ModbusAttr 10 slave ASCII');
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep8", 0);
|
return 0.1;
|
||||||
}
|
}
|
||||||
sub testStep8 {
|
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep8: ";
|
|
||||||
is(FhemTestUtils_gotLog('registers Slave1 at MS with id 10, MODE slave, PROTOCOL ASCII'), 1, "now slave can use MS as IO Device");
|
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep9", 0);
|
|
||||||
}
|
|
||||||
sub testStep9 {
|
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep9: ";
|
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStep10", 0);
|
|
||||||
}
|
|
||||||
sub testStep10 {
|
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStep10: ";
|
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStepEnd", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub testStepX {
|
|
||||||
Log3 undef, 1, "----------------";
|
|
||||||
Log3 undef, 1, "TestStepX: ";
|
|
||||||
#fhem ('get ');
|
|
||||||
InternalTimer(gettimeofday() + 0.1, "testStepEnd", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub testStepEnd {
|
|
||||||
done_testing;
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -11,56 +11,28 @@ use Time::HiRes qw( gettimeofday tv_interval); # return time as flo
|
|||||||
use FHEM::HTTPMOD::Utils qw(:all);
|
use FHEM::HTTPMOD::Utils qw(:all);
|
||||||
use FHEM::Modbus::TestUtils qw(:all);
|
use FHEM::Modbus::TestUtils qw(:all);
|
||||||
|
|
||||||
#$logInform{'MS'} = \&ReactOnSendingLog;
|
|
||||||
|
|
||||||
my @rData = (
|
|
||||||
|
|
||||||
'05030100000585b1', # request h 256 - h 260 (TempWasserEin, TempWasserAus)
|
|
||||||
'05030a0137110001381100010dac7b', # response
|
|
||||||
|
|
||||||
'0503010600016473', # request h 262
|
|
||||||
'0503020106c816', # response
|
|
||||||
|
|
||||||
'050303020001240a', # request h 770
|
|
||||||
'0503020122c80d', # response
|
|
||||||
|
|
||||||
'05030309000155c8', # request
|
|
||||||
'05030200004984', # response
|
|
||||||
|
|
||||||
'0503010000018472',
|
|
||||||
'050302013709c2', # response
|
|
||||||
|
|
||||||
'0506030900005808', # request set hyst mode
|
|
||||||
'0506030900005808', # response
|
|
||||||
|
|
||||||
'0506030201182850', # request set temp soll 28
|
|
||||||
'0506030201182850' # response
|
|
||||||
);
|
|
||||||
my $dataPtr = 0;
|
|
||||||
|
|
||||||
fhem 'attr global mseclog 1';
|
fhem 'attr global mseclog 1';
|
||||||
InternalTimer(gettimeofday()+5, "testStepLast", 0); # last resort
|
|
||||||
NextStep();
|
NextStep();
|
||||||
|
|
||||||
|
|
||||||
sub testStep1 {
|
sub testStep1 {
|
||||||
LogStep "send first request in parts";
|
LogStep "send first request in parts";
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
SimRead('MS', \&Modbus::ReadFn, 'fe03'); # part of a request
|
SimRead('MS', 'fe03'); # part of a request
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub testStep2 {
|
sub testStep2 {
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
SimRead('MS', \&Modbus::ReadFn, '0164000810'); # part of a request
|
SimRead('MS', '0164000810'); # part of a request
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub testStep3 {
|
sub testStep3 {
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
SimRead('MS', \&Modbus::ReadFn, '20'); # final part of a request
|
SimRead('MS', '20'); # final part of a request
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,18 +42,18 @@ sub testStep4 {
|
|||||||
is(FhemTestUtils_gotLog('received valid request, now wait for the reponse'), 1, "first request reassembled correctly");
|
is(FhemTestUtils_gotLog('received valid request, now wait for the reponse'), 1, "first request reassembled correctly");
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
FhemTestUtils_resetEvents();
|
FhemTestUtils_resetEvents();
|
||||||
SimRead('MS', \&Modbus::ReadFn, 'fe03016400081020'); # another request
|
SimRead('MS', 'fe03016400081020'); # another request
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub testStep5 {
|
sub testStep5 {
|
||||||
LogStep "check reception of repeated request and send first reply";
|
LogStep "check reception of repeated request and send first reply";
|
||||||
is(FhemTestUtils_gotLog('no valid response -> try interpretation as request instead'), 1, "invalid respone and switch to request");
|
is(FhemTestUtils_gotLog('no valid response -> try interpretation as request instead'), 1, "corectly detected invalid respone and switch to request");
|
||||||
is(FhemTestUtils_gotLog('received valid request, now wait for the reponse'), 1, "second request interpreted");
|
is(FhemTestUtils_gotLog('received valid request, now wait for the reponse'), 1, "second request interpreted");
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
FhemTestUtils_resetEvents();
|
FhemTestUtils_resetEvents();
|
||||||
SimRead('MS', \&Modbus::ReadFn,'fe03100000000b000000400000011a00000167f378'); # the reply
|
SimRead('MS', 'fe03100000000b000000400000011a00000167f378'); # the reply
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +63,7 @@ sub testStep6 {
|
|||||||
is(FhemTestUtils_gotLog('ParseObj has no information about handling h356'), 1, "try parsing registers");
|
is(FhemTestUtils_gotLog('ParseObj has no information about handling h356'), 1, "try parsing registers");
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
FhemTestUtils_resetEvents();
|
FhemTestUtils_resetEvents();
|
||||||
SimRead('MS', \&Modbus::ReadFn,'fe03100000000b000000400000011a00000167f378'); # the reply repeated
|
SimRead('MS', 'fe03100000000b000000400000011a00000167f378'); # the reply repeated
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +74,7 @@ sub testStep7 {
|
|||||||
is(FhemTestUtils_gotLog('HandleResponse got data but we don.t have a request'), 1, "next response without a request seen");
|
is(FhemTestUtils_gotLog('HandleResponse got data but we don.t have a request'), 1, "next response without a request seen");
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
FhemTestUtils_resetEvents();
|
FhemTestUtils_resetEvents();
|
||||||
SimRead('MS', \&Modbus::ReadFn, 'fe03064000810209'); # a broken frame
|
SimRead('MS', 'fe03064000810209'); # a broken frame
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +82,7 @@ sub testStep7 {
|
|||||||
sub testStep8 {
|
sub testStep8 {
|
||||||
is(FhemTestUtils_gotLog('HandleRequest Done, error: '), 1, "invalid frame");
|
is(FhemTestUtils_gotLog('HandleRequest Done, error: '), 1, "invalid frame");
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
SimRead('MS', \&Modbus::ReadFn, 'fe03016400081020'); # another request
|
SimRead('MS', 'fe03016400081020'); # another request
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +97,7 @@ sub testStep10 {
|
|||||||
LogStep "check broken frame with illegal fcode";
|
LogStep "check broken frame with illegal fcode";
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
FhemTestUtils_resetEvents();
|
FhemTestUtils_resetEvents();
|
||||||
SimRead('MS', \&Modbus::ReadFn, 'fe00064000810209'); # a broken frame
|
SimRead('MS', 'fe00064000810209'); # a broken frame
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +105,7 @@ sub testStep10 {
|
|||||||
sub testStep11 {
|
sub testStep11 {
|
||||||
is(FhemTestUtils_gotLog('HandleRequest Done, error:'), 1, "invalid frame");
|
is(FhemTestUtils_gotLog('HandleRequest Done, error:'), 1, "invalid frame");
|
||||||
FhemTestUtils_resetLogs();
|
FhemTestUtils_resetLogs();
|
||||||
SimRead('MS', \&Modbus::ReadFn, 'fe03016400081020'); # another request
|
SimRead('MS', 'fe03016400081020'); # another request
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ sub testStep1 {
|
|||||||
|
|
||||||
sub testStep2 {
|
sub testStep2 {
|
||||||
LogStep('simulate normal reception');
|
LogStep('simulate normal reception');
|
||||||
SimRead('MS', \&Modbus::ReadFn, '05030a0137110001381100010dac7b'); # normal response
|
SimRead('MS', '05030a0137110001381100010dac7b'); # normal response
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ sub testStep3 {
|
|||||||
|
|
||||||
sub testStep4 {
|
sub testStep4 {
|
||||||
LogStep('simulate short response');
|
LogStep('simulate short response');
|
||||||
SimRead('MS', \&Modbus::ReadFn, '05030a013711000138110091a8'); # short response
|
SimRead('MS', '05030a013711000138110091a8'); # short response
|
||||||
return 1.1; # next step after 1.1 seconds
|
return 1.1; # next step after 1.1 seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ sub testStep5 {
|
|||||||
|
|
||||||
sub testStep6 {
|
sub testStep6 {
|
||||||
LogStep('simulate another short response');
|
LogStep('simulate another short response');
|
||||||
SimRead('MS', \&Modbus::ReadFn, '05030a013711000138110091a8'); # short response
|
SimRead('MS', '05030a013711000138110091a8'); # short response
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ sub testStep7 {
|
|||||||
|
|
||||||
sub testStep8 {
|
sub testStep8 {
|
||||||
LogStep('simulate broken fc3 response');
|
LogStep('simulate broken fc3 response');
|
||||||
SimRead('MS', \&Modbus::ReadFn, '050301000137110001381100010dd04d'); # response type broken FC3
|
SimRead('MS', '050301000137110001381100010dd04d'); # response type broken FC3
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ use FHEM::HTTPMOD::Utils qw(:all);
|
|||||||
use FHEM::Modbus::TestUtils qw(:all);
|
use FHEM::Modbus::TestUtils qw(:all);
|
||||||
|
|
||||||
fhem 'attr global mseclog 1';
|
fhem 'attr global mseclog 1';
|
||||||
InternalTimer(gettimeofday()+5, "testStepLast", 0); # last resort
|
|
||||||
NextStep();
|
NextStep();
|
||||||
|
|
||||||
sub testStep1 { # preparation of slave content, enable devices
|
sub testStep1 { # preparation of slave content, enable devices
|
||||||
@ -219,13 +218,4 @@ sub testStep21 {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# todo: different protocols (RTU, ASCII, TCP)
|
|
||||||
# data type definition
|
|
||||||
# swap bytes and similar
|
|
||||||
# unpack variations
|
|
||||||
|
|
||||||
# then relay mode
|
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
##############################################
|
##############################################
|
||||||
# test master slave end to end
|
# test relay
|
||||||
##############################################
|
##############################################
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
@ -12,7 +12,6 @@ use FHEM::HTTPMOD::Utils qw(:all);
|
|||||||
use FHEM::Modbus::TestUtils qw(:all);
|
use FHEM::Modbus::TestUtils qw(:all);
|
||||||
|
|
||||||
fhem 'attr global mseclog 1';
|
fhem 'attr global mseclog 1';
|
||||||
InternalTimer(gettimeofday()+5, "testStepLast", 0); # last resort
|
|
||||||
NextStep();
|
NextStep();
|
||||||
|
|
||||||
sub testStep1 { # preparation of slave content, enable devices
|
sub testStep1 { # preparation of slave content, enable devices
|
||||||
@ -108,7 +107,7 @@ sub testStep9 { # check write data
|
|||||||
is(FhemTestUtils_gotLog('0506000a0001698c'), 1, "set o1 on message in log");
|
is(FhemTestUtils_gotLog('0506000a0001698c'), 1, "set o1 on message in log");
|
||||||
is(FhemTestUtils_gotLog('0506000b0002784d'), 1, "set O2 2 message in log");
|
is(FhemTestUtils_gotLog('0506000b0002784d'), 1, "set O2 2 message in log");
|
||||||
fhem ('attr Master verbose 3');
|
fhem ('attr Master verbose 3');
|
||||||
return 0.1;
|
return 0.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -116,7 +115,7 @@ sub testStep10 { # check combined read of holding registers and coils
|
|||||||
LogStep "getUpdate with combine";
|
LogStep "getUpdate with combine";
|
||||||
FhemTestUtils_resetEvents();
|
FhemTestUtils_resetEvents();
|
||||||
fhem ('set Master reread');
|
fhem ('set Master reread');
|
||||||
return 0.1;
|
return 0.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep11 { # check results coming from slave and write coils to slave
|
sub testStep11 { # check results coming from slave and write coils to slave
|
||||||
@ -129,8 +128,9 @@ sub testStep11 { # check results coming from slave and write coils to slave
|
|||||||
|
|
||||||
fhem ('attr Slave obj-c402-allowWrite 1');
|
fhem ('attr Slave obj-c402-allowWrite 1');
|
||||||
fhem ('attr Master verbose 5');
|
fhem ('attr Master verbose 5');
|
||||||
|
#fhem ('attr Slave verbose 5'); # todo: remove
|
||||||
fhem ('set Master c2 1');
|
fhem ('set Master c2 1');
|
||||||
return 0.1;
|
return 0.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep12 {
|
sub testStep12 {
|
||||||
@ -144,7 +144,7 @@ sub testStep12 {
|
|||||||
fhem ('attr Slave verbose 3');
|
fhem ('attr Slave verbose 3');
|
||||||
fhem ('attr Master dev-h-write 16');
|
fhem ('attr Master dev-h-write 16');
|
||||||
fhem ('set Master TempWasserAus 29');
|
fhem ('set Master TempWasserAus 29');
|
||||||
return 0.1;
|
return 0.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep13 {
|
sub testStep13 {
|
||||||
@ -160,7 +160,7 @@ sub testStep14 {
|
|||||||
fhem ('attr Master closeAfterResponse 1');
|
fhem ('attr Master closeAfterResponse 1');
|
||||||
fhem ('attr Master verbose 4');
|
fhem ('attr Master verbose 4');
|
||||||
fhem ('set Master reread');
|
fhem ('set Master reread');
|
||||||
return 0.1;
|
return 0.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep15 {
|
sub testStep15 {
|
||||||
@ -219,12 +219,4 @@ sub testStep21 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# todo: different protocols (RTU, ASCII, TCP)
|
|
||||||
# data type definition
|
|
||||||
# swap bytes and similar
|
|
||||||
# unpack variations
|
|
||||||
|
|
||||||
# then relay mode
|
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
##############################################
|
##############################################
|
||||||
# test master slave end to end
|
# test relay with different protocols
|
||||||
##############################################
|
##############################################
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
@ -12,7 +12,6 @@ use FHEM::HTTPMOD::Utils qw(:all);
|
|||||||
use FHEM::Modbus::TestUtils qw(:all);
|
use FHEM::Modbus::TestUtils qw(:all);
|
||||||
|
|
||||||
fhem 'attr global mseclog 1';
|
fhem 'attr global mseclog 1';
|
||||||
InternalTimer(gettimeofday()+5, "testStepLast", 0); # last resort
|
|
||||||
NextStep();
|
NextStep();
|
||||||
|
|
||||||
sub testStep1 { # preparation of slave content, enable devices
|
sub testStep1 { # preparation of slave content, enable devices
|
||||||
@ -116,7 +115,7 @@ sub testStep10 { # check combined read of holding registers and coils
|
|||||||
LogStep "getUpdate with combine";
|
LogStep "getUpdate with combine";
|
||||||
FhemTestUtils_resetEvents();
|
FhemTestUtils_resetEvents();
|
||||||
fhem ('set Master reread');
|
fhem ('set Master reread');
|
||||||
return 0.1;
|
return 0.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testStep11 { # check results coming from slave and write coils to slave
|
sub testStep11 { # check results coming from slave and write coils to slave
|
||||||
@ -218,13 +217,4 @@ sub testStep21 {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# todo: different protocols (RTU, ASCII, TCP)
|
|
||||||
# data type definition
|
|
||||||
# swap bytes and similar
|
|
||||||
# unpack variations
|
|
||||||
|
|
||||||
# then relay mode
|
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
##############################################
|
##############################################
|
||||||
# test master slave end to end
|
# test profiler (to be implemented!)
|
||||||
##############################################
|
##############################################
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
@ -12,7 +12,6 @@ use FHEM::HTTPMOD::Utils qw(:all);
|
|||||||
use FHEM::Modbus::TestUtils qw(:all);
|
use FHEM::Modbus::TestUtils qw(:all);
|
||||||
|
|
||||||
fhem 'attr global mseclog 1';
|
fhem 'attr global mseclog 1';
|
||||||
InternalTimer(gettimeofday()+5, "testStepLast", 0); # last resort
|
|
||||||
NextStep();
|
NextStep();
|
||||||
|
|
||||||
sub testStep1 { # preparation of slave content, enable devices
|
sub testStep1 { # preparation of slave content, enable devices
|
||||||
|
Loading…
x
Reference in New Issue
Block a user