2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-07 12:58:13 +00:00

98_Modbus.pm: added tests

git-svn-id: https://svn.fhem.de/fhem/trunk@23485 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
StefanStrobel 2021-01-07 13:06:26 +00:00
parent 90503ced50
commit 84a1c425fb
25 changed files with 3368 additions and 0 deletions

View File

@ -0,0 +1,3 @@
define M1 ModbusAttr 1 1
attr M1 verbose 5
define MS Modbus none

View File

@ -0,0 +1,22 @@
##############################################
# test update timer
##############################################
use strict;
use warnings;
use Test::More;
fhem('set M1 interval 0.2');
is(FhemTestUtils_gotLog("changed interval to 0.2 seconds"), 1, "set interval in log");
fhem('set M1 interval test');
is(FhemTestUtils_gotLog("set interval test not valid"), 1, "invalid interval in log");
InternalTimer(time()+1, sub() {
isnt(FhemTestUtils_gotLog("GetUpdate called"), 0, "GetUpdate in log");
isnt(FhemTestUtils_gotLog("UpdateTimer called from.*GetUpdate"), 0, "UpdateTimer in log");
done_testing;
exit(0);
}, 0);
1;

View File

@ -0,0 +1,234 @@
define MS Modbus none
attr MS verbose 4
attr MS clientSwitchDelay 0
attr MS busDelay 0
define M5 ModbusAttr 5 0
attr M5 verbose 3
attr M5 dev-timing-sendDelay 0
attr M5 dev-timing-commDelay 0
attr M5 nonPrioritizedGet 1
attr M5 obj-h256-reading TempWasserEin
attr M5 obj-h258-reading TempWasserAus
attr M5 obj-h10-reading o1
attr M5 obj-h10-map 0:off, 1:on
attr M5 obj-h10-set 1
attr M5 obj-h11-reading o2
attr M5 obj-h11-hint 1,2,3
attr M5 dev-h-defSet 1
attr M5 dev-h-defShowGet 1
define M1 ModbusAttr 1 0
attr M1 verbose 3
attr M1 dev-timing-sendDelay 0
attr M1 dev-timing-commDelay 0
attr M1 nonPrioritizedGet 1
attr M1 dev-c-defPoll 1
attr M1 dev-h-combine 5
attr M1 dev-h-defLen 2
attr M1 dev-h-defPoll 1
attr M1 dev-h-defRevRegs 1
attr M1 dev-h-write 16
attr M1 dev-i-defFormat %.1f
attr M1 dev-i-defLen 2
attr M1 dev-i-defPoll 1
attr M1 dev-i-defRevRegs 1
attr M1 dev-i-defUnpack f>
attr M1 dev-type-VT_Date-expr sprintf("%02d.%02d",($val >> 8),($val & 0xff))
attr M1 dev-type-VT_Date-len 1
attr M1 dev-type-VT_Date-unpack n
attr M1 dev-type-VT_R4-format %.1f
attr M1 dev-type-VT_R4-len 2
attr M1 dev-type-VT_R4-revRegs 1
attr M1 dev-type-VT_R4-unpack f>
attr M1 dev-type-VT_String-bswapRegs 1
attr M1 dev-type-VT_String-decode cp850
attr M1 dev-type-VT_String-encode utf8
attr M1 dev-type-VT_String-expr $val =~ s/[\00]+//gr
attr M1 dev-type-VT_String-len 8
attr M1 dev-type-VT_String-revRegs 0
attr M1 dev-type-VT_String-unpack a*
attr M1 dev-type-VT_Time-expr sprintf("%02d:%02d",($val >> 8),($val & 0xff))
attr M1 dev-type-VT_Time-len 1
attr M1 dev-type-VT_Time-unpack n
attr M1 obj-c1009-map 0:false, 1:true
attr M1 obj-c1009-polldelay 3600
attr M1 obj-c1009-reading HeatOff
attr M1 obj-c1329-map 0:false, 1:true
attr M1 obj-c1329-polldelay 300
attr M1 obj-c1329-reading HeatIncreaseOff
attr M1 obj-c1409-map 0:0, 1:1=2, 2:1->2, 3:1->2->3
attr M1 obj-c1409-polldelay 60
attr M1 obj-c1409-reading AuxilaryModeHeating
attr M1 obj-c1457-map 0:false, 1:true
attr M1 obj-c1457-reading CoolOff
attr M1 obj-c1633-map 0:false, 1:true
attr M1 obj-c1633-reading DomesticWaterOff
attr M1 obj-h1-len 13
attr M1 obj-h1-poll 0
attr M1 obj-h1-reading RTCTime
attr M1 obj-h1-unpack H*
attr M1 obj-h1025-polldelay 86400
attr M1 obj-h1025-reading HeatTimeOn
attr M1 obj-h1025-type VT_Time
attr M1 obj-h1041-polldelay 86400
attr M1 obj-h1041-reading HeatTimeOff
attr M1 obj-h1041-type VT_Time
attr M1 obj-h1057-max 30
attr M1 obj-h1057-min 10
attr M1 obj-h1057-reading HeatCharacteristicSetPoint
attr M1 obj-h1057-type VT_R4
attr M1 obj-h1089-max 65
attr M1 obj-h1089-min 15
attr M1 obj-h1089-reading HeatCharacteristicSetPointBaseTemp
attr M1 obj-h1089-set 1
attr M1 obj-h1089-type VT_R4
attr M1 obj-h1121-max 100
attr M1 obj-h1121-min 0
attr M1 obj-h1121-reading HeatCharacteristicGradient
attr M1 obj-h1121-type VT_R4
attr M1 obj-h1153-max 72
attr M1 obj-h1153-min 10
attr M1 obj-h1153-reading HeatCharacteristicLimit
attr M1 obj-h1153-type VT_R4
attr M1 obj-h1185-reading HeatReturnTemp
attr M1 obj-h1185-type VT_R4
attr M1 obj-h1249-max 3
attr M1 obj-h1249-min 1
attr M1 obj-h1249-reading HeatTempHyst
attr M1 obj-h1249-type VT_R4
attr M1 obj-h1281-reading RoomTempNominal
attr M1 obj-h1281-type VT_R4
attr M1 obj-h1313-len 1
attr M1 obj-h1313-max 200
attr M1 obj-h1313-min 0
attr M1 obj-h1313-reading RoomTempFactor
attr M1 obj-h1313-unpack S>
attr M1 obj-h1345-polldelay 86400
attr M1 obj-h1345-reading HeatIncreaseTimeOn
attr M1 obj-h1345-type VT_Time
attr M1 obj-h1361-polldelay 86400
attr M1 obj-h1361-reading HeatIncreaseTimeOff
attr M1 obj-h1361-type VT_Time
attr M1 obj-h1377-max 5
attr M1 obj-h1377-min -5
attr M1 obj-h1377-reading HeatIncreaseSetPtOffset
attr M1 obj-h1377-type VT_R4
attr M1 obj-h1425-max 5
attr M1 obj-h1425-min 0
attr M1 obj-h1425-reading AuxilaryMaxDifference
attr M1 obj-h1425-type VT_R4
attr M1 obj-h1473-polldelay 86400
attr M1 obj-h1473-reading CoolTimeOn
attr M1 obj-h1473-type VT_Time
attr M1 obj-h1489-polldelay 86400
attr M1 obj-h1489-reading CoolTimeOff
attr M1 obj-h1489-type VT_Time
attr M1 obj-h1505-max 30
attr M1 obj-h1505-min 18
attr M1 obj-h1505-reading CoolCharacteristicSetPoint
attr M1 obj-h1505-type VT_R4
attr M1 obj-h1569-reading CoolReturnTempNominal
attr M1 obj-h1569-type VT_R4
attr M1 obj-h1601-max 3
attr M1 obj-h1601-min 1
attr M1 obj-h1601-reading CoolReturnTempHyst
attr M1 obj-h1601-type VT_R4
attr M1 obj-h1649-polldelay 86400
attr M1 obj-h1649-reading DomesticWaterTimeOn
attr M1 obj-h1649-type VT_Time
attr M1 obj-h1665-polldelay 86400
attr M1 obj-h1665-reading DomesticWaterTimeOff
attr M1 obj-h1665-type VT_Time
attr M1 obj-h1713-reading DomesticWaterTempNominal
attr M1 obj-h1713-set 1
attr M1 obj-h1713-type VT_R4
attr M1 obj-h1745-max 10
attr M1 obj-h1745-min 5
attr M1 obj-h1745-reading DomesticWaterTempHyst
attr M1 obj-h1745-type VT_R4
attr M1 obj-h1777-len 16
attr M1 obj-h1777-polldelay 86400
attr M1 obj-h1777-reading LegionellaSchedule
attr M1 obj-h1777-unpack H*
attr M1 obj-h1793-polldelay 86400
attr M1 obj-h1793-type VT_Time
attr M1 obj-h1809-polldelay 86400
attr M1 obj-h1809-reading LegionellaTimeOff
attr M1 obj-h1809-type VT_Time
attr M1 obj-h209-len 13
attr M1 obj-h209-poll 0
attr M1 obj-h209-reading RTCDate
attr M1 obj-h209-unpack H*
attr M1 obj-h417-len 1
attr M1 obj-h417-polldelay 86400
attr M1 obj-h417-reading LngSelect
attr M1 obj-h4497-reading PElectric
attr M1 obj-h4497-type VT_R4
attr M1 obj-h4529-reading PThermal
attr M1 obj-h4529-type VT_R4
attr M1 obj-h4689-polldelay 86400
attr M1 obj-h4689-reading FirmwareVersion
attr M1 obj-h4689-showGet 1
attr M1 obj-h4689-type VT_String
attr M1 obj-h4689-unpack (a*)
attr M1 obj-h4817-polldelay 86400
attr M1 obj-h4817-reading FirmwareDate
attr M1 obj-h4817-type VT_String
attr M1 obj-h4945-polldelay 86400
attr M1 obj-h4945-reading ManufType
attr M1 obj-h4945-type VT_String
attr M1 obj-h5073-polldelay 86400
attr M1 obj-h5073-reading ManufSerialNum
attr M1 obj-h5073-type VT_String
attr M1 obj-h5457-len 1
attr M1 obj-h5457-map 0048:Kühlung, 0040:Idle, 0051:Warmwasser, 0052:Heizung
attr M1 obj-h5457-reading OperatingState
attr M1 obj-h5457-unpack H*
attr M1 obj-h5505-len 16
attr M1 obj-h5505-reading ADC_Error
attr M1 obj-h5505-unpack H*
attr M1 obj-h5521-reading LCD_Display_Line_1
attr M1 obj-h5521-type VT_String
attr M1 obj-h5649-reading LCD_Display_Line_2
attr M1 obj-h5649-type VT_String
attr M1 obj-i1217-reading HeatReturnTempNominal
attr M1 obj-i1537-reading CoolReturnTemp
attr M1 obj-i1681-reading DomesticWaterTempActual
attr M1 obj-i2625-reading OHCompressor1
attr M1 obj-i2657-reading OHCompressor2
attr M1 obj-i2689-reading OHHeatingCompressor
attr M1 obj-i2721-reading OHHeatingAuxilary
attr M1 obj-i2753-reading OHCooling
attr M1 obj-i2785-reading OHDomesticWaterCompressor
attr M1 obj-i433-reading OutdoorTemp
attr M1 obj-i433-showGet 1
attr M1 obj-i4561-reading COP
attr M1 obj-i4561-showGet 1
attr M1 obj-i465-reading OutdoorTemp1h
attr M1 obj-i497-reading OutdoorTemp24h
attr M1 obj-i529-reading HeatSourceIn
attr M1 obj-i561-reading HeatSourceOut
attr M1 obj-i593-reading EvaporationTemp
attr M1 obj-i625-reading SuctionGasTemp
attr M1 obj-i657-reading EvaporationPress
attr M1 obj-i689-reading ReturnTempNominal
attr M1 obj-i721-reading ReturnTemp
attr M1 obj-i753-reading FlowTemp
attr M1 obj-i785-reading CondensationTemp
attr M1 obj-i817-reading CondensationPress
attr M1 obj-i849-reading RoomTemp
attr M1 obj-i881-reading RoomTemp1h
attr M1 obj-i913-reading DomesticWaterTemp
attr M1 obj-i945-reading PoolTemp
attr M1 obj-i977-reading SolarTemp
attr M1 sortUpdate 1

View File

