Arghatell wrote: ↑Sun Nov 12, 2023 9:20 pm
Nie i jeszcze raz NIE. Pole wyzwalacza nie traktuj jako pola warunku stricte.
Wielokrotnie podnosisz kwestię, do której ja nie zgłaszam zastrzeżeń. Ale muszę Cię poprawić.
Kiedy urządzenie nadawcze (urządzenie z zainstalowaną suplą) wysyła odczytaną z czujnika wartość, trafia ona do
supla cloud. Tam wywoływane jest zapytanie (webhook) do
supla scripts do metody
postAction (
https://github.com/fracz/supla-scripts/ ... er.php#L21).
W zapytaniu przesłane są m.in. takie dane jak identyfikator użytkownika, powiązany z nim kanał i nowa zarejestrowana wartość.
Code: Select all
// $parsedBody = ['userShortUniqueId' => 'dc85740d-cb27-405b-9da3-e8be5c71ae5b', 'channelId' => 123,
// 'state' => ['on' => true, 'connected' => true], 'timestamp' => time(),
// 'channelFunction' => 'LIGHTSWITCH', 'accessToken' => 'XXX'];
// $parsedBody = ['userShortUniqueId' => 'dc85740d-cb27-405b-9da3-e8be5c71ae5b', 'channelId' => 123,
// 'triggered_actions' => ['HOLD'], 'timestamp' => time(),
// 'channelFunction' => 'ACTION_TRIGGER', 'accessToken' => 'XXX'];
Odczytane dane (w postaci użytkownika i kanału) po walidacji przekazywane są do metody
triggerScenesExecution (
https://github.com/fracz/supla-scripts/ ... er.php#L64).
Tam zostają pobrane wszystkie sceny które należą do użytkownika oraz w wyzwalaczu zawierają podany kanał =>
$scenes.
Następnie iterator wykonuje sekwencyjnie operacje na każdej z tych scene, czyli:
Tworzy
FeedbackInterpolator który służy do parsowania wyrażeń. Przeprowadza ewaluacje wyrażenia zapisanego w wyzwalaczu
$feedback = $feedbackInterpolator->interpolate($scene->trigger);.
Wynik interpretuje jako wartość logiczną i zapisuje do zmiennej
$triggerState = boolval($feedback);.
Porównuje z ostatnim zapisanym logicznym stanem wyzwala sceny
if ($triggerState != $scene->lastTriggerState) {
I jeżeli się różni, to wykonuje scenę (teraz dopiero sprawdza opcjonalny warunek wykonania), przypisuje nowy stan logiczny wyzwalacza i zapisuje scenę do bazy.
$scene->log('Wykryto zmianę warunku wyzwolenia sceny - wykonuję.');
$scene->lastTriggerState = $triggerState;
$sceneExecutor->executeWithFeedback($scene);
$scene->save();
Powyżej pokazałem, że pole wyzwalacza przeprowadza ewaluacje złożenia warunków jako całość i działa analogicznie do termostatu (wyzwala raz gdy wartość logiczna zmieni wartość).
A teraz dlaczego nie tylko można dostać (nieprawidłowo) wiele notyfikacji, jak po prostu wielokrotnie wykonać każdą akcję przypisaną do sceny.
Webhook wywoływany przez
supla cloud działa asynchronicznie, dlatego metoda
postAction może zostać wywołana wielokrotnie "w tym samym czasie". Nie posiada ona żadnego zabezpieczenia gwarantującego jakąś kolejność przetwarzania np. po czasie nadejścia aktualizacji z urządzenia nadawczego. Analogicznie przekłada się to na wywoływaną dalej metodę
triggerScenesExecution.
Gdy użyjemy w wyzwalaczu sceny więcej niż jednego kanału, a aktualizacje z tych kanałów nadejdą "w tym samym czasie", oba zapytania rozpoczną proces obsłużenia. Dla obu zostanie pobrany z bazy ten sam rekord sceny, który będzie zawierał ten sam stan logiczny wyzwolenia lastTriggerState. Jeżeli zmiana wartości dowolnego z tych kanałów spowodowała by zmianę tego stanu, to w tym momencie nie ma znaczenia który zostanie obsłużony pierwszy. Zapisze on stan w bazie z nowym stanem logicznym wyzwalacza sceny, ale w tym czasie pozostałe kanały mają już w pamięci poprzedni stan i one również wywołają reakcje przypisane do sceny, co objawi się np. wielokrotną notyfikacją.
Zgłosiłem zagadnienie na githubie -
https://github.com/fracz/supla-scripts/issues/77.