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!";
}
}
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 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?