@ -0,0 +1,256 @@
##############################################
# test request parsing
##############################################
use strict;
use warnings;
use Test::More;
use Time::HiRes qw( gettimeofday tv_interval); # return time as float, not just full seconds
use FHEM::HTTPMOD::Utils qw(:all);
$logInform{'MS'} = \&ReactOnSendingLog;
my %rData = (
'010403d1000221b6' => '01040400000000fb84',
'010404c100022107' => '010404000041b4cba3',
'0104060100022083' => '0104045262419dbb1b',
'01040691000220ae' => '010404000042524ad9',
'01040a4100022207' => '010404533c458c19',
'01040a61000223cd' => '01040400000000fb84',
'01040a810002223b' => '0104049dff454cd77d',
'01040aa1000223f1' => '01040400000000fb84',
'01040ac1000223ef' => '0104044d6345282e78',
'01040ae100022225' => '010404b6f644980f54',
'010411d1000224ce' => '01040400000000fb84',
'050303020001240a' => '0503020122c80d',
'05030309000155c8' => '05030200004984',
'0503010600016473' => '0503020106c816',
'05030100000585b1' => '05030a0137110001381100010dac7b',
'0503010000018472' => '050302013709c2',
'0506030900005808' => '0506030900005808', # set hyst mode
'0506030201182850' => '0506030201182850' # set temp soll 28
);
my $testStep = 0;
my %results;
fhem 'attr global mseclog 1';
sub SimReadMS {
my $text = shift;
my $data = pack ('H*', $text);
my $hash = $defs{MS};
my $name = 'MS';
Log3 undef, 1, "SimReadMS: simulate reception of $text";
$hash->{TestInput} = $data;
Modbus::ReadFn($hash);
#$hash->{READ}{BUFFER} = $data;
#$hash->{REMEMBER}{lrecv} = gettimeofday();
#Modbus::ParseFrameStart($hash);
#Modbus::HandleResponse($hash);
Log3 undef, 1, "SimReadMS: look for next step";
FINDSTEP:
while (1) {
$testStep++;
if ($testStep > 99) {
InternalTimer(gettimeofday(), "testStepLast", 0);
Log3 undef, 1, "SimReadMS: set timer to go to last step and finish testing";
last FINDSTEP;
}
Log3 undef, 1, "SimReadMS: check step $testStep";
next FINDSTEP if (!defined (&{"testStep$testStep"}));
InternalTimer(gettimeofday(), "testStep$testStep", 0);
Log3 undef, 1, "SimReadMS: set timer to call test $testStep";
last FINDSTEP;
}
Log3 undef, 1, "SimReadMS: done.";
return;
}
sub ReactOnSendingLog {
my $name = shift;
my $line = shift;
#die "line got: $line";
if ($line =~ /MS: Simulate sending to none: (.*)/) {
my $send = $1;
my $id = substr ($send, 0,2);
my $recv = $rData{$send} // (($id . '800041c0'));
Log3 undef, 1, "Test: saw sending $send, id $id, simulate receiving $recv";
InternalTimer(gettimeofday() + 0.05, \&SimReadMS, $recv);
}
return;
}
sub findTimesInLog {
$results{'send'.$testStep} = FhemTestUtils_getLogTime('MS:\sSimulate\ssending', 'last');
$results{'recv'.$testStep} = FhemTestUtils_getLogTime('ParseFrameStart\s\(RTU\)\sextracted\sid', 'last');
Log3 undef, 1, "TEST$testStep: LogTime for last Sending is " .
($results{'send'.$testStep} // 'unknown') . " converted: " . FmtTimeMs($results{'send'.$testStep});
Log3 undef, 1, "TEST$testStep: LogTime for last Reception is " .
($results{'recv'.$testStep} // 'unknown') . " converted: " . FmtTimeMs($results{'recv'.$testStep});
return;
}
sub calcDelays {
my $commDelay = $results{'send' . $testStep} - $results{'recv' . ($testStep - 1)};
my $sendDelay = $results{'send' . $testStep} - $results{'send' . ($testStep - 1)};
Log3 undef, 1, "TEST$testStep: delay between receive in step " . ($testStep - 1) . " and send in step $testStep is $commDelay, send delay $sendDelay";
return ($commDelay, $sendDelay);
}
fhem 'get M1 SolarTemp';
InternalTimer(gettimeofday()+5, "testStepLast", 0); # last resort
sub testStep1 {
Log3 undef, 1, "TEST$testStep: initial step called";
findTimesInLog();
FhemTestUtils_resetLogs();
is(FhemTestUtils_gotEvent('M1:SolarTemp'), 1, "Event SolarTemp ...");
fhem 'get M1 HeatOff';
# read simulation is triggered when sending is seen in the log.
# next step is called when read simulation is done.
}
sub testStep2 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
# check no delay between read (get SolarTemp) after Step 0 and send (get HeatOff) in step 1
ok($commDelay < 0.1, 'normal delay from read solar temp to send get HeatOff smaller than 0.1');
fhem 'attr M1 dev-timing-sendDelay 0.2'; # send in step2 should be 0.2 after send in step1
fhem 'get M1 HeatOff';
}
sub testStep3 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
# 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.22, 'defined send delay from read HeatOff to next send get HeatOff not too big');
fhem 'get M5 TempWasserEin';
}
sub testStep4 {
findTimesInLog();
FhemTestUtils_resetLogs();
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
ok($sendDelay < 0.1, '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 'get M5 TempWasserAus';
}
sub testStep5 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
# check bus delay between read (get TempWasserEin) after Step 3 and send (get TempWasserAus) in step 4
ok($commDelay >= 0.2, 'defined bus delay big enough');
ok($commDelay < 0.22, 'defined bus delay not too big');
fhem 'attr MS busDelay 0';
fhem 'attr M1 dev-timing-sendDelay 0';
fhem 'attr MS clientSwitchDelay 0';
fhem 'get M1 SolarTemp';
}
sub testStep6 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
ok($sendDelay < 0.1, 'no delay');
fhem 'attr MS clientSwitchDelay 0.2';
fhem 'get M5 TempWasserEin';
}
sub testStep7 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
ok($commDelay >= 0.2, 'defined clsw delay big enough');
ok($commDelay < 0.22, 'defined clsw delay not too big');
fhem 'get M5 TempWasserAus';
}
sub testStep8 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
ok($sendDelay < 0.1, 'no delay for same id');
fhem 'attr M5 dev-timing-commDelay 0.2';
fhem 'get M5 TempWasserEin';
}
sub testStep9 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
ok($commDelay >= 0.2, 'defined comm delay big enough');
ok($commDelay < 0.22, 'defined comm delay not too big');
fhem 'attr M5 dev-timing-commDelay 0';
fhem 'get M5 TempWasserEin';
}
sub testStep10 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
ok($commDelay < 0.07, 'zero comm delay');
fhem 'attr M5 dev-timing-commDelay 0.2';
fhem 'attr M5 verbose 4';
fhem 'set M5 o1 on';
}
sub testStep11 {
findTimesInLog();
my ($commDelay, $sendDelay) = calcDelays();
is(FhemTestUtils_gotLog('commDelay not over.*sleep'), 1, "sleep message in log");
ok($commDelay >0.2, 'forced comm delay big enough');
ok($commDelay < 0.22, 'forced comm delay not too big');
FhemTestUtils_resetLogs();
testStepLast();
}
sub testStepLast {
done_testing;
exit(0);
};
1;

View File

@ -0,0 +1,203 @@
##############################################
# test request parsing
##############################################
package main;
use strict;
use warnings;
use Test::More;
use Time::HiRes qw( gettimeofday tv_interval); # return time as float, not just full seconds
use FHEM::HTTPMOD::Utils qw(:all);
use FHEM::Modbus::TestUtils qw(:all);
my %rData = (
'010403d1000221b6' => '01040400000000fb84',
'010404c100022107' => '010404000041b4cba3',
'0104060100022083' => '0104045262419dbb1b',
'01040691000220ae' => '010404000042524ad9',
'01040a4100022207' => '010404533c458c19',
'01040a61000223cd' => '01040400000000fb84',
'01040a810002223b' => '0104049dff454cd77d',
'01040aa1000223f1' => '01040400000000fb84',
'01040ac1000223ef' => '0104044d6345282e78',
'01040ae100022225' => '010404b6f644980f54',
'010411d1000224ce' => '01040400000000fb84',
'050303020001240a' => '0503020122c80d',
'05030309000155c8' => '05030200004984',
'0503010600016473' => '0503020106c816',
'05030100000585b1' => '05030a0137110001381100010dac7b',
'0503010000018472' => '050302013709c2',
'0506030900005808' => '0506030900005808', # set hyst mode
'0506030201182850' => '0506030201182850' # set temp soll 28
);
fhem 'attr global mseclog 1';
SetTestOptions(
{ IODevice => 'MS', # for loginform
RespondTo => 'MS: Simulate sending to none: (.*)', # auto reponder / go to next step at reception
ReadFn => \&Modbus::ReadFn, # call for reception
ReplyHash => \%rData, # to find the right response
Time1Name => 'Sending',
Time1Regex => qr{MS:\sSimulate\ssending},
Time2Name => 'Reception',
Time2Regex => qr{ParseFrameStart\s\(RTU\)\sextracted\sid},
}
);
fhem 'get M1 SolarTemp';
sub testStep1 {
findTimesInLog();
FhemTestUtils_resetLogs();
is(FhemTestUtils_gotEvent('M1:SolarTemp'), 1, "Event SolarTemp ...");
fhem 'get M1 HeatOff';
# read simulation is triggered when sending is seen in the log.
# next step is called when read simulation is done.
return;
}
sub testStep2 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
# check no delay between read (get SolarTemp) after Step 0 and send (get HeatOff) in step 1
ok($commDelay < 0.1, 'normal delay from read solar temp to send get HeatOff smaller than 0.1');
fhem 'attr M1 dev-timing-sendDelay 0.2'; # send in step2 should be 0.2 after send in step1
fhem 'get M1 HeatOff';
return;
}
sub testStep3 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
# 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.22, 'defined send delay from read HeatOff to next send get HeatOff not too big');
fhem 'get M5 TempWasserEin';
return;
}
sub testStep4 {
findTimesInLog();
FhemTestUtils_resetLogs();
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
ok($sendDelay < 0.1, '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 'get M5 TempWasserAus';
return;
}
sub testStep5 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
# check bus delay between read (get TempWasserEin) after Step 3 and send (get TempWasserAus) in step 4
ok($commDelay >= 0.2, 'defined bus delay big enough');
ok($commDelay < 0.3, 'defined bus delay not too big');
fhem 'attr MS busDelay 0';
fhem 'attr M1 dev-timing-sendDelay 0';
fhem 'attr MS clientSwitchDelay 0';
fhem 'get M1 SolarTemp';
return;
}
sub testStep6 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
ok($sendDelay < 0.2, 'no delay');
fhem 'attr MS clientSwitchDelay 0.2';
fhem 'get M5 TempWasserEin';
return;
}
sub testStep7 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
ok($commDelay >= 0.2, 'defined clsw delay big enough');
ok($commDelay < 0.3, 'defined clsw delay not too big');
fhem 'get M5 TempWasserAus';
return;
}
sub testStep8 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
ok($sendDelay < 0.1, 'no delay for same id');
fhem 'attr M5 dev-timing-commDelay 0.2';
fhem 'get M5 TempWasserEin';
return;
}
sub testStep9 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
ok($commDelay >= 0.2, 'defined comm delay big enough');
ok($commDelay < 0.22, 'defined comm delay not too big');
fhem 'attr M5 dev-timing-commDelay 0';
fhem 'get M5 TempWasserEin';
return;
}
sub testStep10 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay) = calcDelays();
ok($commDelay < 0.07, 'zero comm delay');
fhem 'attr M5 dev-timing-commDelay 0.2';
fhem 'attr M5 verbose 4';
fhem 'set M5 o1 on';
return;
}
sub testStep11 {
findTimesInLog();
my ($commDelay, $sendDelay) = calcDelays();
is(FhemTestUtils_gotLog('commDelay not over.*sleep'), 1, "sleep message in log");
ok($commDelay >0.2, 'forced comm delay big enough');
ok($commDelay < 0.22, 'forced comm delay not too big');
FhemTestUtils_resetLogs();
return;
}
1;

View File

@ -0,0 +1,123 @@
attr global mseclog 1
define D1 dummy
define Slave ModbusAttr 5 slave global:5501
attr Slave obj-h256-reading TempWasserEin
attr Slave obj-h258-reading D1:TempWasserAus
attr Slave obj-h100-reading Test1
attr Slave obj-h100-setexpr $val * 4
attr Slave obj-h101-reading Test2
attr Slave obj-h101-unpack f>
attr Slave obj-h101-len 2
attr Slave obj-h103-reading Test3
attr Slave obj-h103-unpack a8
attr Slave obj-h103-len 4
attr Slave obj-h120-reading Test4
attr Slave obj-h120-unpack f>
attr Slave obj-h120-len 2
attr Slave obj-h130-reading Test5
attr Slave obj-h130-unpack a*
attr Slave obj-h130-len 2
attr Slave obj-c400-reading c0
attr Slave obj-c401-reading c1
attr Slave obj-c402-reading c2
attr Slave obj-c403-reading c3
attr Slave obj-c404-reading c4
attr Slave obj-c405-reading c5
attr Slave obj-c406-reading c6
attr Slave obj-c407-reading c7
attr Slave obj-c408-reading c8
attr Slave obj-c409-reading c9
attr Slave obj-c410-reading c10
attr Slave obj-c411-reading c11
attr Slave obj-c412-reading c12
attr Slave obj-c413-reading c13
attr Slave obj-c414-reading c14
attr Slave obj-c415-reading c15
attr Slave obj-c416-reading c16
attr Slave obj-c417-reading c17
attr Slave obj-c418-reading c18
define Master ModbusAttr 5 0 localhost:5501
attr Master disable 1
attr Master verbose 3
attr Master nonPrioritizedGet 1
attr Master nonPrioritizedSet 1
attr Master dev-timing-sendDelay 0
attr Master dev-timing-commDelay 0
attr Master obj-h256-reading TempWasserEin
attr Master obj-h258-reading TempWasserAus
attr Master obj-h100-reading Test1
attr Master obj-h100-expr $val + 2
attr Master obj-h100-poll 1
attr Master obj-h101-reading Test2
attr Master obj-h101-unpack f>
attr Master obj-h101-len 2
attr Master obj-h101-format %.2f
attr Master obj-h101-poll 1
attr Master obj-h103-reading Test3
attr Master obj-h103-unpack a8
attr Master obj-h103-len 4
attr Master obj-h103-poll 1
attr Master obj-h120-reading Test4
attr Master obj-h120-unpack f>
attr Master obj-h120-len 2
attr Master obj-h120-format %.2f
attr Master obj-h120-poll 1
attr Master obj-h120-ignoreExpr $val > 10
attr Master obj-h130-reading Test5
attr Master obj-h130-unpack a*
attr Master obj-h130-len 2
attr Master obj-h130-encode utf8
attr Master obj-h10-reading o1
attr Master obj-h10-map 0:off, 1:on
attr Master obj-h11-reading o2
attr Master obj-h11-min 1
attr Master obj-h11-max 3
attr Master dev-h-defSet 1
attr Master dev-c-defSet 1
attr Master dev-h-defShowGet 1
attr Master obj-c400-reading c0
attr Master obj-c401-reading c1
attr Master obj-c402-reading c2
attr Master obj-c403-reading c3
attr Master obj-c404-reading c4
attr Master obj-c405-reading c5
attr Master obj-c406-reading c6
attr Master obj-c407-reading c7
attr Master obj-c408-reading c8
attr Master obj-c409-reading c9
attr Master obj-c410-reading c10
attr Master obj-c411-reading c11
attr Master obj-c412-reading c12
attr Master obj-c413-reading c13
attr Master obj-c414-reading c14
attr Master obj-c415-reading c15
attr Master obj-c416-reading c16
attr Master obj-c417-reading c17
attr Master obj-c418-reading c18
attr Master obj-c400-poll 1
attr Master obj-c405-poll 1
attr Master obj-c406-poll 1
attr Master obj-c417-poll 1
attr Master dev-h-combine 19
attr Master dev-c-combine 32

View File

