Befehl zeitversetzt ausführen und Popup in Konfigurationsformular

Hallo zusammen,

ich bin gerade daran einen An- & Abmeldemodus für mein Modul zu bauen um Geräte an- und abzumelden.

Dafür habe ich im Configurator zwei Buttons erstellt: „Anmelden“ und „Abmelden“. Wenn ich einen der Button drücke, soll eine Nachricht zum Splitter gesendet werden und 30 (oder 60) Sekunden später eine weitere um den Modus wieder zu verlassen. Wenn in der Zwischenzeit eine bestimmte Nachricht vom Splitter gekommen ist, soll ein Popup mit der Nachricht „Paired“ auftauchen.

Ist sowas ansatzweise möglich? Mit IPS_Sleep friert das ganze Konfigurationsformular ein und RegisterTimer funktioniert ja beim Drücken eines Buttons nicht, wenn ich das richtig verstehe? Wie ich ein Popup schicken kann, wenn das Gerät gepaired ist, hab ich garkeine Idee.

Beispiel Abmelden:


    public function GetConfigurationForm()
    {
         // ...
        $data = json_decode(file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . "form.json"), true);
        $data['actions'][14]['onClick'] = <<< 'EOT'
                // include library
                require_once(IPS_GetKernelDir() . DIRECTORY_SEPARATOR . "modules"
                                                . DIRECTORY_SEPARATOR . "IPSDuoFern"
                                                . DIRECTORY_SEPARATOR . "libs"
                                                . DIRECTORY_SEPARATOR . "library.php");

                // define helper function to translate
                function Translate($string)
                {
                    $translations = json_decode(file_get_contents(IPS_GetKernelDir()
                        . DIRECTORY_SEPARATOR . "modules"
                        . DIRECTORY_SEPARATOR . "IPSDuoFern"
                        . DIRECTORY_SEPARATOR . "DuoFernConfigurator"
                        . DIRECTORY_SEPARATOR . "locale.json"), true);
                    $translations = $translations["translations"]["de"];

                    // found translation
                    if (array_key_exists($string, $translations)) {
                        return $translations[$string];
                    }

                    // do not translate
                    return $string;
                }
    
                echo Translate("Start unpairing mode for 10 seconds");
                DUOFERN_SendRawMsg($id, DuoFernMessage::DUOFERN_MSG_UNPAIR_START);
                IPS_Sleep(10000);
                DUOFERN_SendRawMsg($id, DuoFernMessage::DUOFERN_MSG_UNPAIR_STOP);
EOT;
}

Versuch ein Popup zu schicken, wenn das Gerät erfolgreich an-/abgemeldet wurde:


    public function ReceiveData($JSONString)
    {
        // ...
        if (preg_match('/' . substr(DuoFernMessage::DUOFERN_MSG_PAIRED, 0, 5) . '.{38}/', $displayMsg)) {
            echo "paired!";
        } else if (preg_match('/' . substr(DuoFernMessage::DUOFERN_MSG_UNPAIRED, 0, 5) . '.{38}/', $displayMsg)) {
            echo "unpaired!";
        }
    }

Vielen Dank!

Gruß baba

Schau in meinen Plugwise Splitter.
Der macht genau das, mit Popup (einfach echo).
Michael

Meinst du SearchNodes? Weil du hast ja zwei Buttons gemacht Enable joining und Disable joining. Ich hätte halt gerne nur einen Button der dann30 Sekunden sucht, sonst vergisst das ein User auszustellen.

Danke!

Nach dem enable joining, gibt es eine zusätzliche Liste und einen Button für Include Node.
Hier die Methode aus dem Konfig-Formular mit der Meldung per Echo:
IPSPlugwise/module.php at cf692d9a9a437f077cf80381c071588680160066 · Nall-chan/IPSPlugwise · GitHub

Und hier das eigentliche paring:
IPSPlugwise/module.php at cf692d9a9a437f077cf80381c071588680160066 · Nall-chan/IPSPlugwise · GitHub
Dann wird hier auf die Antwort gewartet, darum wird die max Script-Laufzeit erhöht:
IPSPlugwise/module.php at cf692d9a9a437f077cf80381c071588680160066 · Nall-chan/IPSPlugwise · GitHub
In dieser Zeit reagiert dann die Console aber nicht, bis ein Timeout oder die Antwort eintritt.
Michael

