Presence Modul: absenceTimeout wird ignoriert

Begonnen von der_sven, 24 November 2019, 12:19:52

Vorheriges Thema - Nächstes Thema

der_sven

Moin zusammen,

Vielleicht ist es mir früher nicht aufgefallen oder es hat sich während einem der letzten Updates geändert, aber das "absenceTimeout" scheint ignoriert zu werden.

Laut Doku funktioniert es wie folgt:

<snip>

(only in mode "event" applicable)
The timeout after receiving an "absent" event, before the state of the PRESENCE definition is switched to "absent". This can be used to verify the permanent absence by waiting a specific time frame to not receive an "present" event. If this timeout is reached with no "present" event received in the meantime, the presence state will finally be set to "absent". The timeout is given in HH:MM:SS format, where hours and minutes are optional. If this attribute is set to a valid value, the reading state and presence will be set to "maybe absent" during the absence verification.

<snap>

Hier meine Konfiguration:

<snip>

define Bewohner.Sven.Handy PRESENCE event iWifi:i7:.disconnected iWifi:i7:.connected
setuuid Bewohner.Sven.Handy 5c43738b-f33f-c5db-1fae-81f2cd6a7d61f390
attr Bewohner.Sven.Handy absenceTimeout 15:00
attr Bewohner.Sven.Handy event-on-change-reading state,presence
attr Bewohner.Sven.Handy icon it_smartphone
attr Bewohner.Sven.Handy room Bewohner

<snap>

Egal welchen Timeout ich konfiguriere (hier 15 Minuten) "maybe absent" bleibt immer nur für 30 Sekunden als Status, danach gehts direkt in den Status "absent".

Jemand eine Idee oder das selbe Problem?

thx und grüsse

Sven

amenomade

Vemutlich schickt iWifi inzwischen ein "disconneted", und spring deswegen PRESENCE direkt auf "absent"
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

der_sven

Zitat von: amenomade am 24 November 2019, 12:44:36
Vemutlich schickt iWifi inzwischen ein "disconneted", und spring deswegen PRESENCE direkt auf "absent"

Verdammt, stimmt...

hinter iWifi verbirgt sich ein Unifi Controller und der updated den Status regelmässig. Muss ich also vorab noch abpuffern :-/

Danke für den Hinweis

obelix221

Servus Sven,

wie hast Du denn das damals jetzt abgepuffert?
Ich stehe gerade vor der selben Fragestellung .

Grüße Obelix
RPi3 als FHEM-Server, 868 MHz CUL, 433 MHz Transmitter, Homematic Aktoren und Sensoren, Yamaha AVR, Logitech Harmony, Fritzbox, Logitech SB, 433 MHz Steckdosen, HUE, EnOcean

Alpha_DE

#4
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);
    }
}