@ -0,0 +1,219 @@
##############################################
# test master slave end to end
# attr disable
# and set inactive / set active
##############################################
package main;
use strict;
use warnings;
use Test::More;
use Time::HiRes qw( gettimeofday tv_interval); # return time as float, not just full seconds
use FHEM::HTTPMOD::Utils qw(:all);
use Data::Dumper;
my $closeTime;
my $openTime;
my $startTime;
InternalTimer(gettimeofday() + 0.1, "testStep1", 0);
sub getLogTime {
my $regex = shift;
my $times = shift // 1;
is(FhemTestUtils_gotLog($regex), $times, "search $regex in log");
my $time = FhemTestUtils_getLogTime($regex, 'last');
Log3 undef, 1, "Test: found $regex in log at $startTime " . FmtTimeMs($time) if $time;
return $time;
}
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.
Log3 undef, 1, "TestStep1: enable Master and set value at Slave";
fhem ('attr Master disable 0');
fhem ('setreading Slave TempWasserEin 12');
fhem ('setreading Slave Test1 1');
fhem ('setreading Slave Test2 2.123');
fhem ('setreading Slave Test3 abcdefg');
fhem ('setreading Slave Test4 40');
InternalTimer(gettimeofday() + 0.1, "testStep2", 0);
}
sub testStep2 { # get holding registers
Log3 undef, 1, "----------------";
Log3 undef, 1, "TestStep2: get TempWasserEin";
fhem ('attr Master verbose 5');
fhem ('attr Slave verbose 3');
fhem ('get Master TempWasserEin');
InternalTimer(gettimeofday() + 0.1, "testStep3", 0);
}
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");
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('attr Master disable 1');
fhem ('get Master TempWasserEin');
InternalTimer(gettimeofday(), "testStep4", 0);
}
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:disabled/xms), 1, "state disabled");
fhem ('attr Master disable 0');
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
InternalTimer(gettimeofday() + 0.1, "testStep5", 0);
}
sub testStep5 {
Log3 undef, 1, "----------------";
Log3 undef, 1, "TestStep5: now set master inactive";
$startTime = getLogTime ('Master device opened');
fhem ('attr Master enableSetInactive 1');
fhem ('set Master inactive');
InternalTimer(gettimeofday(), "testStep6", 0);
}
sub testStep6 {
Log3 undef, 1, "----------------";
Log3 undef, 1, "TestStep6: now try to get reading again";
fhem ('get Master TempWasserEin');
InternalTimer(gettimeofday(), "testStep7a", 0);
}
sub testStep7a {
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");
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('attr Master nextOpenDelay2 0'); # don't wait with open
fhem ('set Master active');
InternalTimer(gettimeofday(), "testStep7b", 0);
}
sub testStep7b {
Log3 undef, 1, "----------------";
Log3 undef, 1, "TestStep7b: try retrieve again";
$openTime = getLogTime ('Master device opened');
Log3 undef, 1, "TestStep7b: Time diff is " . sprintf ('%.3f', $openTime - $startTime);
ok($openTime - $startTime < 0.25, 'time between two open calls is smaller than 0.25');
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('get Master TempWasserEin');
InternalTimer(gettimeofday() + 0.1, "testStep8", 0);
}
sub testStep8 {
Log3 undef, 1, "----------------";
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');
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('attr Master dev-timing-timeout 0.2');
fhem ('attr Master openTimeout 0.5'); #
fhem ('attr Master nextOpenDelay2 0.1'); #
fhem ('attr Master nextOpenDelay 1'); # can not be smaller than 1
fhem ('get Master TempWasserEin'); # should run into timeout
InternalTimer(gettimeofday()+0.5, "testStep8b", 0);
}
sub testStep8b {
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_gotLog('Master: Timeout waiting for a modbus response'), 1, "saw timeout");
$startTime = getLogTime ('HttpUtils url=http://localhost:5501'); # time of first try
fhem ('set Slave active');
InternalTimer(gettimeofday()+1, "testStep8c", 0);
}
sub testStep8c {
Log3 undef, 1, "----------------";
Log3 undef, 1, "TestStep8c: ";
InternalTimer(gettimeofday()+1, "testStep9a", 0);
}
sub testStep9a {
Log3 undef, 1, "----------------";
Log3 undef, 1, "TestStep9a: check nextOpenDelay";
$openTime = getLogTime ('5501 reappeared');
Log3 undef, 1, "TestStep7b: Time diff is " . sprintf ('%.3f', $openTime - $startTime);
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');
InternalTimer(gettimeofday() + 0.1, "testStep9b", 0);
}
sub testStep9b {
Log3 undef, 1, "----------------";
Log3 undef, 1, "TestStep9b: ";
InternalTimer(gettimeofday(), "testStep9c", 0);
}
sub testStep9c {
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
fhem('attr Slave dev-timing-serverTimeout 1');
fhem('attr Slave dev-timing-serverTimeout 1');
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('get Master TempWasserEin');
InternalTimer(gettimeofday() + 1.1, "testStep10", 0);
}
sub testStep10 {
# 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");
InternalTimer(gettimeofday() + 0.5, "testStep11", 0);
}
sub testStep11 {
Log3 undef, 1, "----------------";
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;

View File

@ -0,0 +1,235 @@
define MS Modbus none
attr MS verbose 5
attr MS clientSwitchDelay 0
attr MS busDelay 0
attr MS queueDelay 0.4
define M5 ModbusAttr 5 0
attr M5 verbose 5
attr M5 dev-timing-sendDelay 0
attr M5 dev-timing-commDelay 0
attr M5 nonPrioritizedGet 1
attr M5 obj-h256-reading TempWasserEin
attr M5 obj-h258-reading TempWasserAus
attr M5 obj-h10-reading o1
attr M5 obj-h10-map 0:off, 1:on
attr M5 obj-h10-set 1
attr M5 obj-h11-reading o2
attr M5 obj-h11-hint 1,2,3
attr M5 dev-h-defSet 1
attr M5 dev-h-defShowGet 1
define M1 ModbusAttr 1 0
attr M1 verbose 5
attr M1 dev-timing-sendDelay 0
attr M1 dev-timing-commDelay 0
attr M1 nonPrioritizedGet 1
attr M1 dev-c-defPoll 1
attr M1 dev-h-combine 5
attr M1 dev-h-defLen 2
attr M1 dev-h-defPoll 1
attr M1 dev-h-defRevRegs 1
attr M1 dev-h-write 16
attr M1 dev-i-defFormat %.1f
attr M1 dev-i-defLen 2
attr M1 dev-i-defPoll 1
attr M1 dev-i-defRevRegs 1
attr M1 dev-i-defUnpack f>
attr M1 dev-type-VT_Date-expr sprintf("%02d.%02d",($val >> 8),($val & 0xff))
attr M1 dev-type-VT_Date-len 1
attr M1 dev-type-VT_Date-unpack n
attr M1 dev-type-VT_R4-format %.1f
attr M1 dev-type-VT_R4-len 2
attr M1 dev-type-VT_R4-revRegs 1
attr M1 dev-type-VT_R4-unpack f>
attr M1 dev-type-VT_String-bswapRegs 1
attr M1 dev-type-VT_String-decode cp850
attr M1 dev-type-VT_String-encode utf8
attr M1 dev-type-VT_String-expr $val =~ s/[\00]+//gr
attr M1 dev-type-VT_String-len 8
attr M1 dev-type-VT_String-revRegs 0
attr M1 dev-type-VT_String-unpack a*
attr M1 dev-type-VT_Time-expr sprintf("%02d:%02d",($val >> 8),($val & 0xff))
attr M1 dev-type-VT_Time-len 1
attr M1 dev-type-VT_Time-unpack n
attr M1 obj-c1009-map 0:false, 1:true
attr M1 obj-c1009-polldelay 3600
attr M1 obj-c1009-reading HeatOff
attr M1 obj-c1329-map 0:false, 1:true
attr M1 obj-c1329-polldelay 300
attr M1 obj-c1329-reading HeatIncreaseOff
attr M1 obj-c1409-map 0:0, 1:1=2, 2:1->2, 3:1->2->3
attr M1 obj-c1409-polldelay 60
attr M1 obj-c1409-reading AuxilaryModeHeating
attr M1 obj-c1457-map 0:false, 1:true
attr M1 obj-c1457-reading CoolOff
attr M1 obj-c1633-map 0:false, 1:true
attr M1 obj-c1633-reading DomesticWaterOff
attr M1 obj-h1-len 13
attr M1 obj-h1-poll 0
attr M1 obj-h1-reading RTCTime
attr M1 obj-h1-unpack H*
attr M1 obj-h1025-polldelay 86400
attr M1 obj-h1025-reading HeatTimeOn
attr M1 obj-h1025-type VT_Time
attr M1 obj-h1041-polldelay 86400
attr M1 obj-h1041-reading HeatTimeOff
attr M1 obj-h1041-type VT_Time
attr M1 obj-h1057-max 30
attr M1 obj-h1057-min 10
attr M1 obj-h1057-reading HeatCharacteristicSetPoint
attr M1 obj-h1057-type VT_R4
attr M1 obj-h1089-max 65
attr M1 obj-h1089-min 15
attr M1 obj-h1089-reading HeatCharacteristicSetPointBaseTemp
attr M1 obj-h1089-set 1
attr M1 obj-h1089-type VT_R4
attr M1 obj-h1121-max 100
attr M1 obj-h1121-min 0
attr M1 obj-h1121-reading HeatCharacteristicGradient
attr M1 obj-h1121-type VT_R4
attr M1 obj-h1153-max 72
attr M1 obj-h1153-min 10
attr M1 obj-h1153-reading HeatCharacteristicLimit
attr M1 obj-h1153-type VT_R4
attr M1 obj-h1185-reading HeatReturnTemp
attr M1 obj-h1185-type VT_R4
attr M1 obj-h1249-max 3
attr M1 obj-h1249-min 1
attr M1 obj-h1249-reading HeatTempHyst
attr M1 obj-h1249-type VT_R4
attr M1 obj-h1281-reading RoomTempNominal
attr M1 obj-h1281-type VT_R4
attr M1 obj-h1313-len 1
attr M1 obj-h1313-max 200
attr M1 obj-h1313-min 0
attr M1 obj-h1313-reading RoomTempFactor
attr M1 obj-h1313-unpack S>
attr M1 obj-h1345-polldelay 86400
attr M1 obj-h1345-reading HeatIncreaseTimeOn
attr M1 obj-h1345-type VT_Time
attr M1 obj-h1361-polldelay 86400
attr M1 obj-h1361-reading HeatIncreaseTimeOff
attr M1 obj-h1361-type VT_Time
attr M1 obj-h1377-max 5
attr M1 obj-h1377-min -5
attr M1 obj-h1377-reading HeatIncreaseSetPtOffset
attr M1 obj-h1377-type VT_R4
attr M1 obj-h1425-max 5
attr M1 obj-h1425-min 0
attr M1 obj-h1425-reading AuxilaryMaxDifference
attr M1 obj-h1425-type VT_R4
attr M1 obj-h1473-polldelay 86400
attr M1 obj-h1473-reading CoolTimeOn
attr M1 obj-h1473-type VT_Time
attr M1 obj-h1489-polldelay 86400
attr M1 obj-h1489-reading CoolTimeOff
attr M1 obj-h1489-type VT_Time
attr M1 obj-h1505-max 30
attr M1 obj-h1505-min 18
attr M1 obj-h1505-reading CoolCharacteristicSetPoint
attr M1 obj-h1505-type VT_R4
attr M1 obj-h1569-reading CoolReturnTempNominal
attr M1 obj-h1569-type VT_R4
attr M1 obj-h1601-max 3
attr M1 obj-h1601-min 1
attr M1 obj-h1601-reading CoolReturnTempHyst
attr M1 obj-h1601-type VT_R4
attr M1 obj-h1649-polldelay 86400
attr M1 obj-h1649-reading DomesticWaterTimeOn
attr M1 obj-h1649-type VT_Time
attr M1 obj-h1665-polldelay 86400
attr M1 obj-h1665-reading DomesticWaterTimeOff
attr M1 obj-h1665-type VT_Time
attr M1 obj-h1713-reading DomesticWaterTempNominal
attr M1 obj-h1713-set 1
attr M1 obj-h1713-type VT_R4
attr M1 obj-h1745-max 10
attr M1 obj-h1745-min 5
attr M1 obj-h1745-reading DomesticWaterTempHyst
attr M1 obj-h1745-type VT_R4
attr M1 obj-h1777-len 16
attr M1 obj-h1777-polldelay 86400
attr M1 obj-h1777-reading LegionellaSchedule
attr M1 obj-h1777-unpack H*
attr M1 obj-h1793-polldelay 86400
attr M1 obj-h1793-type VT_Time
attr M1 obj-h1809-polldelay 86400
attr M1 obj-h1809-reading LegionellaTimeOff
attr M1 obj-h1809-type VT_Time
attr M1 obj-h209-len 13
attr M1 obj-h209-poll 0
attr M1 obj-h209-reading RTCDate
attr M1 obj-h209-unpack H*
attr M1 obj-h417-len 1
attr M1 obj-h417-polldelay 86400
attr M1 obj-h417-reading LngSelect
attr M1 obj-h4497-reading PElectric
attr M1 obj-h4497-type VT_R4
attr M1 obj-h4529-reading PThermal
attr M1 obj-h4529-type VT_R4
attr M1 obj-h4689-polldelay 86400
attr M1 obj-h4689-reading FirmwareVersion
attr M1 obj-h4689-showGet 1
attr M1 obj-h4689-type VT_String
attr M1 obj-h4689-unpack (a*)
attr M1 obj-h4817-polldelay 86400
attr M1 obj-h4817-reading FirmwareDate
attr M1 obj-h4817-type VT_String
attr M1 obj-h4945-polldelay 86400
attr M1 obj-h4945-reading ManufType
attr M1 obj-h4945-type VT_String
attr M1 obj-h5073-polldelay 86400
attr M1 obj-h5073-reading ManufSerialNum
attr M1 obj-h5073-type VT_String
attr M1 obj-h5457-len 1
attr M1 obj-h5457-map 0048:Kühlung, 0040:Idle, 0051:Warmwasser, 0052:Heizung
attr M1 obj-h5457-reading OperatingState
attr M1 obj-h5457-unpack H*
attr M1 obj-h5505-len 16
attr M1 obj-h5505-reading ADC_Error
attr M1 obj-h5505-unpack H*
attr M1 obj-h5521-reading LCD_Display_Line_1
attr M1 obj-h5521-type VT_String
attr M1 obj-h5649-reading LCD_Display_Line_2
attr M1 obj-h5649-type VT_String
attr M1 obj-i1217-reading HeatReturnTempNominal
attr M1 obj-i1537-reading CoolReturnTemp
attr M1 obj-i1681-reading DomesticWaterTempActual
attr M1 obj-i2625-reading OHCompressor1
attr M1 obj-i2657-reading OHCompressor2
attr M1 obj-i2689-reading OHHeatingCompressor
attr M1 obj-i2721-reading OHHeatingAuxilary
attr M1 obj-i2753-reading OHCooling
attr M1 obj-i2785-reading OHDomesticWaterCompressor
attr M1 obj-i433-reading OutdoorTemp
attr M1 obj-i433-showGet 1
attr M1 obj-i4561-reading COP
attr M1 obj-i4561-showGet 1
attr M1 obj-i465-reading OutdoorTemp1h
attr M1 obj-i497-reading OutdoorTemp24h
attr M1 obj-i529-reading HeatSourceIn
attr M1 obj-i561-reading HeatSourceOut
attr M1 obj-i593-reading EvaporationTemp
attr M1 obj-i625-reading SuctionGasTemp
attr M1 obj-i657-reading EvaporationPress
attr M1 obj-i689-reading ReturnTempNominal
attr M1 obj-i721-reading ReturnTemp
attr M1 obj-i753-reading FlowTemp
attr M1 obj-i785-reading CondensationTemp
attr M1 obj-i817-reading CondensationPress
attr M1 obj-i849-reading RoomTemp
attr M1 obj-i881-reading RoomTemp1h
attr M1 obj-i913-reading DomesticWaterTemp
attr M1 obj-i945-reading PoolTemp
attr M1 obj-i977-reading SolarTemp
attr M1 sortUpdate 1

View File

@ -0,0 +1,52 @@
##############################################
# test request parsing
##############################################
use strict;
use warnings;
use Test::More;
use Time::HiRes qw( gettimeofday tv_interval); # return time as float, not just full seconds
use FHEM::HTTPMOD::Utils qw(:all);
use FHEM::Modbus::TestUtils qw(:all);
fhem 'attr global mseclog 1';
SetTestOptions(
{ IODevice => 'MS', # for loginform
#RespondTo => 'MS: Simulate sending to none: (.*)', # auto reponder / go to next step at reception
Time1Name => 'busy',
Time1Regex => qr{Fhem is still waiting},
Time2Name => 'queue run',
Time2Regex => qr{ProcessRequestQueue called from Fhem internal timer as queue:MS},
}
);
NextStep();
sub testStep1 {
findTimesInLog();
fhem 'get M1 SolarTemp';
fhem 'get M5 TempWasserEin';
return 0.5;
}
sub testStep2 {
findTimesInLog();
FhemTestUtils_resetLogs();
return 0.5;
}
sub testStep3 {
findTimesInLog();
FhemTestUtils_resetLogs();
my ($commDelay, $sendDelay, $lastDelay) = calcDelays();
# check no delay between read (get SolarTemp) after Step 0 and send (get HeatOff) in step 1
ok($sendDelay < 0.5, 'queue delay not too big');
ok($sendDelay > 0.3, 'queue delay not too small');
}
1;

View File

@ -0,0 +1,9 @@
define M1 ModbusAttr 1 1
attr M1 verbose 5
attr M1 obj-h10-reading o1
attr M1 obj-h10-map 0:off, 1:on
attr M1 obj-h11-reading o2
attr M1 obj-h11-hint 1,2,3
attr M1 dev-h-defSet 1

View File

@ -0,0 +1,18 @@
##############################################
# test hints for set
##############################################
use strict;
use warnings;
use Test::More;
fhem 'set M1 ?';
is(FhemTestUtils_gotLog('choose one of .* o1:off,on o2:1,2,3'), 1, "hints in log");
InternalTimer(gettimeofday() + 0.2, "testStepEnd", 0);
sub testStepEnd {
done_testing;
exit(0);
}
1;

View File

@ -0,0 +1,7 @@
define MS Modbus none
attr Master verbose 5
attr MS clientSwitchDelay 0
attr MS busDelay 0
attr MS verbose 5
attr global mseclog 1

View File

@ -0,0 +1,109 @@
##############################################
# test master slave end to end
# attr disable
# and set inactive / set active
##############################################
use strict;
use warnings;
use Test::More;
use Time::HiRes qw(gettimeofday tv_interval); # return time as float, not just full seconds
use FHEM::HTTPMOD::Utils qw(:all);
use Data::Dumper;
InternalTimer(gettimeofday() + 0.1, "testStep1", 0);
sub testStep1 {
Log3 undef, 1, "----------------";
Log3 undef, 1, "TestStep1: define Master over MS";
fhem ('define Master ModbusAttr 5 0');
InternalTimer(gettimeofday() + 0.1, "testStep2", 0);
}
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");
fhem ('define Master2 ModbusAttr 4 0');
InternalTimer(gettimeofday() + 0.1, "testStep3", 0);
}
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");
fhem ('define Master3 ModbusAttr 4 0 ASCII');
fhem ('attr Master3 enableSetInactive 1');
fhem ('attr Master3 verbose 5');
fhem ('attr Master3 obj-h100-reading test');
fhem ('attr Master3 obj-h100-showGet 1');
InternalTimer(gettimeofday() + 0.1, "testStep4", 0);
}
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)");
FhemTestUtils_resetLogs();
fhem ('attr Master disable 1');
fhem ('get Master3 test');
InternalTimer(gettimeofday() + 0.1, "testStep5", 0);
}
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)");
FhemTestUtils_resetLogs();
fhem ('attr Master2 disable 1');
fhem ('get Master3 test');
InternalTimer(gettimeofday() + 0.1, "testStep6", 0);
}
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");
FhemTestUtils_resetLogs();
fhem ('define Slave1 ModbusAttr 10 slave ASCII');
InternalTimer(gettimeofday() + 0.1, "testStep7", 0);
}
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");
fhem ('delete Slave1');
fhem ('attr Master3 disable 1');
fhem ('define Slave1 ModbusAttr 10 slave ASCII');
InternalTimer(gettimeofday() + 0.1, "testStep8", 0);
}
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;

