Ich habe mir eine eigene Lösung mit einem Watchdog gebaut, das Presence Device reagiert auf einen zweiten absent Event in jedem Fall mit state absent und ignoriert dann den absenceTimeout. Das Verhalten würde ich nicht erwarten, denn der Timeout soll ja gerade wiederholte (zu frühe) Events aufgrund von Unifi/Wifi Disconnects abpuffern.
In meinem Setup ist es leider unbrauchbar.
Mein Watchdog (direkt vom Unifi Device zum Resident), hier mit 2h Timeout
define WD_Resident_Mobile watchdog UnifiDeviceName:fhem_state:.disconnected 02:00 UnifiDeviceName:fhem_state:.connected {\
if ((Value(rr_Resident) ne "absent") && (Value(rr_Resident) ne "gone")) {\
fhem("set rr_Resident absent;;");;\
}\
}
attr WD_Resident_Mobile room Residents
Nachtrag: Ich habe mir eben mal angesehen, wie das im Modul 73_PRESENCE.pm bisher implementiert ist. Dort führt jeder weitere "absent" bzw. "present" Event dazu, dass der laufende Timeout gelöscht und das Presence-Device hart auf den neuen Status gesetzt wird. Das Setting wird damit zumindest im Unifi-Environment unbrauchbar.
Das lässt sich aber relativ einfach lösen:
Im sub PRESENCE_ProcessState wird in den beiden Zweigen für absent und present der Timer für die verzögerte Ausführung nur bedingt gelöscht, wenn er für den entgegengesetzten Event eingerichtet worden ist.
Bisherige Zeile 1383:
if ($new_state eq "present") {
RemoveInternalTimer($hash, "PRESENCE_ThresholdTrigger");
}
und bisherige Zeile 1381:
if ($new_state eq "absent") {
RemoveInternalTimer($hash, "PRESENCE_ThresholdTrigger");
}
Außerdem wird das harte Setzen von present/absent auf den Fall beschränkt, dass kein absence/presenceTimeout gesetzt worden ist.
Bisherige Zeile 1346:
elsif ($absenceTimeout == 0)
und
Bisherige Zeile 1393:
elsif ($pesenceTimeout == 0)
Insgesamt also für die sub ab bisherige Zeile 1316:
#####################################
sub PRESENCE_ProcessState($$)
{
my ($hash, $state) = @_;
my $name = $hash->{NAME};
my $current_state = $hash->{helper}{CURRENT_STATE} ? $hash->{helper}{CURRENT_STATE} : "";
my $new_state = $hash->{helper}{NEW_STATE} ? $hash->{helper}{NEW_STATE} : "";
my $absenceThreshold = AttrVal($name, "absenceThreshold", 1);
my $presenceThreshold = AttrVal($name, "presenceThreshold", 1);
my $absenceTimeout = PRESENCE_calculateThreshold(AttrVal($name, "absenceTimeout", ""));
my $presenceTimeout = PRESENCE_calculateThreshold(AttrVal($name, "presenceTimeout", ""));
if($state eq "absent")
{
if ($new_state eq "present") {
RemoveInternalTimer($hash, "PRESENCE_ThresholdTrigger");
}
my $count = ($hash->{helper}{ABSENT_COUNT} ? $hash->{helper}{ABSENT_COUNT} : 0);
if($hash->{MODE} eq "event")
{
if($absenceTimeout > 0 and $current_state ne "absent" and $new_state ne "absent")
{
readingsBulkUpdate($hash, "state", "maybe absent");
readingsBulkUpdate($hash, "presence", "maybe absent");
$hash->{helper}{NEW_STATE} = "absent";
InternalTimer(gettimeofday()+$absenceTimeout, "PRESENCE_ThresholdTrigger", $hash);
}
elsif ($absenceTimeout == 0)
{
readingsBulkUpdate($hash, "state", "absent");
readingsBulkUpdate($hash, "presence", "absent");
$hash->{helper}{CURRENT_STATE} = "absent";
delete($hash->{helper}{NEW_STATE});
}
}
else
{
if(++$count >= $absenceThreshold)
{
readingsBulkUpdate($hash, ".presenceThresholdCounter", 0);
readingsBulkUpdate($hash, ".absenceThresholdCounter", ($count-1));
readingsBulkUpdate($hash, "state", "absent");
readingsBulkUpdate($hash, "presence", "absent");
}
else
{
$hash->{helper}{ABSENT_COUNT} = $count;
readingsBulkUpdate($hash, ".presenceThresholdCounter", 0);
readingsBulkUpdate($hash, ".absenceThresholdCounter", $count);
readingsBulkUpdate($hash, "state", "maybe absent");
readingsBulkUpdate($hash, "presence", "maybe absent");
Log3 $name, 4, "PRESENCE ($name) - device is absent after $count check".($count == 1 ? "" : "s").". ".($absenceThreshold-$count)." check".(($absenceThreshold-$count) == 1 ? "" : "s")." left before going absent";
}
}
delete($hash->{helper}{PRESENT_COUNT});
}
elsif($state eq "present")
{
if ($new_state eq "absent") {
RemoveInternalTimer($hash, "PRESENCE_ThresholdTrigger");
}
my $count = ($hash->{helper}{PRESENT_COUNT} ? $hash->{helper}{PRESENT_COUNT} : 0);
if($hash->{MODE} eq "event")
{
if($presenceTimeout > 0 and $current_state ne "present" and $new_state ne "present")
{
readingsBulkUpdate($hash, "state", "maybe present");
readingsBulkUpdate($hash, "presence", "maybe present");
$hash->{helper}{NEW_STATE} = "present";
InternalTimer(gettimeofday()+$presenceTimeout, "PRESENCE_ThresholdTrigger", $hash);
}
elsif ($presenceTimeout == 0)
{
readingsBulkUpdate($hash, "state", "present");
readingsBulkUpdate($hash, "presence", "present");
$hash->{helper}{CURRENT_STATE} = "present";
delete($hash->{helper}{NEW_STATE});
}
}
else
{
if(++$count >= $presenceThreshold)
{
readingsBulkUpdate($hash, ".absenceThresholdCounter", 0);
readingsBulkUpdate($hash, ".presenceThresholdCounter", ($count-1));
readingsBulkUpdate($hash, "state", "present");
readingsBulkUpdate($hash, "presence", "present");
$hash->{helper}{CURRENT_STATE} = "present";
}
else
{
$hash->{helper}{PRESENT_COUNT} = $count;
readingsBulkUpdate($hash, ".absenceThresholdCounter", 0);
readingsBulkUpdate($hash, ".presenceThresholdCounter", $count);
readingsBulkUpdate($hash, "state", "maybe present");
readingsBulkUpdate($hash, "presence", "maybe present");
Log3 $name, 4, "PRESENCE ($name) - device is present after $count check".($count == 1 ? "" : "s").". ".($presenceThreshold-$count)." check".(($presenceThreshold-$count) == 1 ? "" : "s")." left before going present";
}
}
delete($hash->{helper}{ABSENT_COUNT});
}
else
{
readingsBulkUpdate($hash, "state", $state);
}
}