]> git.basschouten.com Git - openhab-addons.git/commitdiff
[ipcamera] Improve Hikvision alarm reliability (#10319)
authorMatthew Skinner <matt@pcmus.com>
Mon, 15 Mar 2021 22:58:11 +0000 (09:58 +1100)
committerGitHub <noreply@github.com>
Mon, 15 Mar 2021 22:58:11 +0000 (23:58 +0100)
Signed-off-by: Matthew Skinner <matt@pcmus.com>
bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/HikvisionHandler.java
bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/handler/IpCameraHandler.java

index d99920f865c1815eaa9dcbebaca567d9d1a5e93e..a2e86da0677c20a416f90be304a26d02b7046b88 100644 (file)
@@ -60,6 +60,56 @@ public class HikvisionHandler extends ChannelDuplexHandler {
         this.nvrChannel = nvrChannel;
     }
 
+    private void processEvent(String content) {
+        // some cameras use <dynChannelID> or <channelID> and NVRs use channel 0 to say all channels
+        if (content.contains("hannelID>" + nvrChannel) || content.contains("<channelID>0</channelID>")) {
+            final int debounce = 3;
+            String eventType = Helper.fetchXML(content, "", "<eventType>");
+            switch (eventType) {
+                case "videoloss":
+                    if (content.contains("<eventState>inactive</eventState>")) {
+                        if (vmdCount > 1) {
+                            vmdCount = 1;
+                        }
+                        countDown();
+                        countDown();
+                    }
+                    break;
+                case "PIR":
+                    ipCameraHandler.motionDetected(CHANNEL_PIR_ALARM);
+                    pirCount = debounce;
+                    break;
+                case "attendedBaggage":
+                    ipCameraHandler.setChannelState(CHANNEL_ITEM_TAKEN, OnOffType.ON);
+                    takenCount = debounce;
+                    break;
+                case "unattendedBaggage":
+                    ipCameraHandler.setChannelState(CHANNEL_ITEM_LEFT, OnOffType.ON);
+                    leftCount = debounce;
+                    break;
+                case "facedetection":
+                    ipCameraHandler.setChannelState(CHANNEL_FACE_DETECTED, OnOffType.ON);
+                    faceCount = debounce;
+                    break;
+                case "VMD":
+                    ipCameraHandler.motionDetected(CHANNEL_MOTION_ALARM);
+                    vmdCount = debounce;
+                    break;
+                case "fielddetection":
+                    ipCameraHandler.motionDetected(CHANNEL_FIELD_DETECTION_ALARM);
+                    fieldCount = debounce;
+                    break;
+                case "linedetection":
+                    ipCameraHandler.motionDetected(CHANNEL_LINE_CROSSING_ALARM);
+                    lineCount = debounce;
+                    break;
+                default:
+                    logger.debug("Unrecognised Hikvision eventType={}", eventType);
+            }
+        }
+        countDown();
+    }
+
     // This handles the incoming http replies back from the camera.
     @Override
     public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object msg) throws Exception {
@@ -67,59 +117,10 @@ public class HikvisionHandler extends ChannelDuplexHandler {
             return;
         }
         try {
-            int debounce = 3;
             String content = msg.toString();
             logger.trace("HTTP Result back from camera is \t:{}:", content);
-            if (content.contains("--boundary")) {// Alarm checking goes in here//
-                if (content.contains("<EventNotificationAlert version=\"")) {
-                    if (content.contains("hannelID>" + nvrChannel + "</")) {// some camera use c or <dynChannelID>
-                        if (content.contains("<eventType>linedetection</eventType>")) {
-                            ipCameraHandler.motionDetected(CHANNEL_LINE_CROSSING_ALARM);
-                            lineCount = debounce;
-                        }
-                        if (content.contains("<eventType>fielddetection</eventType>")) {
-                            ipCameraHandler.motionDetected(CHANNEL_FIELD_DETECTION_ALARM);
-                            fieldCount = debounce;
-                        }
-                        if (content.contains("<eventType>VMD</eventType>")) {
-                            ipCameraHandler.motionDetected(CHANNEL_MOTION_ALARM);
-                            vmdCount = debounce;
-                        }
-                        if (content.contains("<eventType>facedetection</eventType>")) {
-                            ipCameraHandler.setChannelState(CHANNEL_FACE_DETECTED, OnOffType.ON);
-                            faceCount = debounce;
-                        }
-                        if (content.contains("<eventType>unattendedBaggage</eventType>")) {
-                            ipCameraHandler.setChannelState(CHANNEL_ITEM_LEFT, OnOffType.ON);
-                            leftCount = debounce;
-                        }
-                        if (content.contains("<eventType>attendedBaggage</eventType>")) {
-                            ipCameraHandler.setChannelState(CHANNEL_ITEM_TAKEN, OnOffType.ON);
-                            takenCount = debounce;
-                        }
-                        if (content.contains("<eventType>PIR</eventType>")) {
-                            ipCameraHandler.motionDetected(CHANNEL_PIR_ALARM);
-                            pirCount = debounce;
-                        }
-                        if (content.contains("<eventType>videoloss</eventType>\r\n<eventState>inactive</eventState>")) {
-                            if (vmdCount > 1) {
-                                vmdCount = 1;
-                            }
-                            countDown();
-                            countDown();
-                        }
-                    } else if (content.contains("<channelID>0</channelID>")) {// NVR uses channel 0 to say all
-                                                                              // channels
-                        if (content.contains("<eventType>videoloss</eventType>\r\n<eventState>inactive</eventState>")) {
-                            if (vmdCount > 1) {
-                                vmdCount = 1;
-                            }
-                            countDown();
-                            countDown();
-                        }
-                    }
-                    countDown();
-                }
+            if (content.startsWith("--boundary")) {// Alarm checking goes in here//
+                processEvent(content);
             } else {
                 String replyElement = Helper.fetchXML(content, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "<");
                 switch (replyElement) {
@@ -196,23 +197,7 @@ public class HikvisionHandler extends ChannelDuplexHandler {
                         }
                         break;
                     default:
-                        if (content.contains("<EventNotificationAlert")) {
-                            if (content.contains("hannelID>" + nvrChannel + "</")
-                                    || content.contains("<channelID>0</channelID>")) {// some camera use c or
-                                                                                      // <dynChannelID>
-                                if (content.contains(
-                                        "<eventType>videoloss</eventType>\r\n<eventState>inactive</eventState>")) {
-                                    if (vmdCount > 1) {
-                                        vmdCount = 1;
-                                    }
-                                    countDown();
-                                    countDown();
-                                }
-                                countDown();
-                            }
-                        } else {
-                            logger.debug("Unhandled reply-{}.", content);
-                        }
+                        logger.debug("Unhandled reply-{}.", content);
                         break;
                 }
             }
index 09a59477f3d1b693b206e1a7e6a1ecce7db6b8ad..9e0c93215cc021aea0c5e30528fd68c7018961ff 100644 (file)
@@ -206,6 +206,7 @@ public class IpCameraHandler extends BaseThingHandler {
         private byte[] incomingJpeg = new byte[0];
         private String incomingMessage = "";
         private String contentType = "empty";
+        private String boundary = "";
         private Object reply = new Object();
         private String requestUrl = "";
         private boolean closeConnection = true;
@@ -255,6 +256,8 @@ public class IpCameraHandler extends BaseThingHandler {
                                         firstStreamedMsg = msg;
                                         streamToGroup(firstStreamedMsg, mjpegChannelGroup, true);
                                     }
+                                } else {
+                                    boundary = Helper.searchString(contentType, "boundary=");
                                 }
                             } else if (contentType.contains("image/jp")) {
                                 if (bytesToRecieve == 0) {
@@ -305,11 +308,32 @@ public class IpCameraHandler extends BaseThingHandler {
                             }
                             // Alarm Streams never have a LastHttpContent as they always stay open//
                             else if (contentType.contains("multipart")) {
-                                if (bytesAlreadyRecieved != 0) {
-                                    reply = incomingMessage;
-                                    incomingMessage = "";
-                                    bytesToRecieve = 0;
-                                    bytesAlreadyRecieved = 0;
+                                int beginIndex, endIndex;
+                                if (bytesToRecieve == 0) {
+                                    beginIndex = incomingMessage.indexOf("Content-Length:");
+                                    if (beginIndex != -1) {
+                                        endIndex = incomingMessage.indexOf("\r\n", beginIndex);
+                                        if (endIndex != -1) {
+                                            bytesToRecieve = Integer.parseInt(
+                                                    incomingMessage.substring(beginIndex + 15, endIndex).strip());
+                                        }
+                                    }
+                                }
+                                // --boundary and headers are not included in the Content-Length value
+                                if (bytesAlreadyRecieved > bytesToRecieve) {
+                                    // Check if message has a second --boundary
+                                    endIndex = incomingMessage.indexOf("--" + boundary, bytesToRecieve);
+                                    if (endIndex == -1) {
+                                        reply = incomingMessage;
+                                        incomingMessage = "";
+                                        bytesToRecieve = 0;
+                                        bytesAlreadyRecieved = 0;
+                                    } else {
+                                        reply = incomingMessage.substring(0, endIndex);
+                                        incomingMessage = incomingMessage.substring(endIndex, incomingMessage.length());
+                                        bytesToRecieve = 0;// Triggers search next time for Content-Length:
+                                        bytesAlreadyRecieved = incomingMessage.length() - endIndex;
+                                    }
                                     super.channelRead(ctx, reply);
                                 }
                             }
@@ -1411,7 +1435,7 @@ public class IpCameraHandler extends BaseThingHandler {
         updateState(channelToUpdate, valueOf);
     }
 
-    void bringCameraOnline() {
+    private void bringCameraOnline() {
         isOnline = true;
         updateStatus(ThingStatus.ONLINE);
         groupTracker.listOfOnlineCameraHandlers.add(this);
@@ -1421,19 +1445,6 @@ public class IpCameraHandler extends BaseThingHandler {
             localFuture.cancel(false);
         }
 
-        switch (thing.getThingTypeUID().getId()) {
-            case HIKVISION_THING:
-                sendHttpGET("/ISAPI/Smart/AudioDetection/channels/" + cameraConfig.getNvrChannel() + "01");
-                sendHttpGET("/ISAPI/Smart/LineDetection/" + cameraConfig.getNvrChannel() + "01");
-                sendHttpGET("/ISAPI/Smart/FieldDetection/" + cameraConfig.getNvrChannel() + "01");
-                sendHttpGET(
-                        "/ISAPI/System/Video/inputs/channels/" + cameraConfig.getNvrChannel() + "01/motionDetection");
-                sendHttpGET("/ISAPI/System/Video/inputs/channels/" + cameraConfig.getNvrChannel() + "/overlays/text/1");
-                sendHttpGET("/ISAPI/System/IO/inputs/" + cameraConfig.getNvrChannel());
-                sendHttpGET("/ISAPI/System/IO/inputs/" + cameraConfig.getNvrChannel());
-                break;
-        }
-
         if (cameraConfig.getGifPreroll() > 0 || cameraConfig.getUpdateImageWhen().contains("1")) {
             snapshotPolling = true;
             snapshotJob = threadPool.scheduleWithFixedDelay(this::snapshotRunnable, 1000, cameraConfig.getPollTime(),