View File

@ -0,0 +1,250 @@
define MS Modbus none
attr MS verbose 5
attr MS clientSwitchDelay 0
attr MS busDelay 0
attr MS skipGarbage 1
define M5 ModbusAttr 5 passive
attr M5 verbose 5
attr M5 dev-timing-sendDelay 0
attr M5 dev-timing-commDelay 0
attr M5 nonPrioritizedGet 1
attr M5 obj-h256-reading TempWasserEin
attr M5 obj-h258-reading TempWasserAus
attr M5 obj-h10-reading o1
attr M5 obj-h10-map 0:off, 1:on
attr M5 obj-h10-set 1
attr M5 obj-h11-reading o2
attr M5 obj-h11-hint 1,2,3
attr M5 dev-h-defSet 1
attr M5 dev-h-defShowGet 1
define M254 ModbusAttr 254 passive
attr M254 verbose 5
attr M254 dev-timing-sendDelay 0
attr M254 dev-timing-commDelay 0
attr M254 nonPrioritizedGet 1
attr M254 obj-h256-reading TempWasserEin
attr M254 obj-h258-reading TempWasserAus
attr M254 obj-h10-reading o1
attr M254 obj-h10-map 0:off, 1:on
attr M254 obj-h10-set 1
attr M254 obj-h11-reading o2
attr M254 obj-h11-hint 1,2,3
attr M254 dev-h-defSet 1
attr M254 dev-h-defShowGet 1
define M1 ModbusAttr 1 passive
attr M1 verbose 5
attr M1 dev-timing-sendDelay 0
attr M1 dev-timing-commDelay 0
attr M1 nonPrioritizedGet 1
attr M1 dev-c-defPoll 1
attr M1 dev-h-combine 5
attr M1 dev-h-defLen 2
attr M1 dev-h-defPoll 1
attr M1 dev-h-defRevRegs 1
attr M1 dev-h-write 16
attr M1 dev-i-defFormat %.1f
attr M1 dev-i-defLen 2
attr M1 dev-i-defPoll 1
attr M1 dev-i-defRevRegs 1
attr M1 dev-i-defUnpack f>
attr M1 dev-type-VT_Date-expr sprintf("%02d.%02d",($val >> 8),($val & 0xff))
attr M1 dev-type-VT_Date-len 1
attr M1 dev-type-VT_Date-unpack n
attr M1 dev-type-VT_R4-format %.1f
attr M1 dev-type-VT_R4-len 2
attr M1 dev-type-VT_R4-revRegs 1
attr M1 dev-type-VT_R4-unpack f>
attr M1 dev-type-VT_String-bswapRegs 1
attr M1 dev-type-VT_String-decode cp850
attr M1 dev-type-VT_String-encode utf8
attr M1 dev-type-VT_String-expr $val =~ s/[\00]+//gr
attr M1 dev-type-VT_String-len 8
attr M1 dev-type-VT_String-revRegs 0
attr M1 dev-type-VT_String-unpack a*
attr M1 dev-type-VT_Time-expr sprintf("%02d:%02d",($val >> 8),($val & 0xff))
attr M1 dev-type-VT_Time-len 1
attr M1 dev-type-VT_Time-unpack n
attr M1 obj-c1009-map 0:false, 1:true
attr M1 obj-c1009-polldelay 3600
attr M1 obj-c1009-reading HeatOff
attr M1 obj-c1329-map 0:false, 1:true
attr M1 obj-c1329-polldelay 300
attr M1 obj-c1329-reading HeatIncreaseOff
attr M1 obj-c1409-map 0:0, 1:1=2, 2:1->2, 3:1->2->3
attr M1 obj-c1409-polldelay 60
attr M1 obj-c1409-reading AuxilaryModeHeating
attr M1 obj-c1457-map 0:false, 1:true
attr M1 obj-c1457-reading CoolOff
attr M1 obj-c1633-map 0:false, 1:true
attr M1 obj-c1633-reading DomesticWaterOff
attr M1 obj-h1-len 13
attr M1 obj-h1-poll 0
attr M1 obj-h1-reading RTCTime
attr M1 obj-h1-unpack H*
attr M1 obj-h1025-polldelay 86400
attr M1 obj-h1025-reading HeatTimeOn
attr M1 obj-h1025-type VT_Time
attr M1 obj-h1041-polldelay 86400
attr M1 obj-h1041-reading HeatTimeOff
attr M1 obj-h1041-type VT_Time
attr M1 obj-h1057-max 30
attr M1 obj-h1057-min 10
attr M1 obj-h1057-reading HeatCharacteristicSetPoint
attr M1 obj-h1057-type VT_R4
attr M1 obj-h1089-max 65
attr M1 obj-h1089-min 15
attr M1 obj-h1089-reading HeatCharacteristicSetPointBaseTemp
attr M1 obj-h1089-set 1
attr M1 obj-h1089-type VT_R4
attr M1 obj-h1121-max 100
attr M1 obj-h1121-min 0
attr M1 obj-h1121-reading HeatCharacteristicGradient
attr M1 obj-h1121-type VT_R4
attr M1 obj-h1153-max 72
attr M1 obj-h1153-min 10
attr M1 obj-h1153-reading HeatCharacteristicLimit
attr M1 obj-h1153-type VT_R4
attr M1 obj-h1185-reading HeatReturnTemp
attr M1 obj-h1185-type VT_R4
attr M1 obj-h1249-max 3
attr M1 obj-h1249-min 1
attr M1 obj-h1249-reading HeatTempHyst
attr M1 obj-h1249-type VT_R4
attr M1 obj-h1281-reading RoomTempNominal
attr M1 obj-h1281-type VT_R4
attr M1 obj-h1313-len 1
attr M1 obj-h1313-max 200
attr M1 obj-h1313-min 0
attr M1 obj-h1313-reading RoomTempFactor
attr M1 obj-h1313-unpack S>
attr M1 obj-h1345-polldelay 86400
attr M1 obj-h1345-reading HeatIncreaseTimeOn
attr M1 obj-h1345-type VT_Time
attr M1 obj-h1361-polldelay 86400
attr M1 obj-h1361-reading HeatIncreaseTimeOff
attr M1 obj-h1361-type VT_Time
attr M1 obj-h1377-max 5
attr M1 obj-h1377-min -5
attr M1 obj-h1377-reading HeatIncreaseSetPtOffset
attr M1 obj-h1377-type VT_R4
attr M1 obj-h1425-max 5
attr M1 obj-h1425-min 0
attr M1 obj-h1425-reading AuxilaryMaxDifference
attr M1 obj-h1425-type VT_R4
attr M1 obj-h1473-polldelay 86400
attr M1 obj-h1473-reading CoolTimeOn
attr M1 obj-h1473-type VT_Time
attr M1 obj-h1489-polldelay 86400
attr M1 obj-h1489-reading CoolTimeOff
attr M1 obj-h1489-type VT_Time
attr M1 obj-h1505-max 30
attr M1 obj-h1505-min 18
attr M1 obj-h1505-reading CoolCharacteristicSetPoint
attr M1 obj-h1505-type VT_R4
attr M1 obj-h1569-reading CoolReturnTempNominal
attr M1 obj-h1569-type VT_R4
attr M1 obj-h1601-max 3
attr M1 obj-h1601-min 1
attr M1 obj-h1601-reading CoolReturnTempHyst
attr M1 obj-h1601-type VT_R4
attr M1 obj-h1649-polldelay 86400
attr M1 obj-h1649-reading DomesticWaterTimeOn
attr M1 obj-h1649-type VT_Time
attr M1 obj-h1665-polldelay 86400
attr M1 obj-h1665-reading DomesticWaterTimeOff
attr M1 obj-h1665-type VT_Time
attr M1 obj-h1713-reading DomesticWaterTempNominal
attr M1 obj-h1713-set 1
attr M1 obj-h1713-type VT_R4
attr M1 obj-h1745-max 10
attr M1 obj-h1745-min 5
attr M1 obj-h1745-reading DomesticWaterTempHyst
attr M1 obj-h1745-type VT_R4
attr M1 obj-h1777-len 16
attr M1 obj-h1777-polldelay 86400
attr M1 obj-h1777-reading LegionellaSchedule
attr M1 obj-h1777-unpack H*
attr M1 obj-h1793-polldelay 86400
attr M1 obj-h1793-type VT_Time
attr M1 obj-h1809-polldelay 86400
attr M1 obj-h1809-reading LegionellaTimeOff
attr M1 obj-h1809-type VT_Time
attr M1 obj-h209-len 13
attr M1 obj-h209-poll 0
attr M1 obj-h209-reading RTCDate
attr M1 obj-h209-unpack H*
attr M1 obj-h417-len 1
attr M1 obj-h417-polldelay 86400
attr M1 obj-h417-reading LngSelect
attr M1 obj-h4497-reading PElectric
attr M1 obj-h4497-type VT_R4
attr M1 obj-h4529-reading PThermal
attr M1 obj-h4529-type VT_R4
attr M1 obj-h4689-polldelay 86400
attr M1 obj-h4689-reading FirmwareVersion
attr M1 obj-h4689-showGet 1
attr M1 obj-h4689-type VT_String
attr M1 obj-h4689-unpack (a*)
attr M1 obj-h4817-polldelay 86400
attr M1 obj-h4817-reading FirmwareDate
attr M1 obj-h4817-type VT_String
attr M1 obj-h4945-polldelay 86400
attr M1 obj-h4945-reading ManufType
attr M1 obj-h4945-type VT_String
attr M1 obj-h5073-polldelay 86400
attr M1 obj-h5073-reading ManufSerialNum
attr M1 obj-h5073-type VT_String
attr M1 obj-h5457-len 1
attr M1 obj-h5457-map 0048:Kühlung, 0040:Idle, 0051:Warmwasser, 0052:Heizung
attr M1 obj-h5457-reading OperatingState
attr M1 obj-h5457-unpack H*
attr M1 obj-h5505-len 16
attr M1 obj-h5505-reading ADC_Error
attr M1 obj-h5505-unpack H*
attr M1 obj-h5521-reading LCD_Display_Line_1
attr M1 obj-h5521-type VT_String
attr M1 obj-h5649-reading LCD_Display_Line_2
attr M1 obj-h5649-type VT_String
attr M1 obj-i1217-reading HeatReturnTempNominal
attr M1 obj-i1537-reading CoolReturnTemp
attr M1 obj-i1681-reading DomesticWaterTempActual
attr M1 obj-i2625-reading OHCompressor1
attr M1 obj-i2657-reading OHCompressor2
attr M1 obj-i2689-reading OHHeatingCompressor
attr M1 obj-i2721-reading OHHeatingAuxilary
attr M1 obj-i2753-reading OHCooling
attr M1 obj-i2785-reading OHDomesticWaterCompressor
attr M1 obj-i433-reading OutdoorTemp
attr M1 obj-i433-showGet 1
attr M1 obj-i4561-reading COP
attr M1 obj-i4561-showGet 1
attr M1 obj-i465-reading OutdoorTemp1h
attr M1 obj-i497-reading OutdoorTemp24h
attr M1 obj-i529-reading HeatSourceIn
attr M1 obj-i561-reading HeatSourceOut
attr M1 obj-i593-reading EvaporationTemp
attr M1 obj-i625-reading SuctionGasTemp
attr M1 obj-i657-reading EvaporationPress
attr M1 obj-i689-reading ReturnTempNominal
attr M1 obj-i721-reading ReturnTemp
attr M1 obj-i753-reading FlowTemp
attr M1 obj-i785-reading CondensationTemp
attr M1 obj-i817-reading CondensationPress
attr M1 obj-i849-reading RoomTemp
attr M1 obj-i881-reading RoomTemp1h
attr M1 obj-i913-reading DomesticWaterTemp
attr M1 obj-i945-reading PoolTemp
attr M1 obj-i977-reading SolarTemp
attr M1 sortUpdate 1