Danke für deine Tipps. Für den normalen An- und Abmeldemodus warte ich auf keine bestimmte Nachricht, da können auch mehrere Devices antworten, deshalb habe ich da jetzt doch mit Timern und IPS_Logmessage gearbeitet. Gibt es eine möglichkeit direkt ins Meldungen fenster zu springen aus dem Konfigurationsformular?

Aber für die Fernanmeldung für ein bestimmtes Gerät, macht das mit dem Warten schon sinn. Da ich es im Konfigurator und nicht im Splitter habe, wollte ich mir eine WaitForMsg Methode bauen um auf bestimmte Nachrichten zu warten (brauche ich eh noch für das Device). Ich komme aber irgendwie nicht so richtig weiter:

WaitForMsg ($this->WaitForMsgBuffer ist ein Buffer):


 private function WaitForMsg($expectedMsg, $seconds = 10)
    {
        // check valid msg
        if (!preg_match(DuoFernRegex::DUOFERN_REGEX_MSG, $expectedMsg)) {
            return false;
        }

        // try to get response $seconds times
        for ($i = 0; $i < $seconds * 100; $i++) {
            // get data
            if ($this->SemaphoreEnter('WaitForMsgBuffer')) {
                $waitForResponseBuffer = $this->WaitForMsgBuffer;
                $response = $waitForResponseBuffer->WaitFor($expectedMsg);
                $this->WaitForMsgBuffer = $waitForResponseBuffer;
                $this->SemaphoreLeave('WaitForMsgBuffer');

                if ($response === true) {
                    $this->SendDebug("RECEIVED EXPECTED MSG", $this->ConvertMsgToSend($expectedMsg), 1);
                    return $expectedMsg;
                }
            }

            // wait 10 ms
            IPS_Sleep(10);
        }

        // remove msg from buffer (timeout)
        if ($this->SemaphoreEnter('WaitForMsgBuffer')) {
            $waitForResponseBuffer = $this->WaitForMsgBuffer;
            $waitForResponseBuffer->Remove($expectedMsg, false);
            $this->WaitForMsgBuffer = $waitForResponseBuffer;
            $this->SemaphoreLeave('WaitForMsgBuffer');
        }

        // send expected response as debug msg
        $this->SendDebug("TIMEOUT WAITFORMSG", $this->ConvertMsgToSend($expectedMsg), 1);

        return false;
    }
}

ReceiveData:


   public function ReceiveData($JSONString)
    {
        // decode data
        $data = json_decode($JSONString);

        // get msg
        $msg = utf8_decode($data->Buffer);

        $displayMsg = $this->ConvertMsgToDisplay($msg);

        // wait for msg buffer
        $waitForMsgBuffer = $this->WaitForMsgBuffer;
        $waitForMsgBuffer->Received($displayMsg);
        $this->WaitForMsgBuffer = $waitForMsgBuffer;
        // ...
    }

Create:


    public function Create()
    {
        parent::Create();
        $this->WaitForMsgBuffer = new DuoFernWaitForMsgBuffer();
        // ..
    }

DuoFernWaitForMsgBuffer:


class DuoFernWaitForMsgBuffer
{
    public $items = array();

    public function WaitFor($msg)
    {
        foreach ($this->items as $key => $item) {
            if ($item['msg'] == $msg && $item['received'] == true) { // received
                unset ($this->items [$key]);
                return true;
            } else if ($item['msg'] == $msg && $item['received'] == false) { // wait
                return false;
            } else { // new message
                $this->items[] = array("msg" => $msg, "received" => false);
                return false;
            }
        }
    }

    public function Received($msg)
    {
        foreach ($this->items as $key => $item) {
            if ($item['msg'] == $msg && $item['received'] == false) {
                $this->items [$key] = array("msg" => $msg, "received" => true);
                return true;
            }
        }
        return false;
    }

    public function Remove($msg, $received)
    {
        foreach ($this->items as $key => $item) {
            if ($item['msg'] == $msg && $item['received'] == $received) {
                unset ($this->items [$key]);
                return true;
            }
        }
        return false;
    }
}

Eine Idee, warum das so nicht läuft, oder sogar eine einfachere Lösung?

Gruß baba