Hallo Boris,
ich schreibe hier meine weiteren Beobachtungen, die ich gemacht habe.
Nachdem ich mich mit der Funktionsweise von ECMD / ECMDDevice und auch DevIO noch etwas näher beschäftigt habe ist mir folgendes aufgefallen:
In ECMD werden Daten sowohl asynchron als auch synchron ausgewertet, obwohl sich beides ins Gehege kommen kann.
Vor allem
1)
get/set <commandname> expect vs.
2)
reading <reading> match "<regex>"Bei 1 wird mit
my $answer= DevIo_Expect($hash, $msg, $timeout );
in ECMD_SimpleExpect synchron auf eine Antwort gewartet, wobei eigentlich immer gleichzeitig mit
my $buf = ECMD_SimpleRead($hash);
Daten in ECMD_Read über die globale Loop abgeholt werden, die falls es passt an 2) weitergeleitet werden.
Interessanterweise funktioniert das, nur sauber ist das IMHO nicht. In ECMD_SimpleExpect werden einfach Antworten von der Quelle "abgefischt" und kommen so (glücklicherweise) nicht bei ECMD_Read an... Habe aber auch keine Idee wie das alles über einen Kanal, also ECMD_Read abzuwickeln wäre (vor allem die Unterscheidung Antwort auf set/get expect oder Spontanmeldung für reading expect)
Ich habe deshalb meine Classdef geändert, sämtliche set-Befehle haben nun kein expect/postproc mehr - dadurch werden Daten nur noch an einer Stelle geschrieben (ECMD_SimpleWrite) und der Empfang von Daten geschieht bei mir nur noch mit ECMD_Read...
params modnr pin
state internal
set on cmd { return "S%modnr:%pin\n" if (ReadingsVal("%NAME","internal","off") eq "off"); return undef; }
#set on expect "(ok\r\n)|(error:.*\r\n)"
#set on postproc { s/\r\n//; $_ }
set off cmd { return "S%modnr:%pin\n" if (ReadingsVal("%NAME","internal","on") eq "on"); return undef; }
#set off expect "(ok\r\n)|(error:.*\r\n)"
#set off postproc { s/\r\n//; $_ }
reading internal match "I%modnr:%pin=[01]\r\n"
reading internal postproc { my $oldstate=ReadingsVal("%NAME","internal",""); s/^I%modnr:%pin=1\r\n$/on/; my $newstate="$_" eq "on" ? "on" : "off"; if ($newstate ne $oldstate) { $_=$newstate; } else { $_= undef; } }
Wenn in der Classdef keine reading <reading> match "<regex>" definiert sind, könnte ECMD_Read ja eigentlich ignoriert werden?
Auf der anderen Seite könnte die Definition von get/set <commandname> expect und reading <reading> match "<regex>" in einer Classdef als unzulässig definiert werden?Was mir sonst noch aufgefallen ist, das unglaublich oft dispatch aufgerufen wird, meistens mit sehr wenigen Zeichen:
2020.01.06 17:30:36 5: IOServer: dispatch I
2020.01.06 17:30:36 5: IOServer: dispatch 0:1=1\r\n
2020.01.06 17:30:36 5: IOServer: dispatch I
2020.01.06 17:30:36 5: IOServer: dispatch 0:1=0\r\n
2020.01.06 17:30:37 5: IOServer: dispatch I
2020.01.06 17:30:37 5: IOServer: dispatch 0:1=1\r\n
2020.01.06 17:30:37 5: IOServer: dispatch I
2020.01.06 17:30:37 5: IOServer: dispatch 0:1=0\r\n
2020.01.06 17:30:37 5: IOServer: dispatch I
2020.01.06 17:30:37 5: IOServer: dispatch 0:1=1\r
2020.01.06 17:30:37 5: IOServer: dispatch \n
2020.01.06 17:30:37 5: IOServer: dispatch I
2020.01.06 17:30:37 5: IOServer: dispatch 0:1=0\r\n
2020.01.06 17:30:37 5: IOServer: dispatch I
2020.01.06 17:30:37 5: IOServer: dispatch 0:1=1\r\n
2020.01.06 17:30:38 5: IOServer: dispatch I0
2020.01.06 17:30:38 5: IOServer: dispatch :1=0\r\n
2020.01.06 17:30:38 5: IOServer: dispatch I
2020.01.06 17:30:38 5: IOServer: dispatch 0:1=1\r\n
2020.01.06 17:30:38 5: IOServer: dispatch I
2020.01.06 17:30:38 5: IOServer: dispatch 0:1=0\r\n
2020.01.06 17:30:38 5: IOServer: dispatch I
2020.01.06 17:30:38 5: IOServer: dispatch 0:1=1\r\n
2020.01.06 17:30:38 5: IOServer: dispatch I
2020.01.06 17:30:38 5: IOServer: dispatch 0:1=0\r\n
Zusammengeführt werden die Daten dann irgendwie im ECMDDevice, aber nur wenn das
partial Attribut eine Zeitangabe enthält...
Nach Lektüre von DevIO habe ich dann mal die Funktion ECMD_Read etwas umgebaut, sodass bei Spontanempfang von Daten und der Definition eines responseSeparators die Daten schon bei ECMD_Read "richtig gestellt" werden. Den Aufruf von ECMD_SimpleRead könnte man nun auch noch ignorieren, falls keine readings definiert wurden, oder wird das noch für etwas anderes benötigt?
Zitat#####################################
# called from the global loop, when the select for hash->{FD} reports data
sub ECMD_Read($)
{
my ($hash) = @_;
return undef unless($hash->{STATE} eq "opened"); # avoid reading from closed device
my $buf = ECMD_SimpleRead($hash);
return unless(defined($buf));
return if($buf eq "");
my $responseSeparator= $hash->{fhem}{".responseSeparator"};
if (defined($responseSeparator)) {
my $buffer = $hash->{PARTIAL};
# concat received data to $buffer
$buffer .= $buf;
# as long as the buffer contains newlines (complete datagramm)
while($buffer =~ m/\n/)
{
my $msg;
# extract the complete message ($msg), everything else is assigned to $buffer
($msg, $buffer) = split($responseSeparator, $buffer, 2);
# remove trailing whitespaces
chomp $msg;
$msg=$msg.$responseSeparator;
ECMD_Log $hash, 5, "Spontaneously received " . dq($msg);
# parse the extracted message
Dispatch($hash, $msg, undef);
}
# update $hash->{PARTIAL} with the current buffer content
$hash->{PARTIAL} = $buffer;
} else {
ECMD_Log $hash, 5, "Spontaneously received " . dq($buf);
Dispatch($hash, $buf, undef); # dispatch result to ECMDDevices
}
}
Das ganze an den responseSeparator zu hängen (der ja ausschließlich für set/get expect definiert ist) ist eventuell nicht ganz geschickt?
Insgesamt sieht das Logfile schon viel aufgeräumter aus und es "matched" auch sofort (also bei I0:1=0\r\n):
2020.01.09 18:32:58 5: IOServer: dispatch error: timer running\r\n
2020.01.09 18:47:32 5: IOServer: dispatch I0:1=1\r\n
2020.01.09 18:47:42 5: IOServer: dispatch ok\r\n
2020.01.09 18:47:42 5: IOServer: dispatch I0:1=0\r\n
2020.01.09 18:47:50 5: IOServer: dispatch ok\r\n
2020.01.09 18:47:50 5: IOServer: dispatch I0:1=1\r\n
2020.01.09 18:47:51 5: IOServer: dispatch ok\r\n
2020.01.09 18:47:51 5: IOServer: dispatch I0:1=0\r\n
2020.01.09 18:47:52 5: IOServer: dispatch ok\r\n
2020.01.09 18:47:52 5: IOServer: dispatch I0:1=1\r\n
2020.01.09 18:47:53 5: IOServer: dispatch ok\r\n
2020.01.09 18:47:53 5: IOServer: dispatch I0:1=0\r\n
2020.01.09 18:47:55 5: IOServer: dispatch ok\r\n
2020.01.09 18:47:55 5: IOServer: dispatch I0:1=1\r\n
Die "ok\r\n" und "error: ...\r\n" sind Rückmeldungen vom AVR bei den set-Commands.
Hier hätte ich nun vier Möglichkeiten:
- Ich programmier das aus meinem AVR raus, wäre aber schade denn dann bekomme ich nicht mehr direkt mit ob Kommandos ausgeführt werden.
- Oder würde sowas wie "reading <reading> ignore "<regex>" bzw. reading <reading> expect "<regex>" funktionieren??? Denke nicht, denn "ok\r\n" und "error: ...\r\n" werden ja nicht ans ECMDDevice weitergegeben...
- Ich markier' die Rückmeldungen eindeutig z.B. mir "R: ok\r\n" bzw. "R: error ...\r\n" - das könnte dann mittels Regex in einem Attribut in ECMD_Read ignoriert werden. Wäre dann aber global für das gesamte ECMD ...
- Oder ich lasse die Rückmeldungen so wie sie sind und mache nichts ;)
Gruß
Jochen