View File

@ -0,0 +1,147 @@
##############################################
# test passive reception
##############################################
package main;
use strict;
use warnings;
use Test::More;
use Time::HiRes qw( gettimeofday tv_interval); # return time as float, not just full seconds
use FHEM::HTTPMOD::Utils 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';
InternalTimer(gettimeofday()+5, "testStepLast", 0); # last resort
NextStep();
sub testStep1 {
LogStep "send first request in parts";
FhemTestUtils_resetLogs();
SimRead('MS', \&Modbus::ReadFn, 'fe03'); # part of a request
return;
}
sub testStep2 {
FhemTestUtils_resetLogs();
SimRead('MS', \&Modbus::ReadFn, '0164000810'); # part of a request
return;
}
sub testStep3 {
FhemTestUtils_resetLogs();
SimRead('MS', \&Modbus::ReadFn, '20'); # final part of a request
return;
}
sub testStep4 {
LogStep "check reception of request and send another request";
is(FhemTestUtils_gotLog('received valid request, now wait for the reponse'), 1, "first request reassembled correctly");
FhemTestUtils_resetLogs();
FhemTestUtils_resetEvents();
SimRead('MS', \&Modbus::ReadFn, 'fe03016400081020'); # another request
return;
}
sub testStep5 {
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('received valid request, now wait for the reponse'), 1, "second request interpreted");
FhemTestUtils_resetLogs();
FhemTestUtils_resetEvents();
SimRead('MS', \&Modbus::ReadFn,'fe03100000000b000000400000011a00000167f378'); # the reply
return;
}
sub testStep6 {
LogStep "check reception of reply and send another repeated reply";
is(FhemTestUtils_gotLog('ParseObj has no information about handling h356'), 1, "try parsing registers");
FhemTestUtils_resetLogs();
FhemTestUtils_resetEvents();
SimRead('MS', \&Modbus::ReadFn,'fe03100000000b000000400000011a00000167f378'); # the reply repeated
return;
}
sub testStep7 {
LogStep "check reception of repeated reply";
is(FhemTestUtils_gotLog('ParseObj has no information about handling'), 0, "no try parsing registers again since request is missing");
is(FhemTestUtils_gotLog('HandleResponse got data but we don.t have a request'), 1, "next response without a request seen");
FhemTestUtils_resetLogs();
FhemTestUtils_resetEvents();
SimRead('MS', \&Modbus::ReadFn, 'fe03064000810209'); # a broken frame
return;
}
sub testStep8 {
is(FhemTestUtils_gotLog('HandleRequest Done, error: '), 1, "invalid frame");
FhemTestUtils_resetLogs();
SimRead('MS', \&Modbus::ReadFn, 'fe03016400081020'); # another request
return;
}
sub testStep9 {
is(FhemTestUtils_gotLog('received valid request, now wait for the reponse'), 1, "request after garbage interpreted");
FhemTestUtils_resetLogs();
return;
}
sub testStep10 {
LogStep "check broken frame with illegal fcode";
FhemTestUtils_resetLogs();
FhemTestUtils_resetEvents();
SimRead('MS', \&Modbus::ReadFn, 'fe00064000810209'); # a broken frame
return;
}
sub testStep11 {
is(FhemTestUtils_gotLog('HandleRequest Done, error:'), 1, "invalid frame");
FhemTestUtils_resetLogs();
SimRead('MS', \&Modbus::ReadFn, 'fe03016400081020'); # another request
return;
}
sub testStep12 {
is(FhemTestUtils_gotLog('received valid request, now wait for the reponse'), 1, "request after illegal fcode interpreted");
FhemTestUtils_resetLogs();
return;
}
1;

View File

@ -0,0 +1,83 @@
define MS Modbus none
attr MS verbose 5
attr MS clientSwitchDelay 0
attr MS busDelay 0
define PWP ModbusAttr 5 0
attr PWP verbose 5
attr PWP dev-timing-sendDelay 0
attr PWP dev-timing-commDelay 0
attr PWP dev-timing-timeout 1
attr PWP dev-h-defSet 1
attr PWP dev-h-defShowGet 1
attr PWP dev-h-combine 16
attr M5 nonPrioritizedGet 1
attr PWP obj-h256-reading Temp_Wasser_Ein
attr PWP obj-h256-expr $val / 10
attr PWP obj-h256-poll 1
attr PWP obj-h256-polldelay 0
attr PWP obj-h258-reading Temp_Wasser_Aus
attr PWP obj-h258-expr $val / 10
attr PWP obj-h258-poll 1
attr PWP obj-h258-polldelay 0
attr PWP obj-h260-reading Temp_Verdampfer
attr PWP obj-h260-expr $val / 10
attr PWP obj-h260-poll 1
attr PWP obj-h260-polldelay 0
attr PWP obj-h262-reading Temp_Luft
attr PWP obj-h262-expr $val / 10
attr PWP obj-h262-poll 0
attr PWP obj-h770-reading Temp_Soll
attr PWP obj-h770-expr $val / 10
attr PWP obj-h770-hint 8,10,20,25,28,29,30,30.5,31,31.5,32
attr PWP obj-h770-max 32
attr PWP obj-h770-min 10
attr PWP obj-h770-set 1
attr PWP obj-h770-setexpr $val * 10
attr PWP obj-h771-reading Hysterese
attr PWP obj-h771-expr $val / 10
attr PWP obj-h771-max 3
attr PWP obj-h771-min 0.5
attr PWP obj-h771-set 1
attr PWP obj-h771-setexpr $val * 10
attr PWP obj-h777-reading Hyst_Mode
attr PWP obj-h777-map 0:mittig, 1:über, 2:unterhalb
attr PWP obj-h777-set 1
attr PWP obj-h801-reading Temp_Wasser_Ein_Off
attr PWP obj-h801-expr $val / 10
attr PWP obj-h801-name CF24
attr PWP obj-h801-poll 0
attr PWP obj-h801-set 1
attr PWP obj-h801-setexpr $val * 10
attr PWP obj-h802-reading Temp_Wasser_Aus_Off
attr PWP obj-h802-expr $val / 10
attr PWP obj-h802-name CF25
attr PWP obj-h802-poll 0
attr PWP obj-h802-set 1
attr PWP obj-h802-setexpr $val * 10
attr PWP obj-h803-reading Temp_Verdampfer_Off
attr PWP obj-h803-expr $val / 10
attr PWP obj-h803-name CF26
attr PWP obj-h803-poll 0
attr PWP obj-h803-set 1
attr PWP obj-h803-setexpr $val * 10
attr PWP obj-h804-reading Temp_Luft_Off
attr PWP obj-h804-expr $val / 10
attr PWP obj-h804-name CF27
attr PWP obj-h804-poll 0
attr PWP obj-h804-set 1
attr PWP obj-h804-setexpr $val * 10

View File

@ -0,0 +1,121 @@
##############################################
# test modbus RTU Master
##############################################
package main;
use strict;
use warnings;
use Test::More;
use Time::HiRes qw( gettimeofday tv_interval); # return time as float, not just full seconds
use FHEM::HTTPMOD::Utils qw(:all);
use FHEM::Modbus::TestUtils qw(:all);
fhem 'attr global mseclog 1';
NextStep();
sub testStep1 {
LogStep('start reread');
FhemTestUtils_resetLogs();
fhem('set PWP reread');
return;
}
sub testStep2 {
LogStep('simulate normal reception');
SimRead('MS', \&Modbus::ReadFn, '05030a0137110001381100010dac7b'); # normal response
return;
}
sub testStep3 {
LogStep('check reception and start second reread');
is(FhemTestUtils_gotEvent(qr/PWP:Temp_Wasser_Ein:\s31\.1/xms), 1, "Parse TempEin");
is(FhemTestUtils_gotEvent(qr/PWP:Temp_Wasser_Aus:\s31\.2/xms), 1, "Parse TempAus");
is(FhemTestUtils_gotEvent(qr/PWP:Temp_Verdampfer:\s26\.9/xms), 1, "Parse TempVerdampfer");
FhemTestUtils_resetLogs();
FhemTestUtils_resetEvents();
fhem('set PWP reread');
return;
}
sub testStep4 {
LogStep('simulate short response');
SimRead('MS', \&Modbus::ReadFn, '05030a013711000138110091a8'); # short response
return 1.1; # next step after 1.1 seconds
}
sub testStep5 {
LogStep('verify failed short response and then allow them and reread');
is(FhemTestUtils_gotLog('frame that looks valid but is too short'), 1, "short frame");
is(FhemTestUtils_gotEvent(qr/PWP:Temp_Wasser_Ein:\s31\.1/xms), 0, "No TempEin");
FhemTestUtils_resetLogs();
FhemTestUtils_resetEvents();
fhem('attr PWP dev-h-allowShortResponses 1');
fhem('set PWP reread');
return;
}
sub testStep6 {
LogStep('simulate another short response');
SimRead('MS', \&Modbus::ReadFn, '05030a013711000138110091a8'); # short response
return;
}
sub testStep7 {
LogStep('verify valid short response reception and send another reread');
is(FhemTestUtils_gotEvent(qr/PWP:Temp_Wasser_Ein:\s31\.1/xms), 1, "Parse TempEin");
is(FhemTestUtils_gotEvent(qr/PWP:Temp_Wasser_Aus:\s31\.2/xms), 1, "Parse TempAus");
is(FhemTestUtils_gotEvent(qr/PWP:Temp_Verdampfer:\s26\.9/xms), 0, "No Parse TempVerdampfer");
FhemTestUtils_resetLogs();
FhemTestUtils_resetEvents();
fhem('attr PWP dev-h-brokenFC3 1');
fhem('set PWP reread');
return;
}
sub testStep8 {
LogStep('simulate broken fc3 response');
SimRead('MS', \&Modbus::ReadFn, '050301000137110001381100010dd04d'); # response type broken FC3
return;
}
sub testStep9 {
LogStep('verify brokenfc3 reception and send another reread');
is(FhemTestUtils_gotEvent(qr/PWP:Temp_Wasser_Ein:\s31\.1/xms), 1, "Parse TempEin");
is(FhemTestUtils_gotEvent(qr/PWP:Temp_Wasser_Aus:\s31\.2/xms), 1, "Parse TempAus");
is(FhemTestUtils_gotEvent(qr/PWP:Temp_Verdampfer:\s26\.9/xms), 1, "Parse TempVerdampfer");
FhemTestUtils_resetLogs();
FhemTestUtils_resetEvents();
fhem('attr PWP dev-h-brokenFC3 0');
return 0.1;
}
sub testStep10 {
LogStep('check polldelay');
fhem('attr PWP obj-h256-polldelay 0');
fhem('attr PWP obj-h258-polldelay 0');
fhem('attr PWP obj-h260-polldelay 0.4');
fhem('set PWP reread');
return;
}
sub testStep11 {
LogStep('check results');
is(FhemTestUtils_gotLog('Simulate sending to none: 05030100000305b3'), 1, "request for 256 and 258 without 260 seen");
return;
}
1;

View File

