diff --git a/ONVIF Configurator/README.md b/ONVIF Configurator/README.md index 2de6443..2e865e1 100644 --- a/ONVIF Configurator/README.md +++ b/ONVIF Configurator/README.md @@ -1,6 +1,6 @@ [![SDK](https://img.shields.io/badge/Symcon-PHPModul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Version](https://img.shields.io/badge/Modul%20Version-2.00-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) -[![Version](https://img.shields.io/badge/Symcon%20Version-6.1%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) +[![Version](https://img.shields.io/badge/Modul%20Version-2.10-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) +[![Version](https://img.shields.io/badge/Symcon%20Version-7.0%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) [![Check Style](https://github.com/Nall-chan/ONVIF/workflows/Check%20Style/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) [![Run Tests](https://github.com/Nall-chan/ONVIF/workflows/Run%20Tests/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) @@ -34,8 +34,8 @@ Beschreibung des Moduls. ## 2. Voraussetzungen -* IP-Symcon ab Version 6.1 -* Kameras oder Video-Encoder mit ONVIF Profil S Unterstützung. +* IP-Symcon ab Version 7.0 +* Kameras oder Video-Encoder mit ONVIF Profil S und/oder Profil T Unterstützung. ## 3. Software-Installation @@ -49,8 +49,10 @@ Beschreibung des Moduls. Der Konfigurator ermöglicht es folgende Instanzen einfach zu erstellen und fertig zu konfigurieren: -- ONVIF Media Stream ([Dokumentation](../ONVIF%20Media%20Stream/README.md)) +- ONVIF Media Stream ([Dokumentation](../ONVIF%20Media%20Stream/README.md)) + - Pro Videoquelle wird erneut ein Stream zum erstellen angeboten, wie es noch ungenutzte Profile des Kanals gibt. (nach aktualisieren der Ansicht) - ONVIF Image Grabber ([Dokumentation](../ONVIF%20Image%20Grabber/README.md)) + - Pro Videoquelle wird erneut ein Stream zum erstellen angeboten, wie es noch ungenutzte Profile des Kanals gibt. (nach aktualisieren der Ansicht) - ONVIF Digital Input ([Dokumentation](../ONVIF%20Digital%20Input/README.md)) - ONVIF Digital Output ([Dokumentation](../ONVIF%20Digital%20Output/README.md)) - ONVIF Events ([Dokumentation](../ONVIF%20Events/README.md)) diff --git a/ONVIF Digital Input/README.md b/ONVIF Digital Input/README.md index fa1882c..46541d8 100644 --- a/ONVIF Digital Input/README.md +++ b/ONVIF Digital Input/README.md @@ -1,6 +1,6 @@ [![SDK](https://img.shields.io/badge/Symcon-PHPModul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Version](https://img.shields.io/badge/Modul%20Version-2.00-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) -[![Version](https://img.shields.io/badge/Symcon%20Version-6.1%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) +[![Version](https://img.shields.io/badge/Modul%20Version-2.10-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) +[![Version](https://img.shields.io/badge/Symcon%20Version-7.0%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) [![Check Style](https://github.com/Nall-chan/ONVIF/workflows/Check%20Style/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) [![Run Tests](https://github.com/Nall-chan/ONVIF/workflows/Run%20Tests/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) @@ -30,8 +30,8 @@ Bildet die Digitalen Eingänge in Symcon ab. ## 2. Voraussetzungen -* IP-Symcon ab Version 6.1 -* Kameras oder Video-Encoder mit ONVIF Profil S Unterstützung. +* IP-Symcon ab Version 7.0 +* Kameras oder Video-Encoder mit ONVIF Profil S und/oder Profil T Unterstützung. * Geräte müssen über mindestens einen Digitalen Eingang verfügen. ## 3. Software-Installation diff --git a/ONVIF Digital Output/README.md b/ONVIF Digital Output/README.md index 75f023f..be55671 100644 --- a/ONVIF Digital Output/README.md +++ b/ONVIF Digital Output/README.md @@ -1,6 +1,6 @@ [![SDK](https://img.shields.io/badge/Symcon-PHPModul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Version](https://img.shields.io/badge/Modul%20Version-2.00-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) -[![Version](https://img.shields.io/badge/Symcon%20Version-6.1%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) +[![Version](https://img.shields.io/badge/Modul%20Version-2.10-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) +[![Version](https://img.shields.io/badge/Symcon%20Version-7.0%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) [![Check Style](https://github.com/Nall-chan/ONVIF/workflows/Check%20Style/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) [![Run Tests](https://github.com/Nall-chan/ONVIF/workflows/Run%20Tests/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) @@ -31,8 +31,8 @@ Bildet Digitale Ausgänge (Relays) in Symcon ab. ## 2. Voraussetzungen -* IP-Symcon ab Version 6.1 -* Kameras oder Video-Encoder mit ONVIF Profil S Unterstützung. +* IP-Symcon ab Version 7.0 +* Kameras oder Video-Encoder mit ONVIF Profil S und/oder Profil T Unterstützung. * Geräte müssen über mindestens einen Digitalen Ausgang (bzw. Relais) verfügen. ## 3. Software-Installation diff --git a/ONVIF Discovery/README.md b/ONVIF Discovery/README.md index 03531a2..1ccb44a 100644 --- a/ONVIF Discovery/README.md +++ b/ONVIF Discovery/README.md @@ -1,6 +1,6 @@ [![SDK](https://img.shields.io/badge/Symcon-PHPModul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Version](https://img.shields.io/badge/Modul%20Version-2.00-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) -[![Version](https://img.shields.io/badge/Symcon%20Version-6.1%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) +[![Version](https://img.shields.io/badge/Modul%20Version-2.10-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) +[![Version](https://img.shields.io/badge/Symcon%20Version-7.0%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) [![Check Style](https://github.com/Nall-chan/ONVIF/workflows/Check%20Style/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) [![Run Tests](https://github.com/Nall-chan/ONVIF/workflows/Run%20Tests/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) @@ -34,8 +34,8 @@ Erkennt ONVIF kompatible Geräte innerhalb des lokalen LAN. ## 2. Voraussetzungen -* IP-Symcon ab Version 6.1 -* Kameras oder Video-Encoder mit ONVIF Profil S Unterstützung. +* IP-Symcon ab Version 7.0 +* Kameras oder Video-Encoder mit ONVIF Profil S und/oder Profil T Unterstützung. * Geräte und Symcon müssen per Multicast kommunizieren können [(siehe 4.)](#laden-der-konfigurationsseite). ## 3. Software-Installation diff --git a/ONVIF Events/README.md b/ONVIF Events/README.md index 53cbd1f..fb33f2b 100644 --- a/ONVIF Events/README.md +++ b/ONVIF Events/README.md @@ -1,6 +1,6 @@ [![SDK](https://img.shields.io/badge/Symcon-PHPModul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Version](https://img.shields.io/badge/Modul%20Version-2.00-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) -[![Version](https://img.shields.io/badge/Symcon%20Version-6.1%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) +[![Version](https://img.shields.io/badge/Modul%20Version-2.10-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) +[![Version](https://img.shields.io/badge/Symcon%20Version-7.0%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) [![Check Style](https://github.com/Nall-chan/ONVIF/workflows/Check%20Style/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) [![Run Tests](https://github.com/Nall-chan/ONVIF/workflows/Run%20Tests/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) @@ -38,8 +38,8 @@ Bildet verschiedene Ereignisse (Events) als Statusvariablen in Symcon ab. ## 2. Voraussetzungen -* IP-Symcon ab Version 6.1 -* Kameras oder Video-Encoder mit ONVIF Profil S Unterstützung. +* IP-Symcon ab Version 7.0 +* Kameras oder Video-Encoder mit ONVIF Profil S und/oder Profil T Unterstützung. * Geräte müssen ONVIF-Events unterstützen. ## 3. Software-Installation diff --git a/ONVIF IO/README.md b/ONVIF IO/README.md index a1bde96..1d57c98 100644 --- a/ONVIF IO/README.md +++ b/ONVIF IO/README.md @@ -1,6 +1,6 @@ [![SDK](https://img.shields.io/badge/Symcon-PHPModul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Version](https://img.shields.io/badge/Modul%20Version-2.00-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) -[![Version](https://img.shields.io/badge/Symcon%20Version-6.1%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) +[![Version](https://img.shields.io/badge/Modul%20Version-2.10-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) +[![Version](https://img.shields.io/badge/Symcon%20Version-7.0%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) [![Check Style](https://github.com/Nall-chan/ONVIF/workflows/Check%20Style/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) [![Run Tests](https://github.com/Nall-chan/ONVIF/workflows/Run%20Tests/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) @@ -16,6 +16,7 @@ Stellt die Verbindung zu einem ONVIF-Gerät her. - [3. Software-Installation](#3-software-installation) - [4. Einrichten der Instanzen in IP-Symcon](#4-einrichten-der-instanzen-in-ip-symcon) - [Konfigurationsseite: Übersicht](#konfigurationsseite-übersicht) + - [Konfigurationsseite: Ereignisse möglich](#konfigurationsseite-ereignisse-möglich) - [Konfigurationsseite: Ereignisse nicht möglich](#konfigurationsseite-ereignisse-nicht-möglich) - [5. Statusvariablen](#5-statusvariablen) - [6. WebFront](#6-webfront) @@ -33,8 +34,8 @@ Stellt die Verbindung zu einem ONVIF-Gerät her. ## 2. Voraussetzungen -* IP-Symcon ab Version 6.1 -* Kameras oder Video-Encoder mit ONVIF Profil S Unterstützung. +* IP-Symcon ab Version 7.0 +* Kameras oder Video-Encoder mit ONVIF Profil S und/oder Profil T Unterstützung. ## 3. Software-Installation @@ -49,15 +50,21 @@ Stellt die Verbindung zu einem ONVIF-Gerät her. ### Konfigurationsseite: Übersicht -| Name | Text | Beschreibung | -| ------------ | ------------------- | ----------------------------------------------------------------------------- | -| Open | Aktiv | Öffnet/Aktiviert die Verbindung zum Gerät. | -| Address | Adresse | URL von dem Gerät (z.B. http://192.168.1.111:8080) | -| Username | Benutzername | Benutzername für die Anmeldung | -| Password | Passwort | Passwort zum Benutzernamen | -| WebHookIP | Experteneinstellung | IP Adresse unter welcher IPS von dem Gerät aus erreichbar ist. | -| WebHookPort | Experteneinstellung | Port unter welchem IPS von dem Gerät aus erreichbar ist (3777) | -| WebHookHTTPS | Experteneinstellung | true wenn https benutzt werden soll | +| Name | Text | Typ | Beschreibung | +| ------------------------------- | -------------------------------- | ------- | ---------------------------------------------------------------------- | +| Open | Aktiv | bool | Öffnet/Aktiviert die Verbindung zum Gerät | +| Address | Adresse | string | URL von dem Gerät (z.B. http://192.168.1.111:8080) | +| Username | Benutzername | string | Benutzername für die Anmeldung | +| Password | Passwort | string | Passwort zum Benutzernamen | +| EventHandler | Ereignisse verarbeiten | Bitmask | Bit0: Subscribe, Bit1: PullPoint | +| WebHookIP | Experteneinstellung (Abonnieren) | string | IP Adresse unter welcher IPS von dem Gerät aus erreichbar ist | +| WebHookPort | Experteneinstellung (Abonnieren) | int | Port unter welchem IPS von dem Gerät aus erreichbar ist (3777) | +| WebHookHTTPS | Experteneinstellung (Abonnieren) | bool | true wenn https benutzt werden soll | +| SubscribeInitialTerminationTime | Experteneinstellung (Abonnieren) | int | Erstes Timeout welches beim abonnieren angefragt wird | +| SubscribeEventTimeout | Experteneinstellung (Abonnieren) | int | Timeout bis wann das erste Ereignis eintreffen muss | +| PullPointInitialTerminationTime | Experteneinstellung (Abfragen) | int | Erstes Timeout welches beim abonnieren angefragt wird | +| PullPointTimeout | Experteneinstellung (Abfragen) | int | Timeout bis wann das Gerät warten soll, bevor es die Verbindung trennt | +| MessageLimit | Experteneinstellung (Abfragen) | int | Maximal Anzahl von Ereignissen pro Abfrage | ![Config](imgs/Config2.png) @@ -65,14 +72,36 @@ Der Aktions-Bereich zeigt aktuelle Informationen zur Verbindung an. Unter `Geräteinformationen` werden die gemeldeten Informationen und erkannten Fähigkeiten aufgeführt. -Sofern das Gerät ONVIF-Ereignisse unterstützt, wird eine Adresse unter `Abonnementreferenz` angezeigt, welche Symcon vom Gerät erhalten hat. +### Konfigurationsseite: Ereignisse möglich + +Es gibt zwei verschiedene Arten der Ereignisverarbeitung welche vom IO unterstützt werden. +Die bevorzugte Variante wird vom IO automatisch anhand der ermittelten Fähigkeiten der Geräte festgelegt. + +__Abonnieren__ Für Geräte welche das ONVIF Profile S unterstützen, wird der `Ereignis-Hook`, auf welchen Symcon die Nachrichten des Endgerätes empfängt angezeigt. Die IP-Adresse des `Ereignis-Hook` wird automatisch ermittelt, je nachdem über welchen Adresse das Gerät erreichbar ist. **Diese Erkennung funktioniert nicht bei NAT, da hier die externe Adresse Symcon nicht automatisch ermitteln kann. Es müssen die [Spezialschalter](https://www.symcon.de/service/dokumentation/entwicklerbereich/spezialschalter/) `NATSupport` und `NATPublicIP` benutzt werden** -**Wird der übliche Port (3777) von Symcon nicht benutzt (z.B. forwarding NAT) so kann hier der Port, unter welchen Symcon erreichbar ist, angepasst werden.** +Sollte es nötig sein, so können bei Bedarf die eigene IP und der Port, sowie die Verwendung von https anstatt http, in den `Experteneinstellungen (Ereignisse abonnieren)` geändert und fixiert werden. + +**Wird der übliche Port (3777) von Symcon nicht benutzt (z.B. Port forwarding) so kann hier auch der Port, unter welchen Symcon erreichbar ist, angepasst werden.** + +--- + +__Abfragen__ + +Für Geräte welche das Profil S nicht unterstützen, gibt es außerdem noch die Möglichkeit die Ereignisse von dem Gerät abzufragen. +Hierzu baut Symcon der IO eine Verbindung zum Gerät auf und wartet auf eine Antwort. Das Gerät sendet bis zum erreichen der Wartezeit ein auftretendes Ereignis als Antwort an Symcon. +Anschließend baut Symcon die nächste Verbindung auf. +**Bei dieser Art der Verarbeitung ist zu beachten, dass permanent ein PHP-Thread von der IO-Instanz belegt wird!** + +--- + +__Allgemein__ + +Sofern das Gerät ONVIF-Ereignisse unterstützt und Symcon sich erfolgreich am Gerät angemeldet hat, wird eine Adresse unter `Abonnementreferenz` angezeigt. In der Tabelle wird eine Liste aller vom Gerät gemeldeten Ereignissen angezeigt, welche sich in Symcon nutzen lassen. Über das Feld `Benutzt` wird angezeigt ob das Ereignis in einer Instanz konfiguriert wurde. Und über das Zahnrad einer Zeile werden diese Instanzen tabellarisch angezeigt. diff --git a/ONVIF IO/form.json b/ONVIF IO/form.json index e6aa6f4..1abbcdd 100644 --- a/ONVIF IO/form.json +++ b/ONVIF IO/form.json @@ -49,6 +49,7 @@ "type": "Select", "name": "EventHandler", "caption": "Event handling", + "onChange": "IPS_RequestAction($id,'EventHandler',$EventHandler);", "options": [ { "caption": "never", @@ -70,8 +71,8 @@ }, { "type": "ExpansionPanel", - "name": "WebHookExpansionPanel", - "caption": "Expert settings event hook", + "name": "SubscribeExpansionPanel", + "caption": "Expert settings (event subscribe)", "items": [ { "type": "RowLayout", @@ -95,6 +96,58 @@ "caption": "use https" } ] + }, + { + "type": "NumberSpinner", + "name": "SubscribeInitialTerminationTime", + "caption": "Initial Termination Time", + "suffix": "minute(s)", + "width": "250px", + "minimum": 1, + "maximum": 60 + }, + { + "type": "NumberSpinner", + "name": "SubscribeEventTimeout", + "caption": "Timeout for first event", + "suffix": "second(s)", + "width": "250px", + "minimum": 0, + "maximum": 30 + } + ] + }, + { + "type": "ExpansionPanel", + "name": "PullPointExpansionPanel", + "caption": "Expert settings (event pull)", + "items": [ + { + "type": "NumberSpinner", + "name": "PullPointInitialTerminationTime", + "caption": "Initial Termination Time", + "suffix": "minute(s)", + "width": "250px", + "minimum": 1, + "maximum": 60 + }, + { + "type": "NumberSpinner", + "name": "PullPointTimeout", + "caption": "Pull request wait time", + "suffix": "second(s)", + "width": "250px", + "minimum": 5, + "maximum": 30 + }, + { + "type": "NumberSpinner", + "name": "MessageLimit", + "caption": "Message limit per request", + "suffix": "Events", + "width": "250px", + "minimum": 8, + "maximum": 256 } ] } diff --git a/ONVIF IO/imgs/Config2.png b/ONVIF IO/imgs/Config2.png index 375bf8e..728d379 100644 Binary files a/ONVIF IO/imgs/Config2.png and b/ONVIF IO/imgs/Config2.png differ diff --git a/ONVIF IO/locale.json b/ONVIF IO/locale.json index 669bda6..417b3f7 100644 --- a/ONVIF IO/locale.json +++ b/ONVIF IO/locale.json @@ -3,6 +3,7 @@ "de": { "Open": "Aktiv", "Address": "Adresse", + "Open in browser": "Im Browser öffnen", "Username": "Benutzername", "Password": "Passwort", "Event handling": "Ereignisse verarbeiten", @@ -10,10 +11,18 @@ "only subscribe": "Nur abonnieren", "only PullPoint": "Nur abfragen", "automatic": "Automatisch", - "Expert settings event hook": "Experteneinstellung Ereignis-Hook", + "Expert settings (event subscribe)": "Experteneinstellung (Ereignisse abonnieren)", "IP of event hook": "IP für Ereignis-Hook", "Port of event hook": "Port für Ereignis-Hook", "use https": "https benutzen", + "Timeout for first event": "Zeitüberschreitung für erstes Ereignis", + "second(s)": "Sekunde(n)", + "Initial Termination Time": "Erste Abbruchzeit", + "minute(s)": "Minute(n)", + "Expert settings (event pull)": "Experteneinstellung (Ereignisse abfragen)", + "Pull request wait time": "Wartezeit beim abfragen", + "Message limit per request": "Maximale Ereignisse pro Abfrage", + "Events": "Ereignisse", "Device information": "Geräteinformationen", "Event hook:": "Ereignis-Hook", "Subscription reference:": "Abonnementreferenz:", @@ -38,7 +47,7 @@ "Failed to get Imaging service capabilities. Device reported ONVIF T scope, but is not compliant!": "Imaging-Dienstfunktionen konnten nicht abgerufen werden. Das Gerät hat den ONVIF T-Scope gemeldet, ist aber nicht konform!", "Failed to get Event service capabilities. Device reported ONVIF T scope, but is not compliant!": "Ereignisdienstfunktionen konnten nicht abgerufen werden. Das Gerät hat den ONVIF T-Scope gemeldet, ist aber nicht konform!", "Analytics events could not be retrieved. The device reported AnalyticsTokens, but the Analytics namespace and XAddr were not reported!": "Analytics-Ereignisse konnten nicht abgerufen werden. Das Gerät hat AnalyticsTokens gemeldet, aber der Analytics-Namespace und XAddr wurden nicht gemeldet!", - "This device not support events.": "Dieses Gerät unterstützt keine Ereignisse.", + "This device not support events or they are disabled.": "Dieses Gerät unterstützt keine Ereignisse oder sie wurden deaktiviert.", "This device does not support ONVIF events, but it is mandatory.": "Dieses Gerät unterstützt keine ONVIF-Ereignisse, dies ist jedoch obligatorisch.", "Some features will not work properly": "Einige Funktionen werden nicht richtig funktionieren", "NATPublicIP is missing in special switches!": "NATPublicIP fehlt in den Spezialschaltern!", @@ -76,6 +85,7 @@ "Inputs: ": "Eingänge: ", "Outputs: ": "Ausgänge: ", "Serial ports: ": "Serialports: ", + "Device ignore timeout in PullMessagesRequest!\r\nThis can lead to increased network traffic, CPU load or a slow Symcon.\r\nIf possible, switch to subscribe to avoid this error from the device.": "Gerät ignoriert das Timeout in PullMessagesRequest!\r\nDies kann zu erhöhten Netzwerkverkehr, CPU-Last oder einem langsamen Symcon führen.\r\nSofern möglich, auf abonnieren wechseln um diesen Fehler vom Gerät zu vermeiden.", "This module is free for non-commercial use,\r\nDonations in support of the author are accepted here:": "Dieses Modul ist für die nicht kommerzielle Nutzung kostenlos,\r\nSchenkungen als Unterstützung für den Autor werden hier akzeptiert:" } } diff --git a/ONVIF IO/module.php b/ONVIF IO/module.php index e187382..f082a9a 100644 --- a/ONVIF IO/module.php +++ b/ONVIF IO/module.php @@ -19,6 +19,7 @@ * @property bool $WaitForFirstEvent * @property \ONVIF\EventHandler $usedEventHandler * @property \ONVIF\Profile $Profile + * @property string $TerminationTime * @property array $Warnings * @method void RegisterAttributeArray(string $name, mixed $Value, int $Size = 0) * @method mixed ReadAttributeArray(string $name) @@ -50,6 +51,11 @@ public function Create(): void $this->RegisterPropertyString('WebHookIP', ''); $this->RegisterPropertyBoolean('WebHookHTTPS', false); $this->RegisterPropertyInteger('WebHookPort', 3777); + $this->RegisterPropertyInteger('SubscribeEventTimeout', 5); + $this->RegisterPropertyInteger('SubscribeInitialTerminationTime', 1); + $this->RegisterPropertyInteger('PullPointInitialTerminationTime', 1); + $this->RegisterPropertyInteger('PullPointTimeout', 10); + $this->RegisterPropertyInteger('MessageLimit', 32); $this->RegisterAttributeArray('VideoSources', []); $this->RegisterAttributeArray('AudioSources', []); $this->RegisterAttributeArray('VideoSourcesJPEG', []); @@ -75,7 +81,6 @@ public function Create(): void $this->RegisterAttributeString('SubscriptionId', ''); $this->RegisterAttributeInteger('CapabilitiesVersion', 0); $this->RegisterTimer('RenewSubscription', 0, 'IPS_RequestAction(' . $this->InstanceID . ',"Renew",true);'); - //$this->RegisterTimer('PullMessages', 0, 'IPS_RequestAction(' . $this->InstanceID . ',"PullMessages",true);'); $this->Host = ''; $this->MyIP = ''; $this->MyPort = 3777; @@ -83,6 +88,7 @@ public function Create(): void $this->isSubscribed = false; $this->Profile = new \ONVIF\Profile(); $this->usedEventHandler = new \ONVIF\EventHandler(); + $this->TerminationTime = 'PT1M0S'; $this->Warnings = []; $this->WaitForFirstEvent = false; if (IPS_GetKernelRunlevel() == KR_READY) { @@ -129,7 +135,6 @@ public function MessageSink(int $TimeStamp, int $SenderID, int $Message, array $ public function ApplyChanges(): void { $this->SetTimerInterval('RenewSubscription', 0); - //$this->SetTimerInterval('PullMessages', 0); if ($this->GetStatus() == IS_ACTIVE) { // block childs $this->SetStatus(IS_INACTIVE); } @@ -593,14 +598,13 @@ public function RequestAction(string $Ident, mixed $Value): void // No break. Add additional comment above this line if intentional case 'CreatePullPointSubscription': if ($this->CreatePullPointSubscription()) { - $this->SetSynchronizationPoint(); $this->UpdateFormField('DeviceData', 'items', json_encode($this->GetDeviceDataForForm())); $this->UpdateFormField('DeviceDataPanel', 'visible', true); $this->UpdateFormField('DeviceDataPanel', 'expanded', true); $this->UpdateFormField('Events', 'visible', true); + // Start PullMessages loop + IPS_RunScriptText('IPS_RequestAction(' . $this->InstanceID . ',"PullMessages",true);'); } - // Start PullMessages loop - IPS_RunScriptText('IPS_RequestAction(' . $this->InstanceID . ',"PullMessages",true);'); return; case 'PullMessages': $this->PullMessages(); @@ -631,6 +635,26 @@ public function RequestAction(string $Ident, mixed $Value): void case'KernelReady': $this->KernelReady(); return; + case 'EventHandler': + switch ((int) $Value) { + case \ONVIF\EventHandler::None: + $this->UpdateFormField('SubscribeExpansionPanel', 'visible', false); + $this->UpdateFormField('PullPointExpansionPanel', 'visible', false); + break; + case \ONVIF\EventHandler::Subscribe: + $this->UpdateFormField('SubscribeExpansionPanel', 'visible', true); + $this->UpdateFormField('PullPointExpansionPanel', 'visible', false); + break; + case \ONVIF\EventHandler::PullPoint: + $this->UpdateFormField('SubscribeExpansionPanel', 'visible', false); + $this->UpdateFormField('PullPointExpansionPanel', 'visible', true); + break; + case \ONVIF\EventHandler::Automatic: + $this->UpdateFormField('SubscribeExpansionPanel', 'visible', true); + $this->UpdateFormField('PullPointExpansionPanel', 'visible', true); + break; + } + return; } } public function GetConfigurationForm(): string @@ -639,14 +663,30 @@ public function GetConfigurationForm(): string if ($this->GetStatus() == IS_CREATING) { return json_encode($Form); } - if ($this->GetStatus() == IS_ACTIVE) { - if ($this->Profile->Profile == \ONVIF\Profile::T) { + $EventHandler = $this->ReadPropertyInteger('EventHandler'); + switch ($EventHandler) { + case \ONVIF\EventHandler::None: $Form['elements'][4]['visible'] = false; - } + $Form['elements'][5]['visible'] = false; + break; + case \ONVIF\EventHandler::Subscribe: + $Form['elements'][4]['visible'] = true; + $Form['elements'][5]['visible'] = false; + break; + case \ONVIF\EventHandler::PullPoint: + $Form['elements'][4]['visible'] = false; + $Form['elements'][5]['visible'] = true; + break; + case \ONVIF\EventHandler::Automatic: + $Form['elements'][4]['visible'] = true; + $Form['elements'][5]['visible'] = true; + break; + } + if ($this->GetStatus() == IS_ACTIVE) { $Form['actions'][1]['items'][0]['items'] = $this->GetDeviceDataForForm(); $SubscriptionReference = $this->ReadAttributeString('SubscriptionReference'); if ($SubscriptionReference == '') { - $SubscriptionReference = $this->Translate('This device not support events.'); + $SubscriptionReference = $this->Translate('This device not support events or they are disabled.'); $Form['actions'][4]['visible'] = false; } $Form['actions'][3]['items'][1]['caption'] = $SubscriptionReference; @@ -837,26 +877,35 @@ protected function CreatePullPointSubscription(): bool if ($XAddr[\ONVIF\NS::Event] == '') { return false; } + $PullPointInitialTerminationTime = $this->ReadPropertyInteger('PullPointInitialTerminationTime'); + $AllowedEventHandler = $this->ReadPropertyInteger('EventHandler'); + $this->lock('EventHandler'); $Action = 'http://www.onvif.org/ver10/events/wsdl/EventPortType/CreatePullPointSubscriptionRequest'; - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'Action', new SoapVar($Action, XSD_ANYURI, '', \ONVIF\NS::Addressing), true); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'To', new SoapVar($this->Host . $XAddr[\ONVIF\NS::Event], XSD_ANYURI, '', \ONVIF\NS::Addressing), true); - $Address[] = new SoapVar(\ONVIF\NS::Addressing . '/anonymous', XSD_ANYURI, '', \ONVIF\NS::Addressing, 'Address', \ONVIF\NS::Addressing); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'ReplyTo', new SoapVar($Address, SOAP_ENC_OBJECT, '', \ONVIF\NS::Addressing)); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'MessageID', new SoapVar(self::generateMessageID(), XSD_ANYURI, '', \ONVIF\NS::Addressing)); + $Header = $this->GenerateSOAPHeader($Action, $this->Host . $XAddr[\ONVIF\NS::Event]); $empty = ''; $Params = [ - 'InitialTerminationTime' => 'PT60S' + 'InitialTerminationTime' => 'PT' . (string) $PullPointInitialTerminationTime . 'M' ]; $CreatePullPointResult = $this->SendData($XAddr[\ONVIF\NS::Event], \ONVIF\WSDL::Event, 'CreatePullPointSubscription', true, $Params, $empty, $Header); if (is_a($CreatePullPointResult, 'SoapFault')) { - $this->SetStatus(IS_EBASE + 3); + $this->unlock('EventHandler'); + if ($AllowedEventHandler == \ONVIF\EventHandler::Automatic) { + $this->SetStatus(IS_EBASE + 4); + } else { + $this->SetStatus(IS_EBASE + 3); + } $this->LogMessage($this->Translate('Connection lost'), KL_ERROR); /** @var SoapFault $CreatePullPointResult */ $this->ShowLastError($CreatePullPointResult->getMessage()); return false; } if (!is_object($CreatePullPointResult)) { - $this->SetStatus(IS_EBASE + 3); + $this->unlock('EventHandler'); + if ($AllowedEventHandler == \ONVIF\EventHandler::Automatic) { + $this->SetStatus(IS_EBASE + 4); + } else { + $this->SetStatus(IS_EBASE + 3); + } $this->LogMessage($this->Translate('Connection lost'), KL_ERROR); $this->ShowLastError('No Response'); return false; @@ -884,42 +933,39 @@ protected function CreatePullPointSubscription(): bool } $this->isSubscribed = true; $this->usedEventHandler = new \ONVIF\EventHandler(\ONVIF\EventHandler::PullPoint); - $this->SetTimerInterval('RenewSubscription', 55 * 1000); - //if ($this->GetStatus() != IS_ACTIVE) { + $this->SetRenewInterval($CreatePullPointResult); + $this->SetSynchronizationPoint(); + $this->unlock('EventHandler'); $this->LogMessage($this->Translate('Interface connected'), KL_MESSAGE); $this->SetStatus(IS_ACTIVE); - //} return true; } - protected function PullMessages(): bool + protected function PullMessages(): void { - //$this->SetTimerInterval('PullMessages', 0); if (!$this->isSubscribed) { // Exit PullMessages loop - return true; + return; } $SubscriptionReference = $this->ReadAttributeString('SubscriptionReference'); if ($SubscriptionReference == '') { $this->SendDebug('ERROR PullMessages', 'No SubscriptionReference', 0); $this->LogMessage($this->Translate('Call PullMessages with no SubscriptionReference'), KL_ERROR); - return $this->CreatePullPointSubscription(); + $this->SetStatus(IS_EBASE + 3); + $this->LogMessage($this->Translate('Connection lost'), KL_ERROR); + return; } + $Timeout = $this->ReadPropertyInteger('PullPointTimeout'); $Action = 'http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesRequest'; - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'Action', new SoapVar($Action, XSD_ANYURI, '', \ONVIF\NS::Addressing), true); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'To', new SoapVar($SubscriptionReference, XSD_ANYURI, '', \ONVIF\NS::Addressing), true); - $Address[] = new SoapVar(\ONVIF\NS::Addressing . '/anonymous', XSD_ANYURI, '', \ONVIF\NS::Addressing, 'Address', \ONVIF\NS::Addressing); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'ReplyTo', new SoapVar($Address, SOAP_ENC_OBJECT, '', \ONVIF\NS::Addressing)); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'MessageID', new SoapVar(self::generateMessageID(), XSD_ANYURI, '', \ONVIF\NS::Addressing)); + $Header = $this->GenerateSOAPHeader($Action, $SubscriptionReference); $Params = [ - 'Timeout' => 'PT10S', - 'MessageLimit'=> 32 + 'Timeout' => 'PT' . (string) $Timeout . 'S', + 'MessageLimit'=> $this->ReadPropertyInteger('MessageLimit') ]; $Response = ''; + $ResponseTime = time() + $Timeout; $PullMessagesResult = $this->SendData($SubscriptionReference, \ONVIF\WSDL::Event, 'PullMessages', true, $Params, $Response, $Header, 15); if ($Response) { if (is_a($PullMessagesResult, 'SoapFault')) { - //$this->SetTimerInterval('PullMessages', 0); - //return $this->CreatePullPointSubscription(); if ($this->isSubscribed) { /** @var SoapFault $PullMessagesResult */ $this->SendDebug('ERROR PullMessages', 'No Response', 0); @@ -927,19 +973,18 @@ protected function PullMessages(): bool $this->SetStatus(IS_EBASE + 3); $this->isSubscribed = false; } - return false; + return; } } - /*if (!is_object($PullMessagesResult)) { - //$this->SetTimerInterval('PullMessages', 0); - $this->SendDebug('ERROR PullMessages', 'No Response', 0); - $this->LogMessage($this->Translate('Error PullMessages with no Response'), KL_ERROR); - $this->SetStatus(IS_EBASE + 3); - $this->isSubscribed = false; - return false; - }*/ - //$this->SetTimerInterval('PullMessages', 0); if ($this->isSubscribed) { + if (is_object($PullMessagesResult)) { + if (!property_exists($PullMessagesResult, 'NotificationMessage')) { + if (time() < $ResponseTime) { + $this->LogMessage($this->Translate("Device ignore timeout in PullMessagesRequest!\r\nThis can lead to increased network traffic, CPU load or a slow Symcon.\r\nIf possible, switch to subscribe to avoid this error from the device."), KL_WARNING); + IPS_Sleep(($ResponseTime - time()) * 1000); + } + } + } // Continue PullMessages loop when subscribed IPS_RunScriptText('IPS_RequestAction(' . $this->InstanceID . ',"PullMessages",true);'); } @@ -948,7 +993,7 @@ protected function PullMessages(): bool $this->DecodeNotificationMessage($Response); } } - return true; + return; } protected function Subscribe(): bool { @@ -956,19 +1001,16 @@ protected function Subscribe(): bool if ($XAddr[\ONVIF\NS::Event] == '') { return false; } + $SubscribeInitialTerminationTime = $this->ReadPropertyInteger('SubscribeInitialTerminationTime'); $AllowedEventHandler = $this->ReadPropertyInteger('EventHandler'); $this->lock('EventHandler'); $Action = 'http://docs.oasis-open.org/wsn/bw-2/NotificationProducer/SubscribeRequest'; - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'Action', new SoapVar($Action, XSD_ANYURI, '', \ONVIF\NS::Addressing), true); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'To', new SoapVar($this->Host . $XAddr[\ONVIF\NS::Event], XSD_ANYURI, '', \ONVIF\NS::Addressing), true); - $Address[] = new SoapVar(\ONVIF\NS::Addressing . '/anonymous', XSD_ANYURI, '', \ONVIF\NS::Addressing, 'Address', \ONVIF\NS::Addressing); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'ReplyTo', new SoapVar($Address, SOAP_ENC_OBJECT, '', \ONVIF\NS::Addressing)); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'MessageID', new SoapVar(self::generateMessageID(), XSD_ANYURI, '', \ONVIF\NS::Addressing)); + $Header = $this->GenerateSOAPHeader($Action, $this->Host . $XAddr[\ONVIF\NS::Event]); $Params = [ 'ConsumerReference' => [ 'Address' => $this->ReadAttributeString('ConsumerAddress') ], - 'InitialTerminationTime' => 'PT60S' + 'InitialTerminationTime' => 'PT' . (string) $SubscribeInitialTerminationTime . 'M' ]; $Response = ''; $this->WaitForFirstEvent = true; @@ -1007,20 +1049,32 @@ protected function Subscribe(): bool } $this->isSubscribed = true; $this->usedEventHandler = new \ONVIF\EventHandler(\ONVIF\EventHandler::Subscribe); - $this->SetTimerInterval('RenewSubscription', 55 * 1000); + $this->SetRenewInterval($SubscribeResult); $this->SetSynchronizationPoint(); $this->unlock('EventHandler'); - for ($i = 0; $i < 500; $i++) { - if (!$this->WaitForFirstEvent) { - $this->UpdateFormField('DeviceData', 'items', json_encode($this->GetDeviceDataForForm())); - $this->UpdateFormField('DeviceDataPanel', 'visible', true); - $this->UpdateFormField('DeviceDataPanel', 'expanded', true); - $this->UpdateFormField('Events', 'visible', true); - $this->LogMessage($this->Translate('Interface connected'), KL_MESSAGE); - $this->SetStatus(IS_ACTIVE); - return true; + $EventTimeout = $this->ReadPropertyInteger('SubscribeEventTimeout') * 1000; + if ($EventTimeout) { + for ($i = 0; $i < $EventTimeout; $i = $i + 50) { + if (!$this->WaitForFirstEvent) { + $this->UpdateFormField('DeviceData', 'items', json_encode($this->GetDeviceDataForForm())); + $this->UpdateFormField('DeviceDataPanel', 'visible', true); + $this->UpdateFormField('DeviceDataPanel', 'expanded', true); + $this->UpdateFormField('Events', 'visible', true); + $this->LogMessage($this->Translate('Interface connected'), KL_MESSAGE); + $this->SetStatus(IS_ACTIVE); + return true; + } + IPS_Sleep(50); } - IPS_Sleep(8); + } else { + $this->WaitForFirstEvent = false; + $this->UpdateFormField('DeviceData', 'items', json_encode($this->GetDeviceDataForForm())); + $this->UpdateFormField('DeviceDataPanel', 'visible', true); + $this->UpdateFormField('DeviceDataPanel', 'expanded', true); + $this->UpdateFormField('Events', 'visible', true); + $this->LogMessage($this->Translate('Interface connected'), KL_MESSAGE); + $this->SetStatus(IS_ACTIVE); + return true; } $this->Unsubscribe(); $this->WaitForFirstEvent = false; @@ -1039,11 +1093,7 @@ protected function SetSynchronizationPoint(): bool return false; } $Action = 'http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/SetSynchronizationPointRequest'; - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'Action', new SoapVar($Action, XSD_ANYURI, '', \ONVIF\NS::Addressing), true); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'To', new SoapVar($SubscriptionReference, XSD_ANYURI, '', \ONVIF\NS::Addressing), true); - $Address[] = new SoapVar(\ONVIF\NS::Addressing . '/anonymous', XSD_ANYURI, '', \ONVIF\NS::Addressing, 'Address', \ONVIF\NS::Addressing); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'ReplyTo', new SoapVar($Address, SOAP_ENC_OBJECT, '', \ONVIF\NS::Addressing)); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'MessageID', new SoapVar(self::generateMessageID(), XSD_ANYURI, '', \ONVIF\NS::Addressing)); + $Header = $this->GenerateSOAPHeader($Action, $SubscriptionReference); $SubscriptionId = $this->ReadAttributeString('SubscriptionId'); if ($SubscriptionId != '') { $xml = new DOMDocument(); @@ -1063,6 +1113,7 @@ protected function SetSynchronizationPoint(): bool } protected function Renew(): bool { + $this->SetTimerInterval('RenewSubscription', 0); if (!$this->isSubscribed) { return true; } @@ -1075,11 +1126,7 @@ protected function Renew(): bool return false; } $Action = 'http://docs.oasis-open.org/wsn/bw-2/SubscriptionManager/RenewRequest'; - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'Action', new SoapVar($Action, XSD_ANYURI, '', \ONVIF\NS::Addressing), true); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'To', new SoapVar($SubscriptionReference, XSD_ANYURI, '', \ONVIF\NS::Addressing), true); - $Address[] = new SoapVar(\ONVIF\NS::Addressing . '/anonymous', XSD_ANYURI, '', \ONVIF\NS::Addressing, 'Address', \ONVIF\NS::Addressing); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'ReplyTo', new SoapVar($Address, SOAP_ENC_OBJECT, '', \ONVIF\NS::Addressing)); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'MessageID', new SoapVar(self::generateMessageID(), XSD_ANYURI, '', \ONVIF\NS::Addressing)); + $Header = $this->GenerateSOAPHeader($Action, $SubscriptionReference); $SubscriptionId = $this->ReadAttributeString('SubscriptionId'); if ($SubscriptionId != '') { $xml = new DOMDocument(); @@ -1089,7 +1136,7 @@ protected function Renew(): bool $Header[] = new SoapHeader($ns, $name, new SoapVar($SubscriptionId, XSD_ANYXML), true); } $Params = [ - 'TerminationTime' => 'PT1M' + 'TerminationTime' => $this->TerminationTime ]; $empty = ''; $RenewResult = $this->SendData($SubscriptionReference, \ONVIF\WSDL::Event, 'Renew', true, $Params, $empty, $Header); @@ -1098,7 +1145,6 @@ protected function Renew(): bool $this->LogMessage($this->Translate('Error Renew Subscription with:') . $RenewResult->getMessage(), KL_ERROR); $this->SetStatus(IS_EBASE + 3); $this->isSubscribed = false; - $this->SetTimerInterval('RenewSubscription', 0); $this->unlock('EventHandler'); return false; } @@ -1107,10 +1153,10 @@ protected function Renew(): bool $this->LogMessage($this->Translate('Error Renew with no Response'), KL_ERROR); $this->SetStatus(IS_EBASE + 3); $this->isSubscribed = false; - $this->SetTimerInterval('RenewSubscription', 0); $this->unlock('EventHandler'); return false; } + $this->SetRenewInterval($RenewResult); $this->unlock('EventHandler'); return true; } @@ -1122,7 +1168,6 @@ protected function Unsubscribe(): bool } $this->lock('EventHandler'); $this->SetTimerInterval('RenewSubscription', 0); - //$this->SetTimerInterval('PullMessages', 0); $this->isSubscribed = false; $this->UpdateFormField('SubscriptionReference', 'caption', ''); $this->UpdateFormField('SubscriptionReferenceRow', 'visible', false); @@ -1137,11 +1182,7 @@ protected function Unsubscribe(): bool return false; } $Action = 'http://docs.oasis-open.org/wsn/bw-2/SubscriptionManager/UnsubscribeRequest'; - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'Action', new SoapVar($Action, XSD_ANYURI, '', \ONVIF\NS::Addressing), true); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'To', new SoapVar($SubscriptionReference, XSD_ANYURI, '', \ONVIF\NS::Addressing), true); - $Address[] = new SoapVar(\ONVIF\NS::Addressing . '/anonymous', XSD_ANYURI, '', \ONVIF\NS::Addressing, 'Address', \ONVIF\NS::Addressing); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'ReplyTo', new SoapVar($Address, SOAP_ENC_OBJECT, '', \ONVIF\NS::Addressing)); - $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'MessageID', new SoapVar(self::generateMessageID(), XSD_ANYURI, '', \ONVIF\NS::Addressing)); + $Header = $this->GenerateSOAPHeader($Action, $SubscriptionReference); if ($SubscriptionId != '') { $xml = new DOMDocument(); $xml->loadXML($SubscriptionId); @@ -1959,4 +2000,24 @@ private function ConvertToMyNamespace(string $Value, array $ValueNS): string } return $Value; } + private function GenerateSOAPHeader(string $Action, string $Url): array + { + $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'Action', new SoapVar($Action, XSD_ANYURI, '', \ONVIF\NS::Addressing), true); + $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'To', new SoapVar($Url, XSD_ANYURI, '', \ONVIF\NS::Addressing), true); + $Address[] = new SoapVar(\ONVIF\NS::Addressing . '/anonymous', XSD_ANYURI, '', \ONVIF\NS::Addressing, 'Address', \ONVIF\NS::Addressing); + $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'ReplyTo', new SoapVar($Address, SOAP_ENC_OBJECT, '', \ONVIF\NS::Addressing)); + $Header[] = new SoapHeader(\ONVIF\NS::Addressing, 'MessageID', new SoapVar(self::generateMessageID(), XSD_ANYURI, '', \ONVIF\NS::Addressing)); + return $Header; + } + private function SetRenewInterval(object $Result): void + { + $CurrentTime = DateTimeImmutable::createFromFormat(DATE_W3C, $Result->CurrentTime); + $TerminationTime = DateTimeImmutable::createFromFormat(DATE_W3C, $Result->TerminationTime); + $TimeDiff = $CurrentTime->diff($TerminationTime); + $this->TerminationTime = $TimeDiff->format('PT%iM%sS'); + $this->SendDebug('TerminationTime', $this->TerminationTime, 0); + $Interval = $TerminationTime->getTimestamp() - $CurrentTime->getTimestamp() - 5; + $this->SendDebug('Renew Interval', $Interval, 0); + $this->SetTimerInterval('RenewSubscription', $Interval * 1000); + } } diff --git a/ONVIF Image Grabber/README.md b/ONVIF Image Grabber/README.md index af06da7..9670da9 100644 --- a/ONVIF Image Grabber/README.md +++ b/ONVIF Image Grabber/README.md @@ -1,6 +1,6 @@ [![SDK](https://img.shields.io/badge/Symcon-PHPModul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Version](https://img.shields.io/badge/Modul%20Version-2.00-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) -[![Version](https://img.shields.io/badge/Symcon%20Version-6.1%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) +[![Version](https://img.shields.io/badge/Modul%20Version-2.10-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) +[![Version](https://img.shields.io/badge/Symcon%20Version-7.0%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) [![Check Style](https://github.com/Nall-chan/ONVIF/workflows/Check%20Style/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) [![Run Tests](https://github.com/Nall-chan/ONVIF/workflows/Run%20Tests/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) @@ -34,8 +34,8 @@ Speichert einzelne Snapshots (Standbilder) als ein IPS Medien-Objekt. ## 2. Voraussetzungen -* IP-Symcon ab Version 6.1 -* Kameras oder Video-Encoder mit ONVIF Profil S Unterstützung. +* IP-Symcon ab Version 7.0 +* Kameras oder Video-Encoder mit ONVIF Profil S und/oder Profil T Unterstützung. ## 3. Software-Installation diff --git a/ONVIF Media Stream/README.md b/ONVIF Media Stream/README.md index dd11c62..ca12ac8 100644 --- a/ONVIF Media Stream/README.md +++ b/ONVIF Media Stream/README.md @@ -1,6 +1,6 @@ [![SDK](https://img.shields.io/badge/Symcon-PHPModul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Version](https://img.shields.io/badge/Modul%20Version-2.00-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) -[![Version](https://img.shields.io/badge/Symcon%20Version-6.1%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) +[![Version](https://img.shields.io/badge/Modul%20Version-2.10-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) +[![Version](https://img.shields.io/badge/Symcon%20Version-7.0%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) [![Check Style](https://github.com/Nall-chan/ONVIF/workflows/Check%20Style/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) [![Run Tests](https://github.com/Nall-chan/ONVIF/workflows/Run%20Tests/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) @@ -46,8 +46,8 @@ Konfiguriert ein IPS Medien-Objekt anhand der Geräte-Fähigkeiten. ## 2. Voraussetzungen -* IP-Symcon ab Version 6.1 -* Kameras oder Video-Encoder mit ONVIF Profil S Unterstützung. +* IP-Symcon ab Version 7.0 +* Kameras oder Video-Encoder mit ONVIF Profil S und/oder Profil T Unterstützung. * Geräte müssen h264 Streams bereitstellen. (MJPEG/JPEG/h265 wird von Symcon nicht über RTSP unterstützt!) * PTZ Overlay wird offiziell nur für das WebFront unterstützt. diff --git a/README.md b/README.md index f189781..a3db711 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![SDK](https://img.shields.io/badge/Symcon-PHPModul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Version](https://img.shields.io/badge/Modul%20Version-2.00-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) -[![Version](https://img.shields.io/badge/Symcon%20Version-6.1%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) +[![Version](https://img.shields.io/badge/Modul%20Version-2.10-blue.svg)](https://community.symcon.de/t/modul-onvif-profil-s-fuer-ip-kameras-und-encoder/52036) +[![Version](https://img.shields.io/badge/Symcon%20Version-7.0%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) [![Check Style](https://github.com/Nall-chan/ONVIF/workflows/Check%20Style/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) [![Run Tests](https://github.com/Nall-chan/ONVIF/workflows/Run%20Tests/badge.svg)](https://github.com/Nall-chan/ONVIF/actions) @@ -40,7 +40,7 @@ Dies ist kein Fehler, sondern ein beabsichtigtes Verhalten. Es werden Instanzen zum auffinden (Discovery) und einrichten (Konfigurator) von Geräten in Symcon bereitgestellt. Diese Instanzen werden nur korrekt funktionieren, wenn die betreffenden Geräte entsprechend Konfiguriert wurden. -So gibt es Geräte bei welchen am Werk z.B. das ONVIF Protokoll deaktiviert ist. +So gibt es Geräte bei welchen am Werk z.B. das ONVIF Protokoll oder ONVIF Discover deaktiviert ist. Oder wo eine entsprechende Zugangsberechtigung erstellt bzw. erweitert werden muss. Eine Konfiguration der Geräte über Symcon ist in dieser Library aktuell nicht vorgesehen. Unerlässlich ist eine korrekte Uhrzeit auf den Geräten, da eine Authentifizierung sonst fehlschlägt. @@ -54,7 +54,7 @@ Es wird dringend empfohlen vor der Integration in IPS folgende Parameter in den - Nach Möglichkeit sollten die Geräte und der Symcon Host die Uhrzeit aus der gleichen Quelle beziehen (NTP-Server). - PTZ-Vorpositionen / Szenen (sofern vorhanden) - h264-Profile bzw. Media-Profile für ONVIF -- Sinnvolle Namen der Videoquellen und der Media-Profile, sofern die Geräte das umbenennen unterstützen. +- Sinnvolle Namen der Videoquellen, der Media-Profile und der Ein-/Ausgänge, sofern die Geräte das umbenennen unterstützen. ---------- ### Hinweise zum Symcon-System / Host @@ -64,14 +64,16 @@ Die Maximale Anzahl der gleichzeitig verwendbaren RTSP-Streams hängt von der Sy ---------- **Folgendes gilt nicht für reine Profil T Geräte:** -Um Ereignisse der Geräte in Symcon zu verarbeiten wird ein Webhook pro [IO-Modul](ONVIF%20IO/README.md) erzeugt. -Hier wird beim anlegen der Instanz automatisch nur der interne WebServer von Symcon auf Port 3777 eingetragen. -Die IP-Adresse auf welchem Symcon die Daten empfängt wird automatisch ermittelt. +Um Ereignisse der Geräte ressourcenschonend in Symcon zu verarbeiten, werden diese vom Gerät abonniert. Dazu wird beim abonnieren eine Zieladresse an das Gerät übertragen, an welches es auftretende Ereignisse senden soll. +Die Zieladresse ist ein Webhook, welcher pro [IO-Modul](ONVIF%20IO/README.md) automatisch erzeugt wird. +Beim anlegen der IO-Instanz wird automatisch nur der interne WebServer von Symcon auf Port 3777 eingetragen. +Die IP-Adresse auf welchem Symcon die Daten empfängt wird automatisch ermittelt. -Bei System mit aktiven NAT-Support funktioniert die automatische Erkennung der eigenen IP-Adresse nicht. __Hier wird automatisch die NATPublicIP aus den [Symcon-Spezialschaltern](https://www.symcon.de/service/dokumentation/entwicklerbereich/spezialschalter/) benutzt.__ +Bei System mit **aktiven NAT-Support** funktioniert die automatische Erkennung der eigenen IP-Adresse nicht. +__In dem Fall wird automatisch die NATPublicIP aus den [Symcon-Spezialschaltern](https://www.symcon.de/service/dokumentation/entwicklerbereich/spezialschalter/) benutzt.__ **Auch bei Systemen mit aktiven NAT-Support wird extern automatisch nur der Port 3777 beim anlegen von IO-Instanzen unterstützt.** -Sollte es nötig sein, so können bei Bedarf die eigene IP und der Port, sowie die Verwendung von https, in den IO-Instanzen unter `Experteneinstellungen` geändert und fixiert werden. +Sollte es nötig sein, so können bei Bedarf die eigene IP und der Port, sowie die Verwendung von https anstatt http, in den IO-Instanzen unter `Experteneinstellungen` geändert und fixiert werden. ---------- Damit Geräte über das [Discovery-Modul](ONVIF%20Discovery/README.md) gefunden werden können, müssen bei in gerouteten Netzen und bei NAT Systemen Multicast-Pakete korrekt weitergeleitet werden. @@ -81,7 +83,7 @@ Für das Discovery werden Pakete über die Multicast-Adresse `239.255.255.250` a ---------- ## 2. Voraussetzungen -* IP-Symcon ab Version 6.1 +* IP-Symcon ab Version 7.0 * Kameras oder Video-Encoder mit ONVIF Profil S und/oder Profil T Unterstützung. ## 3. Software-Installation @@ -138,6 +140,16 @@ Für das Discovery werden Pakete über die Multicast-Adresse `239.255.255.250` a ---------- ### 2. Changelog +**Version 2.10:** **(Dies ist die letzte Version für IPS kleiner Version 7.0)** +- Änderungen an der IO-Instanz: + - Möglichkeit die Geräte-URL im Browser zu öffnen. + - Die Art der Ereignisverarbeitung kann eingestellt werden. + - Experteneinstellungen für Abonnieren um erste Abbruchzeit (Subscribe Timeout) und Zeitüberschreitung des ersten Ereignis (Timeout nach Subscribe) erweitert. + - Experteneinstellungen für Ereignisse abfragen (PullPoint) hinzugefügt. + - Geräteinformationen um Informationen zur Ereignisverarbeitung ergänzt. + - Das Intervall zum erneuern der Registrierung für Ereignisse ist nicht mehr fest auf 55 Sekunden eingestellt, sondern wird automatisch durch das Feld `TerminationTime` aus der Antwort der Geräte berechnet. + + **Version 2.00:** - Verbindungsaufbau des IO überarbeitet. - Wechsel von PHP-Streams auf CURL zur Unterstützung von HTTP digest Authentifizierung. diff --git a/library.json b/library.json index 003aee2..172aeeb 100644 --- a/library.json +++ b/library.json @@ -6,7 +6,7 @@ "compatibility": { "version": "7.0" }, - "version": "2.01", - "build": 206, - "date": 1683304881 + "version": "2.10", + "build": 211, + "date": 1690797408 } \ No newline at end of file diff --git a/libs/ONVIF.inc.php b/libs/ONVIF.inc.php index 11bb02c..30ac231 100644 --- a/libs/ONVIF.inc.php +++ b/libs/ONVIF.inc.php @@ -4,16 +4,13 @@ namespace ONVIF; -/** - * @property-write string __last_request_headers - * @property-write string __last_response_headers - * - */ class ONVIFsoapClient extends \SoapClient { private string $User; private string $Pass; private array $Options; + private ?string $__last_request_headers; + private ?string $__last_response_headers; public function __construct(string $wsdl, array $options = []) { @@ -30,6 +27,17 @@ public function __construct(string $wsdl, array $options = []) } $this->Options = $options; } + + public function __getLastRequestHeaders(): ?string + { + return $this->__last_request_headers; + } + + public function __getLastResponseHeaders(): ?string + { + return $this->__last_response_headers; + } + public function __doRequest(string $request, string $location, string $action, int $version, bool $one_way = false): ?string { $headers = [ @@ -57,7 +65,6 @@ public function __doRequest(string $request, string $location, string $action, i curl_setopt($ch, CURLOPT_PASSWORD, $this->Pass); } $response = curl_exec($ch); - //$this->CurlInfo = curl_getinfo($ch); $http_code = curl_getinfo($ch)['http_code']; if ($http_code != 0) { $this->__last_request_headers = curl_getinfo($ch)['request_header'];