mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-07 19:04:20 +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:
parent
90503ced50
commit
84a1c425fb
3
fhem/t/FHEM/98_Modbus/10_Timer.cfg
Normal file
3
fhem/t/FHEM/98_Modbus/10_Timer.cfg
Normal file
@ -0,0 +1,3 @@
|
||||
define M1 ModbusAttr 1 1
|
||||
attr M1 verbose 5
|
||||
define MS Modbus none
|
22
fhem/t/FHEM/98_Modbus/10_Timer.t
Normal file
22
fhem/t/FHEM/98_Modbus/10_Timer.t
Normal 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;
|
234
fhem/t/FHEM/98_Modbus/12_Delays.cfg
Normal file
234
fhem/t/FHEM/98_Modbus/12_Delays.cfg
Normal 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
|
||||
|
256
fhem/t/FHEM/98_Modbus/12_Delays.old
Normal file
256
fhem/t/FHEM/98_Modbus/12_Delays.old
Normal 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;
|
203
fhem/t/FHEM/98_Modbus/12_Delays.t
Normal file
203
fhem/t/FHEM/98_Modbus/12_Delays.t
Normal 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;
|
123
fhem/t/FHEM/98_Modbus/13_OpenDelays.cfg
Normal file
123
fhem/t/FHEM/98_Modbus/13_OpenDelays.cfg
Normal 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
|
219
fhem/t/FHEM/98_Modbus/13_OpenDelays.t
Normal file
219
fhem/t/FHEM/98_Modbus/13_OpenDelays.t
Normal 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;
|
235
fhem/t/FHEM/98_Modbus/14_QDelay.cfg
Normal file
235
fhem/t/FHEM/98_Modbus/14_QDelay.cfg
Normal 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
|
||||
|
52
fhem/t/FHEM/98_Modbus/14_QDelay.t
Normal file
52
fhem/t/FHEM/98_Modbus/14_QDelay.t
Normal 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;
|
9
fhem/t/FHEM/98_Modbus/20_Hints.cfg
Normal file
9
fhem/t/FHEM/98_Modbus/20_Hints.cfg
Normal 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
|
18
fhem/t/FHEM/98_Modbus/20_Hints.t
Normal file
18
fhem/t/FHEM/98_Modbus/20_Hints.t
Normal 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;
|
7
fhem/t/FHEM/98_Modbus/31_Register.cfg
Normal file
7
fhem/t/FHEM/98_Modbus/31_Register.cfg
Normal 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
|
||||
|
109
fhem/t/FHEM/98_Modbus/31_Register.t
Normal file
109
fhem/t/FHEM/98_Modbus/31_Register.t
Normal 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;
|
250
fhem/t/FHEM/98_Modbus/41_Passive.cfg
Normal file
250
fhem/t/FHEM/98_Modbus/41_Passive.cfg
Normal 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
|
||||
|
147
fhem/t/FHEM/98_Modbus/41_Passive.t
Normal file
147
fhem/t/FHEM/98_Modbus/41_Passive.t
Normal 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;
|
83
fhem/t/FHEM/98_Modbus/42_MasterRTU.cfg
Normal file
83
fhem/t/FHEM/98_Modbus/42_MasterRTU.cfg
Normal 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
|
||||
|
||||
|
121
fhem/t/FHEM/98_Modbus/42_MasterRTU.t
Normal file
121
fhem/t/FHEM/98_Modbus/42_MasterRTU.t
Normal 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;
|
127
fhem/t/FHEM/98_Modbus/50_MasterSlave0.cfg
Normal file
127
fhem/t/FHEM/98_Modbus/50_MasterSlave0.cfg
Normal 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
|
231
fhem/t/FHEM/98_Modbus/50_MasterSlave0.t
Normal file
231
fhem/t/FHEM/98_Modbus/50_MasterSlave0.t
Normal 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;
|
135
fhem/t/FHEM/98_Modbus/53_Relay.cfg
Normal file
135
fhem/t/FHEM/98_Modbus/53_Relay.cfg
Normal 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
|
230
fhem/t/FHEM/98_Modbus/53_Relay.t
Normal file
230
fhem/t/FHEM/98_Modbus/53_Relay.t
Normal 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;
|
135
fhem/t/FHEM/98_Modbus/54_RelayProto.cfg
Normal file
135
fhem/t/FHEM/98_Modbus/54_RelayProto.cfg
Normal 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
|
230
fhem/t/FHEM/98_Modbus/54_RelayProto.t
Normal file
230
fhem/t/FHEM/98_Modbus/54_RelayProto.t
Normal 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;
|
128
fhem/t/FHEM/98_Modbus/58_Profiler.cfg
Normal file
128
fhem/t/FHEM/98_Modbus/58_Profiler.cfg
Normal 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
|
61
fhem/t/FHEM/98_Modbus/58_Profiler.t
Normal file
61
fhem/t/FHEM/98_Modbus/58_Profiler.t
Normal 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;
|
Loading…
x
Reference in New Issue
Block a user