@ -0,0 +1,127 @@
attr global mseclog 1
define D1 dummy
define Slave ModbusAttr 5 slave global:5501
attr Slave obj-h256-reading TempWasserEin
attr Slave obj-h258-reading D1:TempWasserAus
attr Slave obj-h100-reading Test1
attr Slave obj-h100-setexpr $val * 4
attr Slave obj-h101-reading Test2
attr Slave obj-h101-unpack f>
attr Slave obj-h101-len 2
attr Slave obj-h103-reading Test3
attr Slave obj-h103-unpack a8
attr Slave obj-h103-len 4
attr Slave obj-h120-reading Test4
attr Slave obj-h120-unpack f>
attr Slave obj-h120-len 2
attr Slave obj-h130-reading Test5
attr Slave obj-h130-unpack a*
attr Slave obj-h130-len 2
attr Slave obj-c400-reading c0
attr Slave obj-c401-reading c1
attr Slave obj-c402-reading c2
attr Slave obj-c403-reading c3
attr Slave obj-c404-reading c4
attr Slave obj-c405-reading c5
attr Slave obj-c406-reading c6
attr Slave obj-c407-reading c7
attr Slave obj-c408-reading c8
attr Slave obj-c409-reading c9
attr Slave obj-c410-reading c10
attr Slave obj-c411-reading c11
attr Slave obj-c412-reading c12
attr Slave obj-c413-reading c13
attr Slave obj-c414-reading c14
attr Slave obj-c415-reading c15
attr Slave obj-c416-reading c16
attr Slave obj-c417-reading c17
attr Slave obj-c418-reading c18
define Master ModbusAttr 5 0 localhost:5501
attr Master disable 1
attr Master verbose 3
attr Master nonPrioritizedGet 1
attr Master nonPrioritizedSet 1
attr Master dev-timing-sendDelay 0
attr Master dev-timing-commDelay 0
attr Master obj-h256-reading TempWasserEin
attr Master obj-h258-reading TempWasserAus
attr Master obj-h100-reading Test1
attr Master obj-h100-expr $val + 2
attr Master obj-h100-poll 1
attr Master obj-h100-polldelay 0
attr Master obj-h101-reading Test2
attr Master obj-h101-unpack f>
attr Master obj-h101-len 2
attr Master obj-h101-format %.2f
attr Master obj-h101-poll 1
attr Master obj-h101-polldelay 0
attr Master obj-h103-reading Test3
attr Master obj-h103-unpack a8
attr Master obj-h103-len 4
attr Master obj-h103-poll 1
attr Master obj-h103-polldelay 0
attr Master obj-h120-reading Test4
attr Master obj-h120-unpack f>
attr Master obj-h120-len 2
attr Master obj-h120-format %.2f
attr Master obj-h120-poll 1
attr Master obj-h120-ignoreExpr $val > 10
attr Master obj-h120-polldelay 0
attr Master obj-h130-reading Test5
attr Master obj-h130-unpack a*
attr Master obj-h130-len 2
attr Master obj-h130-encode utf8
attr Master obj-h10-reading o1
attr Master obj-h10-map 0:off, 1:on
attr Master obj-h11-reading o2
attr Master obj-h11-min 1
attr Master obj-h11-max 3
attr Master dev-h-defSet 1
attr Master dev-c-defSet 1
attr Master dev-h-defShowGet 1
attr Master obj-c400-reading c0
attr Master obj-c401-reading c1
attr Master obj-c402-reading c2
attr Master obj-c403-reading c3
attr Master obj-c404-reading c4
attr Master obj-c405-reading c5
attr Master obj-c406-reading c6
attr Master obj-c407-reading c7
attr Master obj-c408-reading c8
attr Master obj-c409-reading c9
attr Master obj-c410-reading c10
attr Master obj-c411-reading c11
attr Master obj-c412-reading c12
attr Master obj-c413-reading c13
attr Master obj-c414-reading c14
attr Master obj-c415-reading c15
attr Master obj-c416-reading c16
attr Master obj-c417-reading c17
attr Master obj-c418-reading c18
attr Master obj-c400-poll 1
attr Master obj-c405-poll 1
attr Master obj-c406-poll 1
attr Master obj-c417-poll 1
attr Master dev-h-combine 19
attr Master dev-c-combine 32

View File

@ -0,0 +1,231 @@
##############################################
# test master slave end to end
##############################################
package main;
use strict;
use warnings;
use Test::More;
use Time::HiRes qw( gettimeofday tv_interval); # return time as float, not just full seconds
use FHEM::HTTPMOD::Utils qw(:all);
use FHEM::Modbus::TestUtils qw(:all);
fhem 'attr global mseclog 1';
InternalTimer(gettimeofday()+5, "testStepLast", 0); # last resort
NextStep();
sub testStep1 { # preparation of slave content, enable devices
is(FhemTestUtils_gotLog('attribute'), 0, "no unknown attributes"); # logs during init are not collected.
LogStep "enable Master and set value at Slave";
fhem ('attr Master disable 0');
fhem ('setreading Slave TempWasserEin 12');
fhem ('setreading Slave Test1 1');
fhem ('setreading Slave Test2 2.123');
fhem ('setreading Slave Test3 abcdefg');
fhem ('setreading Slave Test4 40');
readingsSingleUpdate($defs{'Slave'}, 'Test5', pack('H*', 'e4f6fc'), 0);
fhem ('setreading Slave c0 1');
fhem ('setreading Slave c5 1');
fhem ('setreading Slave c17 1');
return 0.1;
}
sub testStep2 { # get holding registers
LogStep "get TempWasserEin";
fhem ('attr Master verbose 3');
fhem ('attr Slave verbose 3');
fhem ('get Master TempWasserEin');
fhem ('get Master Test1');
fhem ('get Master Test2');
fhem ('get Master Test3');
fhem ('get Master Test4');
fhem ('get Master Test5');
return 0.3;
}
sub testStep3 { # check results
LogStep "check result";
fhem ('attr Master verbose 3');
fhem ('attr Slave verbose 3');
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 1, "Retrieve integer value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test1: 6/), 1, "Retrieve another integer value with expressions on both sides from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test2: 2.12/), 1, "Retrieve float value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test3: abcdefg/), 1, "Retrieve ascii value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test4: 40/), 0, "ignoreExpr prohibits Test4 set to 40");
is(FhemTestUtils_gotEvent(qr/Master:Test5: äöü/), 1, "encode worked for Test5");
return;
}
sub testStep4 { # set holding register without allowance at salve
LogStep "set TempWasserAus at Slave";
fhem ('set Master TempWasserAus 20');
fhem ('attr Master verbose 4');
return 0.2;
}
sub testStep5 { # check that write was forbidden
LogStep "Check error response";
is(FhemTestUtils_gotLog('Master: HandleResponse got response with error code 86 / 01, illegal function'), 1, "disallow write by default");
fhem ('attr Master verbose 3');
return;
}
sub testStep6 { # allow write at slave and try again to write
LogStep "allow write and try again";
fhem ('attr Slave obj-h258-allowWrite 1');
fhem ('set Master TempWasserAus 20');
return 0.1;
}
sub testStep7 { # check that write holding register did work
LogStep "check result";
is(FhemTestUtils_gotEvent(qr/D1:TempWasserAus:\s20/xms), 1, "Write value to local slave");
return 0.1;
}
sub testStep8 { # check input validation at master and write
LogStep "set with map and min/max";
fhem ('set Master o1 one');
is(FhemTestUtils_gotLog('set Master o1 one : set value one did not match defined map'), 1, "map error message in log");
fhem ('set Master o2 0');
is(FhemTestUtils_gotLog('set Master o2 0 : value 0 is not within defined min/max range'), 1, "min error message in log");
fhem ('set Master o2 4');
is(FhemTestUtils_gotLog('set Master o2 4 : value 4 is not within defined min/max range'), 1, "max error message in log");
fhem ('attr Master verbose 4');
fhem ('set Master o2 2');
fhem ('set Master o1 on');
return 0.2;
}
sub testStep9 { # check write data
LogStep "check log for map and set o2 2";
is(FhemTestUtils_gotLog('0506000a0001698c'), 1, "set o1 on message in log");
is(FhemTestUtils_gotLog('0506000b0002784d'), 1, "set O2 2 message in log");
fhem ('attr Master verbose 3');
return 0.1;
}
sub testStep10 { # check combined read of holding registers and coils
LogStep "getUpdate with combine";
FhemTestUtils_resetEvents();
fhem ('attr Master verbose 3');
fhem ('attr Slave verbose 3');
fhem ('set Master reread');
return 0.1;
}
sub testStep11 { # check results coming from slave and write coils to slave
is(FhemTestUtils_gotEvent(qr/Master:Test1: 6/), 1, "Combined retrieve integer value with expressions on both sides from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test2: 2.12/), 1, "Combined retrieve float value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test3: abcdefg/), 1, "Combined Retrieve ascii value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:c0: 1/), 1, "Combined Retrieve coil bit 0 from local slave");
is(FhemTestUtils_gotEvent(qr/Master:c1: 0/), 1, "Combined Retrieve coil bit 1 from local slave");
is(FhemTestUtils_gotEvent(qr/Master:c17: 1/), 1, "Combined Retrieve coil bit 17 from local slave");
fhem ('attr Slave obj-c402-allowWrite 1');
fhem ('attr Master verbose 5');
fhem ('set Master c2 1');
return 0.1;
}
sub testStep12 {
LogStep "check coil comm";
is(FhemTestUtils_gotLog('sending 05050192ff002daf'), 1, "set c2 1 sending message in log");
is(FhemTestUtils_gotEvent(qr/Master:c2: 1/), 1, "fc5 response for coil shows 1 from local slave");
Log3 undef, 1, "TestStep12: try to write with fc16";
fhem ('attr Master verbose 3');
fhem ('attr Slave verbose 3');
fhem ('attr Master dev-h-write 16');
fhem ('set Master TempWasserAus 29');
return 0.1;
}
sub testStep13 {
LogStep "check write result of fc16";
is(FhemTestUtils_gotEvent(qr/D1:TempWasserAus:\s29/xms), 1, "Write value with fc16 to local slave");
return 0.1;
}
sub testStep14 {
LogStep "closeAfterResponse";
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('attr Master closeAfterResponse 1');
fhem ('attr Master verbose 4');
fhem ('set Master reread');
return 0.1;
}
sub testStep15 {
is(FhemTestUtils_gotEvent(qr/Master:Test1: 6/), 1, "Retrieve Test1");
is(FhemTestUtils_gotEvent(qr/Master:Test3: abcdefg/), 1, "Retrieve Test4");
is(FhemTestUtils_gotLog('HandleResponse will close because closeAfterResponse is set and queue is empty'), 1, "closed");
return 0.1;
}
sub testStep16 {
LogStep "try get while closed";
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('get Master TempWasserEin');
fhem ('attr Master queueDelay 0.3');
return 0.1;
}
sub testStep17 {
LogStep "check get result while connection closed";
is(FhemTestUtils_gotLog('device opened'), 1, "device opened");
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 0, "No retrieve from local slave yet");
return 0.3;
}
sub testStep18 {
LogStep "check get result after another delay";
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 1, "retrieve from local slave after open and QueueDelay");
is(FhemTestUtils_gotLog('close because closeAfterResponse'), 1, "device closed again");
return 0.1;
}
sub testStep19 {
LogStep "now that the connection is closed again, try another prioritized get";
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('attr Master nonPrioritizedGet 0');
fhem ('attr Master dev-timing-timeout 0.5');
fhem ('attr Master verbose 5');
fhem ('get Master TempWasserEin');
return 0.1;
}
sub testStep20 {
LogStep "check result after prio get";
is(FhemTestUtils_gotLog('device opened'), 1, "device opened");
is(FhemTestUtils_gotLog('Master: Timeout in Readanswer'), 1, "readanswer called but slave cannot answer while sitting in readanswer");
return;
}
sub testStep21 {
LogStep "check result after prio get";
is(FhemTestUtils_gotLog('Master: read buffer: 050302000c4981'), 1, "answer arrives after readanswer timeout");
return;
}
# todo: different protocols (RTU, ASCII, TCP)
# data type definition
# swap bytes and similar
# unpack variations
# then relay mode
1;

View File

@ -0,0 +1,135 @@
attr global mseclog 1
define D1 dummy
define Slave ModbusAttr 50 slave global:5501
attr Slave obj-h256-reading TempWasserEin
attr Slave obj-h258-reading D1:TempWasserAus
attr Slave obj-h100-reading Test1
attr Slave obj-h100-setexpr $val * 4
attr Slave obj-h101-reading Test2
attr Slave obj-h101-unpack f>
attr Slave obj-h101-len 2
attr Slave obj-h103-reading Test3
attr Slave obj-h103-unpack a8
attr Slave obj-h103-len 4
attr Slave obj-h120-reading Test4
attr Slave obj-h120-unpack f>
attr Slave obj-h120-len 2
attr Slave obj-h130-reading Test5
attr Slave obj-h130-unpack a*
attr Slave obj-h130-len 2
attr Slave obj-c400-reading c0
attr Slave obj-c401-reading c1
attr Slave obj-c402-reading c2
attr Slave obj-c403-reading c3
attr Slave obj-c404-reading c4
attr Slave obj-c405-reading c5
attr Slave obj-c406-reading c6
attr Slave obj-c407-reading c7
attr Slave obj-c408-reading c8
attr Slave obj-c409-reading c9
attr Slave obj-c410-reading c10
attr Slave obj-c411-reading c11
attr Slave obj-c412-reading c12
attr Slave obj-c413-reading c13
attr Slave obj-c414-reading c14
attr Slave obj-c415-reading c15
attr Slave obj-c416-reading c16
attr Slave obj-c417-reading c17
attr Slave obj-c418-reading c18
define RM ModbusAttr 50 0 localhost:5501
attr RM dev-timing-sendDelay 0
attr RM dev-timing-commDelay 0
attr RM disable 1
define Relay ModbusAttr 5 relay localhost:5510 to RM
attr Relay disable 1
define Master ModbusAttr 5 0 localhost:5510
attr Master disable 1
attr Master verbose 3
attr Master nonPrioritizedGet 1
attr Master nonPrioritizedSet 1
attr Master dev-timing-sendDelay 0
attr Master dev-timing-commDelay 0
attr Master obj-h256-reading TempWasserEin
attr Master obj-h258-reading TempWasserAus
attr Master obj-h100-reading Test1
attr Master obj-h100-expr $val + 2
attr Master obj-h100-poll 1
attr Master obj-h100-polldelay 0
attr Master obj-h101-reading Test2
attr Master obj-h101-unpack f>
attr Master obj-h101-len 2
attr Master obj-h101-format %.2f
attr Master obj-h101-poll 1
attr Master obj-h101-polldelay 0
attr Master obj-h103-reading Test3
attr Master obj-h103-unpack a8
attr Master obj-h103-len 4
attr Master obj-h103-poll 1
attr Master obj-h103-polldelay 0
attr Master obj-h120-reading Test4
attr Master obj-h120-unpack f>
attr Master obj-h120-len 2
attr Master obj-h120-format %.2f
attr Master obj-h120-poll 1
attr Master obj-h120-ignoreExpr $val > 10
attr Master obj-h120-polldelay 0
attr Master obj-h130-reading Test5
attr Master obj-h130-unpack a*
attr Master obj-h130-len 2
attr Master obj-h130-encode utf8
attr Master obj-h10-reading o1
attr Master obj-h10-map 0:off, 1:on
attr Master obj-h11-reading o2
attr Master obj-h11-min 1
attr Master obj-h11-max 3
attr Master dev-h-defSet 1
attr Master dev-c-defSet 1
attr Master dev-h-defShowGet 1
attr Master obj-c400-reading c0
attr Master obj-c401-reading c1
attr Master obj-c402-reading c2
attr Master obj-c403-reading c3
attr Master obj-c404-reading c4
attr Master obj-c405-reading c5
attr Master obj-c406-reading c6
attr Master obj-c407-reading c7
attr Master obj-c408-reading c8
attr Master obj-c409-reading c9
attr Master obj-c410-reading c10
attr Master obj-c411-reading c11
attr Master obj-c412-reading c12
attr Master obj-c413-reading c13
attr Master obj-c414-reading c14
attr Master obj-c415-reading c15
attr Master obj-c416-reading c16
attr Master obj-c417-reading c17
attr Master obj-c418-reading c18
attr Master obj-c400-poll 1
attr Master obj-c405-poll 1
attr Master obj-c406-poll 1
attr Master obj-c417-poll 1
attr Master dev-h-combine 19
attr Master dev-c-combine 32

