From 66f8c82af83789a33be8437fb209461386050b61 Mon Sep 17 00:00:00 2001 From: David Masshardt Date: Mon, 11 Nov 2024 20:11:25 +0100 Subject: [PATCH] Various Onvif fixes for IpCamera (#17732) I made various changes and fixes to the ONVIF connection in the IpCamera binding. Signed-off-by: David Masshardt --- .../org.openhab.binding.ipcamera/README.md | 5 + .../ipcamera/internal/CameraConfig.java | 5 + .../binding/ipcamera/internal/Helper.java | 12 + .../ipcamera/internal/ReolinkHandler.java | 6 +- .../internal/handler/IpCameraHandler.java | 15 +- .../ipcamera/internal/onvif/OnvifCodec.java | 5 + .../internal/onvif/OnvifConnection.java | 482 ++++++++++++------ .../internal/servlet/CameraServlet.java | 4 +- .../resources/OH-INF/i18n/ipcamera.properties | 12 + .../resources/OH-INF/thing/thing-types.xml | 30 ++ 10 files changed, 394 insertions(+), 182 deletions(-) diff --git a/bundles/org.openhab.binding.ipcamera/README.md b/bundles/org.openhab.binding.ipcamera/README.md index a7587950c51..9226c3ef842 100644 --- a/bundles/org.openhab.binding.ipcamera/README.md +++ b/bundles/org.openhab.binding.ipcamera/README.md @@ -209,6 +209,11 @@ If you do not specify any of these, the binding will use the default which shoul | `gifPreroll`| Store this many snapshots from BEFORE you trigger a GIF creation. Default: `0` will not use snapshots and will instead use a realtime stream from the ffmpegInput URL | | `ipWhitelist`| Enter any IPs inside brackets that you wish to allow to access the video stream. `DISABLE` the default value will turn this feature off. Example: `ipWhitelist="(127.0.0.1)(192.168.0.99)"` | | `ptzContinuous`| If set to false (default) the camera will move using Relative commands, If set to true the camera will instead use continuous movements and will require an `OFF` command to stop the movement. | +| `onvifEventServiceType`| ONVIF event method to use. If camera does not report event capabilities, the event method can be forced here. | +| | `0` - Auto detect event capabilities. (Default) ONVIF event capabilities are detected automatically. PullMessages is prefered over WSBaseNotification because there is no way to determine if an WSBaseNotification subscription exists on startup. | +| | `1` - ONVIF events disabled. | +| | `2` - Force ONVIF PullMessages event method even if the camera does not claim to support this. | +| | `3` - Force ONVIF WSBaseSubscription event method even if the camera does not claim to support this. | ## Channels diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/CameraConfig.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/CameraConfig.java index 3b99af18d21..461a6550d72 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/CameraConfig.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/CameraConfig.java @@ -29,6 +29,7 @@ public class CameraConfig { private String password = ""; public boolean useToken = true; private int onvifMediaProfile; + private int onvifEventServiceType; private int pollTime; private String ffmpegInput = ""; private String snapshotUrl = ""; @@ -54,6 +55,10 @@ public class CameraConfig { return onvifMediaProfile; } + public int getOnvifEventServiceType() { + return onvifEventServiceType; + } + public String getFfmpegInputOptions() { return ffmpegInputOptions; } diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/Helper.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/Helper.java index 4ebad71d336..375a176163b 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/Helper.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/Helper.java @@ -12,6 +12,7 @@ */ package org.openhab.binding.ipcamera.internal; +import java.io.ByteArrayInputStream; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; @@ -19,7 +20,11 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Enumeration; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + import org.eclipse.jdt.annotation.NonNullByDefault; +import org.w3c.dom.Document; /** * The {@link Helper} class has static functions that help the IpCamera binding not need as many external libs. @@ -105,6 +110,13 @@ public class Helper { return result; } + public static Document loadXMLFromString(String xml) throws Exception { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + ByteArrayInputStream inputStream = new ByteArrayInputStream(xml.getBytes()); + return builder.parse(inputStream); + } + /** * The {@link encodeSpecialChars} Is used to replace spaces with %20 in Strings meant for URL queries. * diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/ReolinkHandler.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/ReolinkHandler.java index 73102d69a71..1cf515c98f3 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/ReolinkHandler.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/ReolinkHandler.java @@ -106,7 +106,11 @@ public class ReolinkHandler extends ChannelDuplexHandler { getAbilityResponse[0].error.detail); return; } - ipCameraHandler.reolinkScheduleVersion = getAbilityResponse[0].value.ability.scheduleVersion.ver; + if (getAbilityResponse[0].value.ability.scheduleVersion == null) { + ipCameraHandler.logger.debug("Camera has no Schedule support."); + } else { + ipCameraHandler.reolinkScheduleVersion = getAbilityResponse[0].value.ability.scheduleVersion.ver; + } if (getAbilityResponse[0].value.ability.supportFtpEnable == null || getAbilityResponse[0].value.ability.supportFtpEnable.permit == 0) { ipCameraHandler.logger.debug("Camera has no Enable FTP support."); diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/handler/IpCameraHandler.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/handler/IpCameraHandler.java index 9f28386e925..d8dc52ef51b 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/handler/IpCameraHandler.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/handler/IpCameraHandler.java @@ -61,7 +61,6 @@ import org.openhab.binding.ipcamera.internal.IpCameraDynamicStateDescriptionProv import org.openhab.binding.ipcamera.internal.MyNettyAuthHandler; import org.openhab.binding.ipcamera.internal.ReolinkHandler; import org.openhab.binding.ipcamera.internal.onvif.OnvifConnection; -import org.openhab.binding.ipcamera.internal.onvif.OnvifConnection.RequestType; import org.openhab.binding.ipcamera.internal.servlet.CameraServlet; import org.openhab.core.OpenHAB; import org.openhab.core.library.types.DecimalType; @@ -1577,12 +1576,7 @@ public class IpCameraHandler extends BaseThingHandler { checkCameraConnection(); break; case ONVIF_THING: - onvifCamera.sendOnvifRequest(RequestType.Renew, onvifCamera.subscriptionXAddr); - if (onvifCamera.pullMessageRequests.intValue() == 0) { - logger.info("The alarm stream was not running for ONVIF camera {}, re-starting it now", - cameraConfig.getIp()); - onvifCamera.sendOnvifRequest(RequestType.PullMessages, onvifCamera.subscriptionXAddr); - } + onvifCamera.checkAndRenewEventSubscription(); break; case INSTAR_THING: checkCameraConnection(); @@ -1609,12 +1603,7 @@ public class IpCameraHandler extends BaseThingHandler { sendHttpGET("/api.cgi?cmd=GetAiState&channel=" + cameraConfig.getNvrChannel() + reolinkAuth); sendHttpGET("/api.cgi?cmd=GetMdState&channel=" + cameraConfig.getNvrChannel() + reolinkAuth); } else { - onvifCamera.sendOnvifRequest(RequestType.Renew, onvifCamera.subscriptionXAddr); - if (onvifCamera.pullMessageRequests.intValue() == 0) { - logger.debug("The alarm stream was not running for Reolink camera {}, re-starting it now", - cameraConfig.getIp()); - onvifCamera.sendOnvifRequest(RequestType.PullMessages, onvifCamera.subscriptionXAddr); - } + onvifCamera.checkAndRenewEventSubscription(); } break; case DAHUA_THING: diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/onvif/OnvifCodec.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/onvif/OnvifCodec.java index d208a4fdc6f..7d779c8923e 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/onvif/OnvifCodec.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/onvif/OnvifCodec.java @@ -53,6 +53,10 @@ public class OnvifCodec extends ChannelDuplexHandler { switch (response.status().code()) { case 200: break; + case 400: + onvifConnection.processBadRequest(requestType); + ctx.close(); + return; case 401: if (!response.headers().isEmpty()) { for (CharSequence name : response.headers().names()) { @@ -111,6 +115,7 @@ public class OnvifCodec extends ChannelDuplexHandler { @Override public void handlerRemoved(@Nullable ChannelHandlerContext ctx) { if (requestType == RequestType.PullMessages) { + onvifConnection.lastPullMessageReceivedTimestamp = System.currentTimeMillis(); onvifConnection.pullMessageRequests.decrementAndGet(); } } diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/onvif/OnvifConnection.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/onvif/OnvifConnection.java index 7de06864cea..e5f0005022a 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/onvif/OnvifConnection.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/onvif/OnvifConnection.java @@ -45,6 +45,9 @@ import org.openhab.core.types.StateOption; import org.openhab.core.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; @@ -130,16 +133,18 @@ public class OnvifConnection { @SuppressWarnings("unused") private String imagingXAddr = "http://" + ipAddress + "/onvif/device_service"; private String ptzXAddr = "http://" + ipAddress + "/onvif/ptz_service"; - public String subscriptionXAddr = "http://" + ipAddress + "/onvif/device_service"; + public String subscriptionXAddr = ""; public String subscriptionId = ""; private boolean isConnected = false; private int mediaProfileIndex = 0; private String rtspUri = ""; private IpCameraHandler ipCameraHandler; - private boolean supportsEvents = false; // camera has replied that it can do events // Use/skip events even if camera support them. API cameras skip, as their own methods give better results. private boolean usingEvents = false; + private int onvifEventServiceType = 0; // 0 = disabled, 1 = PullMessages, 2 = WSBaseSubscription public AtomicInteger pullMessageRequests = new AtomicInteger(); + private long createSubscriptionTimestamp; + public long lastPullMessageReceivedTimestamp; // These hold the cameras PTZ position in the range that the camera uses, ie // mine is -1 to +1 @@ -228,7 +233,7 @@ public class OnvifConnection { case GetProfiles: return ""; case GetServiceCapabilities: - return ""; + return ""; case GetSnapshotUri: return "" + mediaProfileTokens.get(mediaProfileIndex) + ""; @@ -238,14 +243,14 @@ public class OnvifConnection { case GetSystemDateAndTime: return ""; case Subscribe: - return "
http://" + return "http://" + ipCameraHandler.hostIp + ":" + SERVLET_PORT + "/ipcamera/" + ipCameraHandler.getThing().getUID().getId() - + "/OnvifEvent
"; + + "/OnvifEventPT600S"; case Unsubscribe: - return ""; + return ""; case PullMessages: - return "PT8S1"; + return "PT8S10"; case GetEventProperties: return ""; case RelativeMoveLeft: @@ -273,7 +278,7 @@ public class OnvifConnection { + mediaProfileTokens.get(mediaProfileIndex) + ""; case Renew: - return "PT10S"; + return "PT600S"; case GetConfigurations: return ""; case GetConfigurationOptions: @@ -314,19 +319,24 @@ public class OnvifConnection { logger.trace("ONVIF {} reply is: {}", requestType, message); switch (requestType) { case CreatePullPointSubscription: - supportsEvents = true; - subscriptionXAddr = Helper.fetchXML(message, "SubscriptionReference>", "Address>"); - int start = message.indexOf(""); - if (start > -1 && end > start) { - subscriptionId = message.substring(start, end + 22); + setSubscriptionXAddr(message); + if (!subscriptionXAddr.isEmpty()) { + sendOnvifRequest(RequestType.PullMessages, subscriptionXAddr); } - logger.debug("subscriptionXAddr={} subscriptionId={}", subscriptionXAddr, subscriptionId); - sendOnvifRequest(RequestType.PullMessages, subscriptionXAddr); + break; + case Subscribe: + setSubscriptionXAddr(message); break; case GetCapabilities: parseXAddr(message); - sendOnvifRequest(RequestType.GetProfiles, mediaXAddr); + setOnvifEventServiceType(message.contains("WSPullPointSupport>true"), + message.contains("WSSubscriptionPolicySupport>true")); + if (!getEventsSupported() && ipCameraHandler.cameraConfig.getOnvifEventServiceType() != 1) { + // If the camera does not report event capabilities here we also check with GetServiceCapabilities. + sendOnvifRequest(RequestType.GetServiceCapabilities, mediaXAddr); + } else { + sendOnvifRequest(RequestType.GetProfiles, mediaXAddr); + } break; case GetDeviceInformation: break; @@ -339,14 +349,13 @@ public class OnvifConnection { sendPTZRequest(RequestType.GetNodes); } if (usingEvents) {// stops API cameras from getting sent ONVIF events. - sendOnvifRequest(RequestType.GetEventProperties, eventXAddr); - sendOnvifRequest(RequestType.GetServiceCapabilities, eventXAddr); + createSubscription(); } break; case GetServiceCapabilities: - if (message.contains("WSSubscriptionPolicySupport=\"true\"")) { - sendOnvifRequest(RequestType.Subscribe, eventXAddr); - } + setOnvifEventServiceType(message.contains("WSPullPointSupport=\"true\""), + message.contains("WSSubscriptionPolicySupport=\"true\"")); + sendOnvifRequest(RequestType.GetProfiles, mediaXAddr); break; case GetSnapshotUri: String url = Helper.fetchXML(message, ":MediaUri", ":Uri"); @@ -378,11 +387,16 @@ public class OnvifConnection { parseDateAndTime(message); break; case PullMessages: - eventRecieved(message); - sendOnvifRequest(RequestType.PullMessages, subscriptionXAddr); + try { + eventRecieved(message); + } catch (Exception e) { + logger.error("Error processing PullMessages error:\n{}\nmessage: {}", e.toString(), message); + } + if (!subscriptionXAddr.isEmpty()) { + sendOnvifRequest(RequestType.PullMessages, subscriptionXAddr); + } break; case GetEventProperties: - sendOnvifRequest(RequestType.CreatePullPointSubscription, eventXAddr); break; case Renew: break; @@ -409,6 +423,108 @@ public class OnvifConnection { } } + private void setOnvifEventServiceType(boolean cameraSupportsPullPointSupport, + boolean cameraSupportsSubscriptionPolicySupport) { + if (cameraSupportsPullPointSupport && ipCameraHandler.cameraConfig.getOnvifEventServiceType() == 0 + || ipCameraHandler.cameraConfig.getOnvifEventServiceType() == 2) { + onvifEventServiceType = 1; + } else if (cameraSupportsSubscriptionPolicySupport + && ipCameraHandler.cameraConfig.getOnvifEventServiceType() == 0 + || ipCameraHandler.cameraConfig.getOnvifEventServiceType() == 3) { + onvifEventServiceType = 2; + } + } + + public void processBadRequest(RequestType requestType) { + logger.trace("ONVIF {} processing bad request for camera {}.", requestType, ipAddress); + switch (requestType) { + case CreatePullPointSubscription: + subscriptionXAddr = ""; + logger.debug("Camera {} returned bad request on CreatePullPointSubscription. Trying again later.", + ipAddress); + break; + case Subscribe: + subscriptionXAddr = ""; + logger.debug("Camera {} returned bad request on WSBaseSubscription. Trying again later.", ipAddress); + break; + case GetServiceCapabilities: + logger.debug( + "Camera {} returned bad request on GetServiceCapabilities. Cannot auto detect supported event types.", + ipAddress); + sendOnvifRequest(RequestType.GetProfiles, mediaXAddr); + break; + case PullMessages: + logger.debug("PullMessages returned bad request for camera {}, re-creating subscription now", + ipAddress); + createSubscription(); + break; + case Renew: + logger.debug("Renew subscription returned bad request for camera {}, re-creating subscription now", + ipAddress); + createSubscription(); + break; + default: + break; + } + } + + void setSubscriptionXAddr(String message) { + subscriptionXAddr = Helper.fetchXML(message, "SubscriptionReference>", "Address>"); + int start = message.indexOf(""); + if (start > -1 && end > start) { + subscriptionId = message.substring(start, end + 22); + } + logger.debug("subscriptionXAddr={} subscriptionId={}", subscriptionXAddr, subscriptionId); + } + + public void createSubscription() { + if (!getEventsSupported()) { + // ONVIF events are disabled or not supported. + return; + } + + // Only send new subscription every 5 seconds if the camera is offline or there are already too much + // subscriptions. + if (createSubscriptionTimestamp == 0) { + createSubscriptionTimestamp = System.currentTimeMillis(); + } else if (System.currentTimeMillis() - createSubscriptionTimestamp < 5000) { + // Subscription sent less than 5 seconds ago. + return; + } + + // Prefer PullPoint events over WSBaseSubscription because there is no way to check if a WSBaseSubscription is + // already registered on the camera. + if (onvifEventServiceType == 1) { + sendOnvifRequest(RequestType.CreatePullPointSubscription, eventXAddr); + } else if (onvifEventServiceType == 2) { + sendOnvifRequest(RequestType.Subscribe, eventXAddr); + } + } + + /** + * This method should be executed regularly to renew the event subscription and to check if a new subscription is + * needed. + */ + public void checkAndRenewEventSubscription() { + if (getEventsSupported()) { + // If we get events via PullMessages check if a PullMessages request is running or we just received an + // answer in the last second. If this is not the case create a new PullMessages subscription. + if (onvifEventServiceType == 1 && pullMessageRequests.intValue() == 0 + && System.currentTimeMillis() - lastPullMessageReceivedTimestamp > 1000) { + logger.debug("The alarm stream was not running for camera {}, re-starting it now", ipAddress); + createSubscription(); + } else if (!subscriptionXAddr.isEmpty()) { + // Renew the active subscription. + sendOnvifRequest(RequestType.Renew, subscriptionXAddr); + } else { + // The camera claims to have event support, but no subscription was created yet. Try to create a new + // subscription. + createSubscription(); + } + } + } + /** * The {@link removeIPandPortFromUrl} Will throw away all text before the cameras IP, also removes the IP and the * PORT @@ -460,7 +576,7 @@ public class OnvifConnection { } temp = Helper.fetchXML(message, " 0; } public void setIsConnected(boolean isConnected) { @@ -1049,7 +1196,8 @@ public class OnvifConnection { connecting.lock();// Lock out multiple disconnect()/connect() attempts as we try to send Unsubscribe. try { if (bootstrap != null) { - if (isConnected && usingEvents && !mainEventLoopGroup.isShuttingDown()) { + if (isConnected && usingEvents && !mainEventLoopGroup.isShuttingDown() + && !subscriptionXAddr.isEmpty()) { // Only makes sense to send if connected // Some cameras may continue to send events even when they can't reach a server. sendOnvifRequest(RequestType.Unsubscribe, subscriptionXAddr); diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/servlet/CameraServlet.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/servlet/CameraServlet.java index f37f4716fe6..af25858beac 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/servlet/CameraServlet.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/servlet/CameraServlet.java @@ -79,7 +79,9 @@ public class CameraServlet extends IpCameraServlet { snapshotData.close(); break; case "/OnvifEvent": - handler.onvifCamera.eventRecieved(req.getReader().toString()); + ServletInputStream inputStream = req.getInputStream(); + String xmlData = new String(inputStream.readAllBytes(), "UTF-8"); + handler.onvifCamera.eventRecieved(xmlData); break; default: logger.debug("Recieved unknown request \tPOST:{}", pathInfo); diff --git a/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/i18n/ipcamera.properties b/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/i18n/ipcamera.properties index 48589cf26f8..c7f520ac534 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/i18n/ipcamera.properties +++ b/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/i18n/ipcamera.properties @@ -526,6 +526,12 @@ thing-type.config.ipcamera.onvif.onvifMediaProfile.label = ONVIF Media Profile thing-type.config.ipcamera.onvif.onvifMediaProfile.description = Cameras can supply more than one stream at different resolutions and formats. 0 selects the main-stream and 1 or above are the sub-streams. Sometimes you need to turn on sub-streams in the cameras setup before they can be used. thing-type.config.ipcamera.onvif.onvifPort.label = ONVIF Port thing-type.config.ipcamera.onvif.onvifPort.description = The port your camera uses for ONVIF connections. This is needed for PTZ movement, alarm events and auto discovery of RTSP and snapshot URLs. +thing-type.config.ipcamera.onvif.onvifEventServiceType.label = ONVIF event method +thing-type.config.ipcamera.onvif.onvifEventServiceType.description = ONVIF event method to use. If camera does not report event capabilities, the event method can be forced here. +thing-type.config.ipcamera.onvif.onvifEventServiceType.option.0 = Auto detect (0) +thing-type.config.ipcamera.onvif.onvifEventServiceType.option.1 = Disabled (1) +thing-type.config.ipcamera.onvif.onvifEventServiceType.option.2 = Force PullMessages (2) +thing-type.config.ipcamera.onvif.onvifEventServiceType.option.3 = Force WSBaseSubscription (3) thing-type.config.ipcamera.onvif.password.label = Password thing-type.config.ipcamera.onvif.password.description = Enter the password for your camera. Leave blank if your camera does not use one. thing-type.config.ipcamera.onvif.pollTime.label = Poll Time @@ -590,6 +596,12 @@ thing-type.config.ipcamera.reolink.onvifMediaProfile.label = ONVIF Media Profile thing-type.config.ipcamera.reolink.onvifMediaProfile.description = Cameras can supply more than one stream at different resolutions and formats. 0 selects the main-stream and 1 or above are the sub-streams. Sometimes you need to turn on sub-streams in the cameras setup before they can be used. thing-type.config.ipcamera.reolink.onvifPort.label = ONVIF Port thing-type.config.ipcamera.reolink.onvifPort.description = The port your camera uses for ONVIF connections. This is needed for PTZ movement, alarm events and auto discovery of RTSP and snapshot URLs. +thing-type.config.ipcamera.reolink.onvifEventServiceType.label = ONVIF event method +thing-type.config.ipcamera.reolink.onvifEventServiceType.description = ONVIF event method to use. If camera does not report event capabilities, the event method can be forced here. +thing-type.config.ipcamera.reolink.onvifEventServiceType.option.0 = Auto detect (0) +thing-type.config.ipcamera.reolink.onvifEventServiceType.option.1 = Disabled (1) +thing-type.config.ipcamera.reolink.onvifEventServiceType.option.2 = Force PullMessages (2) +thing-type.config.ipcamera.reolink.onvifEventServiceType.option.3 = Force WSBaseSubscription (3) thing-type.config.ipcamera.reolink.password.label = Password thing-type.config.ipcamera.reolink.password.description = Enter the password for your camera. Leave blank if your camera does not use one. thing-type.config.ipcamera.reolink.pollTime.label = Poll Time diff --git a/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/thing/thing-types.xml index 6d3ecac91e9..1a5551cc5e5 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/thing/thing-types.xml @@ -548,6 +548,21 @@ 0 + + + ONVIF event method to use. If camera does not report event capabilities, the event method can be forced + here. + + 0 + true + + + + + + + + Enter any IP's inside (brackets) that you wish to allow to access the video stream. 'DISABLE' will @@ -2572,6 +2587,21 @@ 0 + + + ONVIF event method to use. If camera does not report event capabilities, the event method can be forced + here. + + 0 + true + + + + + + + + Most features are made on demand and not polled, but some features require a regular snapshot to work.