View File

@ -0,0 +1,230 @@
##############################################
# test master slave end to end
##############################################
package main;
use strict;
use warnings;
use Test::More;
use Time::HiRes qw( gettimeofday tv_interval); # return time as float, not just full seconds
use FHEM::HTTPMOD::Utils qw(:all);
use FHEM::Modbus::TestUtils qw(:all);
fhem 'attr global mseclog 1';
InternalTimer(gettimeofday()+5, "testStepLast", 0); # last resort
NextStep();
sub testStep1 { # preparation of slave content, enable devices
is(FhemTestUtils_gotLog('attribute'), 0, "no unknown attributes"); # logs during init are not collected.
LogStep "enable Master and set value at Slave";
fhem ('attr RM disable 0');
fhem ('attr Relay disable 0');
fhem ('attr Master disable 0');
fhem ('setreading Slave TempWasserEin 12');
fhem ('setreading Slave Test1 1');
fhem ('setreading Slave Test2 2.123');
fhem ('setreading Slave Test3 abcdefg');
fhem ('setreading Slave Test4 40');
readingsSingleUpdate($defs{'Slave'}, 'Test5', pack('H*', 'e4f6fc'), 0);
fhem ('setreading Slave c0 1');
fhem ('setreading Slave c5 1');
fhem ('setreading Slave c17 1');
return 0.1;
}
sub testStep2 { # get holding registers
LogStep "get TempWasserEin";
fhem ('attr Master verbose 3');
fhem ('attr Slave verbose 3');
fhem ('attr Relay verbose 3');
fhem ('attr RM verbose 3');
fhem ('get Master TempWasserEin');
fhem ('get Master Test1');
fhem ('get Master Test2');
fhem ('get Master Test3');
fhem ('get Master Test4');
fhem ('get Master Test5');
return 1;
}
sub testStep3 { # check results
LogStep "check result";
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 1, "Retrieve integer value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test1: 6/), 1, "Retrieve another integer value with expressions on both sides from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test2: 2.12/), 1, "Retrieve float value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test3: abcdefg/), 1, "Retrieve ascii value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test4: 40/), 0, "ignoreExpr prohibits Test4 set to 40");
is(FhemTestUtils_gotEvent(qr/Master:Test5: äöü/), 1, "encode worked for Test5");
return;
}
sub testStep4 { # set holding register without allowance at salve
LogStep "set TempWasserAus at Slave";
fhem ('set Master TempWasserAus 20');
fhem ('attr Master verbose 4');
return 0.2;
}
sub testStep5 { # check that write was forbidden
LogStep "Check error response";
is(FhemTestUtils_gotLog('Master: HandleResponse got response with error code 86 / 01, illegal function'), 1, "disallow write by default");
fhem ('attr Master verbose 3');
return;
}
sub testStep6 { # allow write at slave and try again to write
LogStep "allow write and try again";
fhem ('attr Slave obj-h258-allowWrite 1');
fhem ('set Master TempWasserAus 20');
return 0.1;
}
sub testStep7 { # check that write holding register did work
LogStep "check result";
is(FhemTestUtils_gotEvent(qr/D1:TempWasserAus:\s20/xms), 1, "Write value to local slave");
return 0.1;
}
sub testStep8 { # check input validation at master and write
LogStep "set with map and min/max";
fhem ('set Master o1 one');
is(FhemTestUtils_gotLog('set Master o1 one : set value one did not match defined map'), 1, "map error message in log");
fhem ('set Master o2 0');
is(FhemTestUtils_gotLog('set Master o2 0 : value 0 is not within defined min/max range'), 1, "min error message in log");
fhem ('set Master o2 4');
is(FhemTestUtils_gotLog('set Master o2 4 : value 4 is not within defined min/max range'), 1, "max error message in log");
fhem ('attr Master verbose 4');
fhem ('set Master o2 2');
fhem ('set Master o1 on');
return 0.2;
}
sub testStep9 { # check write data
LogStep "check log for map and set o2 2";
is(FhemTestUtils_gotLog('0506000a0001698c'), 1, "set o1 on message in log");
is(FhemTestUtils_gotLog('0506000b0002784d'), 1, "set O2 2 message in log");
fhem ('attr Master verbose 3');
return 0.1;
}
sub testStep10 { # check combined read of holding registers and coils
LogStep "getUpdate with combine";
FhemTestUtils_resetEvents();
fhem ('set Master reread');
return 0.1;
}
sub testStep11 { # check results coming from slave and write coils to slave
is(FhemTestUtils_gotEvent(qr/Master:Test1: 6/), 1, "Combined retrieve integer value with expressions on both sides from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test2: 2.12/), 1, "Combined retrieve float value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test3: abcdefg/), 1, "Combined Retrieve ascii value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:c0: 1/), 1, "Combined Retrieve coil bit 0 from local slave");
is(FhemTestUtils_gotEvent(qr/Master:c1: 0/), 1, "Combined Retrieve coil bit 1 from local slave");
is(FhemTestUtils_gotEvent(qr/Master:c17: 1/), 1, "Combined Retrieve coil bit 17 from local slave");
fhem ('attr Slave obj-c402-allowWrite 1');
fhem ('attr Master verbose 5');
fhem ('set Master c2 1');
return 0.1;
}
sub testStep12 {
LogStep "check coil comm";
is(FhemTestUtils_gotLog('sending 05050192ff002daf'), 1, "set c2 1 sending message in log");
is(FhemTestUtils_gotEvent(qr/Master:c2: 1/), 1, "fc5 response for coil shows 1 from local slave");
Log3 undef, 1, "TestStep12: try to write with fc16";
fhem ('attr Master verbose 3');
fhem ('attr Slave verbose 3');
fhem ('attr Master dev-h-write 16');
fhem ('set Master TempWasserAus 29');
return 0.1;
}
sub testStep13 {
LogStep "check write result of fc16";
is(FhemTestUtils_gotEvent(qr/D1:TempWasserAus:\s29/xms), 1, "Write value with fc16 to local slave");
return 0.1;
}
sub testStep14 {
LogStep "closeAfterResponse";
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('attr Master closeAfterResponse 1');
fhem ('attr Master verbose 4');
fhem ('set Master reread');
return 0.1;
}
sub testStep15 {
is(FhemTestUtils_gotEvent(qr/Master:Test1: 6/), 1, "Retrieve Test1");
is(FhemTestUtils_gotEvent(qr/Master:Test4: 40/), 0, "Retrieve Test4");
is(FhemTestUtils_gotLog('HandleResponse will close because closeAfterResponse is set and queue is empty'), 1, "closed");
return 0.1;
}
sub testStep16 {
LogStep "try get while closed";
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('get Master TempWasserEin');
fhem ('attr Master queueDelay 0.3');
return 0.1;
}
sub testStep17 {
LogStep "check get result while connection closed";
is(FhemTestUtils_gotLog('device opened'), 1, "device opened");
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 0, "No retrieve from local slave yet");
return 0.3;
}
sub testStep18 {
LogStep "check get result after another delay";
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 1, "retrieve from local slave after open and QueueDelay");
is(FhemTestUtils_gotLog('close because closeAfterResponse'), 1, "device closed again");
return 0.1;
}
sub testStep19 {
LogStep "now that the connection is closed again, try another prioritized get";
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('attr Master nonPrioritizedGet 0');
fhem ('attr Master dev-timing-timeout 0.5');
fhem ('attr Master verbose 5');
fhem ('get Master TempWasserEin');
return 0.1;
}
sub testStep20 {
LogStep "check result after prio get";
is(FhemTestUtils_gotLog('device opened'), 1, "device opened");
is(FhemTestUtils_gotLog('Master: Timeout in Readanswer'), 1, "readanswer called but slave cannot answer while sitting in readanswer");
return;
}
sub testStep21 {
LogStep "check result after prio get";
is(FhemTestUtils_gotLog('Master: read buffer: 050302000c4981'), 1, "answer arrives after readanswer timeout");
return;
}
# todo: different protocols (RTU, ASCII, TCP)
# data type definition
# swap bytes and similar
# unpack variations
# then relay mode
1;

View File

@ -0,0 +1,135 @@
attr global mseclog 1
define D1 dummy
define Slave ModbusAttr 50 slave global:5501 ASCII
attr Slave obj-h256-reading TempWasserEin
attr Slave obj-h258-reading D1:TempWasserAus
attr Slave obj-h100-reading Test1
attr Slave obj-h100-setexpr $val * 4
attr Slave obj-h101-reading Test2
attr Slave obj-h101-unpack f>
attr Slave obj-h101-len 2
attr Slave obj-h103-reading Test3
attr Slave obj-h103-unpack a8
attr Slave obj-h103-len 4
attr Slave obj-h120-reading Test4
attr Slave obj-h120-unpack f>
attr Slave obj-h120-len 2
attr Slave obj-h130-reading Test5
attr Slave obj-h130-unpack a*
attr Slave obj-h130-len 2
attr Slave obj-c400-reading c0
attr Slave obj-c401-reading c1
attr Slave obj-c402-reading c2
attr Slave obj-c403-reading c3
attr Slave obj-c404-reading c4
attr Slave obj-c405-reading c5
attr Slave obj-c406-reading c6
attr Slave obj-c407-reading c7
attr Slave obj-c408-reading c8
attr Slave obj-c409-reading c9
attr Slave obj-c410-reading c10
attr Slave obj-c411-reading c11
attr Slave obj-c412-reading c12
attr Slave obj-c413-reading c13
attr Slave obj-c414-reading c14
attr Slave obj-c415-reading c15
attr Slave obj-c416-reading c16
attr Slave obj-c417-reading c17
attr Slave obj-c418-reading c18
define RM ModbusAttr 50 0 localhost:5501 ASCII
attr RM dev-timing-sendDelay 0
attr RM dev-timing-commDelay 0
attr RM disable 1
define Relay ModbusAttr 5 relay localhost:5510 RTU to RM
attr Relay disable 1
define Master ModbusAttr 5 0 localhost:5510 RTU
attr Master disable 1
attr Master verbose 3
attr Master nonPrioritizedGet 1
attr Master nonPrioritizedSet 1
attr Master dev-timing-sendDelay 0
attr Master dev-timing-commDelay 0
attr Master obj-h256-reading TempWasserEin
attr Master obj-h258-reading TempWasserAus
attr Master obj-h100-reading Test1
attr Master obj-h100-expr $val + 2
attr Master obj-h100-poll 1
attr Master obj-h100-polldelay 0
attr Master obj-h101-reading Test2
attr Master obj-h101-unpack f>
attr Master obj-h101-len 2
attr Master obj-h101-format %.2f
attr Master obj-h101-poll 1
attr Master obj-h101-polldelay 0
attr Master obj-h103-reading Test3
attr Master obj-h103-unpack a8
attr Master obj-h103-len 4
attr Master obj-h103-poll 1
attr Master obj-h103-polldelay 0
attr Master obj-h120-reading Test4
attr Master obj-h120-unpack f>
attr Master obj-h120-len 2
attr Master obj-h120-format %.2f
attr Master obj-h120-poll 1
attr Master obj-h120-ignoreExpr $val > 10
attr Master obj-h120-polldelay 0
attr Master obj-h130-reading Test5
attr Master obj-h130-unpack a*
attr Master obj-h130-len 2
attr Master obj-h130-encode utf8
attr Master obj-h10-reading o1
attr Master obj-h10-map 0:off, 1:on
attr Master obj-h11-reading o2
attr Master obj-h11-min 1
attr Master obj-h11-max 3
attr Master dev-h-defSet 1
attr Master dev-c-defSet 1
attr Master dev-h-defShowGet 1
attr Master obj-c400-reading c0
attr Master obj-c401-reading c1
attr Master obj-c402-reading c2
attr Master obj-c403-reading c3
attr Master obj-c404-reading c4
attr Master obj-c405-reading c5
attr Master obj-c406-reading c6
attr Master obj-c407-reading c7
attr Master obj-c408-reading c8
attr Master obj-c409-reading c9
attr Master obj-c410-reading c10
attr Master obj-c411-reading c11
attr Master obj-c412-reading c12
attr Master obj-c413-reading c13
attr Master obj-c414-reading c14
attr Master obj-c415-reading c15
attr Master obj-c416-reading c16
attr Master obj-c417-reading c17
attr Master obj-c418-reading c18
attr Master obj-c400-poll 1
attr Master obj-c405-poll 1
attr Master obj-c406-poll 1
attr Master obj-c417-poll 1
attr Master dev-h-combine 19
attr Master dev-c-combine 32

View File

@ -0,0 +1,230 @@
##############################################
# test master slave end to end
##############################################
package main;
use strict;
use warnings;
use Test::More;
use Time::HiRes qw( gettimeofday tv_interval); # return time as float, not just full seconds
use FHEM::HTTPMOD::Utils qw(:all);
use FHEM::Modbus::TestUtils qw(:all);
fhem 'attr global mseclog 1';
InternalTimer(gettimeofday()+5, "testStepLast", 0); # last resort
NextStep();
sub testStep1 { # preparation of slave content, enable devices
is(FhemTestUtils_gotLog('attribute'), 0, "no unknown attributes"); # logs during init are not collected.
LogStep "enable Master and set value at Slave";
fhem ('attr RM disable 0');
fhem ('attr Relay disable 0');
fhem ('attr Master disable 0');
fhem ('setreading Slave TempWasserEin 12');
fhem ('setreading Slave Test1 1');
fhem ('setreading Slave Test2 2.123');
fhem ('setreading Slave Test3 abcdefg');
fhem ('setreading Slave Test4 40');
readingsSingleUpdate($defs{'Slave'}, 'Test5', pack('H*', 'e4f6fc'), 0);
fhem ('setreading Slave c0 1');
fhem ('setreading Slave c5 1');
fhem ('setreading Slave c17 1');
return 0.1;
}
sub testStep2 { # get holding registers
LogStep "get TempWasserEin";
fhem ('attr Master verbose 3');
fhem ('attr Slave verbose 3');
fhem ('attr Relay verbose 3');
fhem ('attr RM verbose 3');
fhem ('get Master TempWasserEin');
fhem ('get Master Test1');
fhem ('get Master Test2');
fhem ('get Master Test3');
fhem ('get Master Test4');
fhem ('get Master Test5');
return 1;
}
sub testStep3 { # check results
LogStep "check result";
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 1, "Retrieve integer value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test1: 6/), 1, "Retrieve another integer value with expressions on both sides from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test2: 2.12/), 1, "Retrieve float value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test3: abcdefg/), 1, "Retrieve ascii value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test4: 40/), 0, "ignoreExpr prohibits Test4 set to 40");
is(FhemTestUtils_gotEvent(qr/Master:Test5: äöü/), 1, "encode worked for Test5");
return;
}
sub testStep4 { # set holding register without allowance at salve
LogStep "set TempWasserAus at Slave";
fhem ('set Master TempWasserAus 20');
fhem ('attr Master verbose 4');
return 0.2;
}
sub testStep5 { # check that write was forbidden
LogStep "Check error response";
is(FhemTestUtils_gotLog('Master: HandleResponse got response with error code 86 / 01, illegal function'), 1, "disallow write by default");
fhem ('attr Master verbose 3');
return;
}
sub testStep6 { # allow write at slave and try again to write
LogStep "allow write and try again";
fhem ('attr Slave obj-h258-allowWrite 1');
fhem ('set Master TempWasserAus 20');
return 0.1;
}
sub testStep7 { # check that write holding register did work
LogStep "check result";
is(FhemTestUtils_gotEvent(qr/D1:TempWasserAus:\s20/xms), 1, "Write value to local slave");
return 0.1;
}
sub testStep8 { # check input validation at master and write
LogStep "set with map and min/max";
fhem ('set Master o1 one');
is(FhemTestUtils_gotLog('set Master o1 one : set value one did not match defined map'), 1, "map error message in log");
fhem ('set Master o2 0');
is(FhemTestUtils_gotLog('set Master o2 0 : value 0 is not within defined min/max range'), 1, "min error message in log");
fhem ('set Master o2 4');
is(FhemTestUtils_gotLog('set Master o2 4 : value 4 is not within defined min/max range'), 1, "max error message in log");
fhem ('attr Master verbose 4');
fhem ('set Master o2 2');
fhem ('set Master o1 on');
return 0.2;
}
sub testStep9 { # check write data
LogStep "check log for map and set o2 2";
is(FhemTestUtils_gotLog('0506000a0001698c'), 1, "set o1 on message in log");
is(FhemTestUtils_gotLog('0506000b0002784d'), 1, "set O2 2 message in log");
fhem ('attr Master verbose 3');
return 0.1;
}
sub testStep10 { # check combined read of holding registers and coils
LogStep "getUpdate with combine";
FhemTestUtils_resetEvents();
fhem ('set Master reread');
return 0.1;
}
sub testStep11 { # check results coming from slave and write coils to slave
is(FhemTestUtils_gotEvent(qr/Master:Test1: 6/), 1, "Combined retrieve integer value with expressions on both sides from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test2: 2.12/), 1, "Combined retrieve float value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:Test3: abcdefg/), 1, "Combined Retrieve ascii value from local slave");
is(FhemTestUtils_gotEvent(qr/Master:c0: 1/), 1, "Combined Retrieve coil bit 0 from local slave");
is(FhemTestUtils_gotEvent(qr/Master:c1: 0/), 1, "Combined Retrieve coil bit 1 from local slave");
is(FhemTestUtils_gotEvent(qr/Master:c17: 1/), 1, "Combined Retrieve coil bit 17 from local slave");
fhem ('attr Slave obj-c402-allowWrite 1');
fhem ('attr Master verbose 5');
fhem ('set Master c2 1');
return 0.1;
}
sub testStep12 {
LogStep "check coil comm";
is(FhemTestUtils_gotLog('sending 05050192ff002daf'), 1, "set c2 1 sending message in log");
is(FhemTestUtils_gotEvent(qr/Master:c2: 1/), 1, "fc5 response for coil shows 1 from local slave");
Log3 undef, 1, "TestStep12: try to write with fc16";
fhem ('attr Master verbose 3');
fhem ('attr Slave verbose 3');
fhem ('attr Master dev-h-write 16');
fhem ('set Master TempWasserAus 29');
return 0.1;
}
sub testStep13 {
LogStep "check write result of fc16";
is(FhemTestUtils_gotEvent(qr/D1:TempWasserAus:\s29/xms), 1, "Write value with fc16 to local slave");
return 0.1;
}
sub testStep14 {
LogStep "closeAfterResponse";
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('attr Master closeAfterResponse 1');
fhem ('attr Master verbose 4');
fhem ('set Master reread');
return 0.1;
}
sub testStep15 {
is(FhemTestUtils_gotEvent(qr/Master:Test1: 6/), 1, "Retrieve Test1");
is(FhemTestUtils_gotEvent(qr/Master:Test4: 40/), 0, "Retrieve Test4");
is(FhemTestUtils_gotLog('HandleResponse will close because closeAfterResponse is set and queue is empty'), 1, "closed");
return 0.1;
}
sub testStep16 {
LogStep "try get while closed";
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('get Master TempWasserEin');
fhem ('attr Master queueDelay 0.3');
return 0.1;
}
sub testStep17 {
LogStep "check get result while connection closed";
is(FhemTestUtils_gotLog('device opened'), 1, "device opened");
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 0, "No retrieve from local slave yet");
return 0.3;
}
sub testStep18 {
LogStep "check get result after another delay";
is(FhemTestUtils_gotEvent(qr/Master:TempWasserEin:\s12/xms), 1, "retrieve from local slave after open and QueueDelay");
is(FhemTestUtils_gotLog('close because closeAfterResponse'), 1, "device closed again");
return 0.1;
}
sub testStep19 {
LogStep "now that the connection is closed again, try another prioritized get";
FhemTestUtils_resetEvents();
FhemTestUtils_resetLogs();
fhem ('attr Master nonPrioritizedGet 0');
fhem ('attr Master dev-timing-timeout 0.5');
fhem ('attr Master verbose 5');
fhem ('get Master TempWasserEin');
return 0.1;
}
sub testStep20 {
LogStep "check result after prio get";
is(FhemTestUtils_gotLog('device opened'), 1, "device opened");
is(FhemTestUtils_gotLog('Master: Timeout in Readanswer'), 1, "readanswer called but slave cannot answer while sitting in readanswer");
return;
}
sub testStep21 {
LogStep "check result after prio get";
is(FhemTestUtils_gotLog('Master: read buffer: 050302000c4981'), 1, "answer arrives after readanswer timeout");
return;
}
# todo: different protocols (RTU, ASCII, TCP)
# data type definition
# swap bytes and similar
# unpack variations
# then relay mode
1;

View File

@ -0,0 +1,128 @@
attr global mseclog 1
define D1 dummy
define Slave ModbusAttr 5 slave global:5501
attr Slave obj-h256-reading TempWasserEin
attr Slave obj-h258-reading D1:TempWasserAus
attr Slave obj-h100-reading Test1
attr Slave obj-h100-setexpr $val * 4
attr Slave obj-h101-reading Test2
attr Slave obj-h101-unpack f>
attr Slave obj-h101-len 2
attr Slave obj-h103-reading Test3
attr Slave obj-h103-unpack a8
attr Slave obj-h103-len 4
attr Slave obj-h120-reading Test4
attr Slave obj-h120-unpack f>
attr Slave obj-h120-len 2
attr Slave obj-h130-reading Test5
attr Slave obj-h130-unpack a*
attr Slave obj-h130-len 2
attr Slave obj-c400-reading c0
attr Slave obj-c401-reading c1
attr Slave obj-c402-reading c2
attr Slave obj-c403-reading c3
attr Slave obj-c404-reading c4
attr Slave obj-c405-reading c5
attr Slave obj-c406-reading c6
attr Slave obj-c407-reading c7
attr Slave obj-c408-reading c8
attr Slave obj-c409-reading c9
attr Slave obj-c410-reading c10
attr Slave obj-c411-reading c11
attr Slave obj-c412-reading c12
attr Slave obj-c413-reading c13
attr Slave obj-c414-reading c14
attr Slave obj-c415-reading c15
attr Slave obj-c416-reading c16
attr Slave obj-c417-reading c17
attr Slave obj-c418-reading c18
define Master ModbusAttr 5 0 localhost:5501
attr Master disable 1
attr Master verbose 3
attr Master nonPrioritizedGet 1
attr Master nonPrioritizedSet 1
attr Master profileInterval 1
attr Master dev-timing-sendDelay 0
attr Master dev-timing-commDelay 0
attr Master obj-h256-reading TempWasserEin
attr Master obj-h258-reading TempWasserAus
attr Master obj-h100-reading Test1
attr Master obj-h100-expr $val + 2
attr Master obj-h100-poll 1
attr Master obj-h100-polldelay 0
attr Master obj-h101-reading Test2
attr Master obj-h101-unpack f>
attr Master obj-h101-len 2
attr Master obj-h101-format %.2f
attr Master obj-h101-poll 1
attr Master obj-h101-polldelay 0
attr Master obj-h103-reading Test3
attr Master obj-h103-unpack a8
attr Master obj-h103-len 4
attr Master obj-h103-poll 1
attr Master obj-h103-polldelay 0
attr Master obj-h120-reading Test4
attr Master obj-h120-unpack f>
attr Master obj-h120-len 2
attr Master obj-h120-format %.2f
attr Master obj-h120-poll 1
attr Master obj-h120-ignoreExpr $val > 10
attr Master obj-h120-polldelay 0
attr Master obj-h130-reading Test5
attr Master obj-h130-unpack a*
attr Master obj-h130-len 2
attr Master obj-h130-encode utf8
attr Master obj-h10-reading o1
attr Master obj-h10-map 0:off, 1:on
attr Master obj-h11-reading o2
attr Master obj-h11-min 1
attr Master obj-h11-max 3
attr Master dev-h-defSet 1
attr Master dev-c-defSet 1
attr Master dev-h-defShowGet 1
attr Master obj-c400-reading c0
attr Master obj-c401-reading c1
attr Master obj-c402-reading c2
attr Master obj-c403-reading c3
attr Master obj-c404-reading c4
attr Master obj-c405-reading c5
attr Master obj-c406-reading c6
attr Master obj-c407-reading c7
attr Master obj-c408-reading c8
attr Master obj-c409-reading c9
attr Master obj-c410-reading c10
attr Master obj-c411-reading c11
attr Master obj-c412-reading c12
attr Master obj-c413-reading c13
attr Master obj-c414-reading c14
attr Master obj-c415-reading c15
attr Master obj-c416-reading c16
attr Master obj-c417-reading c17
attr Master obj-c418-reading c18
attr Master obj-c400-poll 1
attr Master obj-c405-poll 1
attr Master obj-c406-poll 1
attr Master obj-c417-poll 1
attr Master dev-h-combine 19
attr Master dev-c-combine 32

View File

@ -0,0 +1,61 @@
##############################################
# test master slave end to end
##############################################
package main;
use strict;
use warnings;
use Test::More;
use Time::HiRes qw( gettimeofday tv_interval); # return time as float, not just full seconds
use FHEM::HTTPMOD::Utils qw(:all);
use FHEM::Modbus::TestUtils qw(:all);
fhem 'attr global mseclog 1';
InternalTimer(gettimeofday()+5, "testStepLast", 0); # last resort
NextStep();
sub testStep1 { # preparation of slave content, enable devices
is(FhemTestUtils_gotLog('attribute'), 0, "no unknown attributes"); # logs during init are not collected.
LogStep "enable Master and set value at Slave";
fhem ('attr Master disable 0');
fhem ('setreading Slave TempWasserEin 12');
fhem ('setreading Slave Test1 1');
fhem ('setreading Slave Test2 2.123');
fhem ('setreading Slave Test3 abcdefg');
fhem ('setreading Slave Test4 40');
readingsSingleUpdate($defs{'Slave'}, 'Test5', pack('H*', 'e4f6fc'), 0);
fhem ('setreading Slave c0 1');
fhem ('setreading Slave c5 1');
fhem ('setreading Slave c17 1');
return 0.1;
}
sub testStep2 { # get holding registers
LogStep "get TempWasserEin";
fhem ('attr Master verbose 5');
fhem ('attr Slave verbose 5');
fhem ('get Master TempWasserEin');
fhem ('get Master Test1');
fhem ('get Master Test2');
fhem ('get Master Test3');
fhem ('get Master Test4');
fhem ('get Master Test5');
return 0.3;
}
sub testStep3 {
fhem 'set Master reread';
return 0.3;
}
sub testStep4 {
fhem 'set Master reread';
return 0.3;
}
1;