diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/HikvisionHandler.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/HikvisionHandler.java index 69cf11f70a85..fc48f9395886 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/HikvisionHandler.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/HikvisionHandler.java @@ -15,6 +15,8 @@ import static org.openhab.binding.ipcamera.internal.IpCameraBindingConstants.*; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -53,6 +55,7 @@ public class HikvisionHandler extends ChannelDuplexHandler { private IpCameraHandler ipCameraHandler; private int nvrChannel; private int lineCount, vmdCount, leftCount, takenCount, faceCount, pirCount, fieldCount; + private String requestUrl = ""; public HikvisionHandler(ThingHandler handler, int nvrChannel) { ipCameraHandler = (IpCameraHandler) handler; @@ -110,6 +113,10 @@ private void processEvent(String content) { countDown(); } + public void setURL(String url) { + requestUrl = url; + } + // This handles the incoming http replies back from the camera. @Override public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object msg) throws Exception { @@ -118,90 +125,145 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms } try { String content = msg.toString(); - logger.trace("HTTP Result back from camera is \t:{}:", content); - if (content.startsWith("--boundary")) {// Alarm checking goes in here// - int startIndex = content.indexOf("<");// skip to start of XML content - if (startIndex != -1) { - String eventData = content.substring(startIndex, content.length()); - processEvent(eventData); - } - } else { - String replyElement = Helper.fetchXML(content, "", "<"); - switch (replyElement) { - case "MotionDetection version=": - ipCameraHandler.storeHttpReply( - "/ISAPI/System/Video/inputs/channels/" + nvrChannel + "01/motionDetection", content); - if (content.contains("true")) { - ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON); - } else if (content.contains("false")) { - ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.OFF); + logger.trace("HTTP Result from {} contains \t:{}:", requestUrl, content); + switch (requestUrl) { + case "/ISAPI/Event/notification/alertStream": + int startIndex = content.indexOf("<");// skip to start of XML content + if (startIndex != -1) { + String eventData = content.substring(startIndex, content.length()); + processEvent(eventData); + } + return; + case "/ISAPI/System/IO/capabilities": // Used to check if the camera supports IO + List removeChannels = new ArrayList<>(); + org.openhab.core.thing.Channel channel; + if (content.contains("0<") || !content.contains("")) { + logger.debug("Camera does not support IO outputs."); + channel = ipCameraHandler.getThing().getChannel(CHANNEL_ACTIVATE_ALARM_OUTPUT); + if (channel != null) { + removeChannels.add(channel); } - break; - case "IOInputPort version=": - ipCameraHandler.storeHttpReply("/ISAPI/System/IO/inputs/" + nvrChannel, content); - if (content.contains("true")) { - ipCameraHandler.setChannelState(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT, OnOffType.ON); - } else if (content.contains("false")) { - ipCameraHandler.setChannelState(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT, OnOffType.OFF); + channel = ipCameraHandler.getThing().getChannel(CHANNEL_ACTIVATE_ALARM_OUTPUT2); + if (channel != null) { + removeChannels.add(channel); } - if (content.contains("low")) { - ipCameraHandler.setChannelState(CHANNEL_TRIGGER_EXTERNAL_ALARM_INPUT, OnOffType.OFF); - } else if (content.contains("high")) { - ipCameraHandler.setChannelState(CHANNEL_TRIGGER_EXTERNAL_ALARM_INPUT, OnOffType.ON); + } else if (content.contains("1<")) { + channel = ipCameraHandler.getThing().getChannel(CHANNEL_ACTIVATE_ALARM_OUTPUT2); + if (channel != null) { + removeChannels.add(channel); } - break; - case "LineDetection": - ipCameraHandler.storeHttpReply("/ISAPI/Smart/LineDetection/" + nvrChannel + "01", content); - if (content.contains("true")) { - ipCameraHandler.setChannelState(CHANNEL_ENABLE_LINE_CROSSING_ALARM, OnOffType.ON); - } else if (content.contains("false")) { - ipCameraHandler.setChannelState(CHANNEL_ENABLE_LINE_CROSSING_ALARM, OnOffType.OFF); + } + ipCameraHandler.lowPriorityRequests.clear(); // no longer need to check if the IO is supported. + if (content.contains("0<") || !content.contains("")) { + logger.debug("Camera does not support IO inputs."); + channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT); + if (channel != null) { + removeChannels.add(channel); } - break; - case "TextOverlay version=": - ipCameraHandler.storeHttpReply( - "/ISAPI/System/Video/inputs/channels/" + nvrChannel + "/overlays/text/1", content); - String text = Helper.fetchXML(content, "true", ""); - ipCameraHandler.setChannelState(CHANNEL_TEXT_OVERLAY, StringType.valueOf(text)); - break; - case "AudioDetection version=": - ipCameraHandler.storeHttpReply("/ISAPI/Smart/AudioDetection/channels/" + nvrChannel + "01", - content); - if (content.contains("true")) { - ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON); - } else if (content.contains("false")) { - ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.OFF); + channel = ipCameraHandler.getThing().getChannel(CHANNEL_TRIGGER_EXTERNAL_ALARM_INPUT); + if (channel != null) { + removeChannels.add(channel); } - break; - case "IOPortStatus version=": - if (content.contains("active")) { - ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT, OnOffType.ON); - } else if (content.contains("inactive")) { - ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT, OnOffType.OFF); + channel = ipCameraHandler.getThing().getChannel(CHANNEL_EXTERNAL_ALARM_INPUT); + if (channel != null) { + removeChannels.add(channel); } - break; - case "FieldDetection version=": - ipCameraHandler.storeHttpReply("/ISAPI/Smart/FieldDetection/" + nvrChannel + "01", content); - if (content.contains("true")) { - ipCameraHandler.setChannelState(CHANNEL_ENABLE_FIELD_DETECTION_ALARM, OnOffType.ON); - } else if (content.contains("false")) { - ipCameraHandler.setChannelState(CHANNEL_ENABLE_FIELD_DETECTION_ALARM, OnOffType.OFF); + channel = ipCameraHandler.getThing().getChannel(CHANNEL_EXTERNAL_ALARM_INPUT2); + if (channel != null) { + removeChannels.add(channel); } - break; - case "ResponseStatus version=": - ////////////////// External Alarm Input /////////////// - if (content.contains( - "/ISAPI/System/IO/inputs/" + nvrChannel + "/status")) { - // Stops checking the external alarm if camera does not have feature. - if (content.contains("Invalid Operation")) { - ipCameraHandler.lowPriorityRequests.remove(0); - ipCameraHandler.logger.debug( - "Stopping checks for alarm inputs as camera appears to be missing this feature."); - } + } else if (content.contains("1<")) { + channel = ipCameraHandler.getThing().getChannel(CHANNEL_EXTERNAL_ALARM_INPUT2); + if (channel != null) { + removeChannels.add(channel); } - break; - } + // start checking the input IO status + ipCameraHandler.lowPriorityRequests.set(0, + "/ISAPI/System/IO/inputs/" + ipCameraHandler.cameraConfig.getNvrChannel() + "/status"); + } else { + // start checking the input IO status + ipCameraHandler.lowPriorityRequests.set(0, + "/ISAPI/System/IO/inputs/" + ipCameraHandler.cameraConfig.getNvrChannel() + "/status"); + } + ipCameraHandler.removeChannels(removeChannels); + return; + } + String replyElement = Helper.fetchXML(content, "", "<"); + switch (replyElement) { + case "MotionDetection version=": + ipCameraHandler.storeHttpReply( + "/ISAPI/System/Video/inputs/channels/" + nvrChannel + "01/motionDetection", content); + if (content.contains("true")) { + ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON); + } else if (content.contains("false")) { + ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.OFF); + } + break; + case "IOInputPort version=": + ipCameraHandler.storeHttpReply("/ISAPI/System/IO/inputs/" + nvrChannel, content); + if (content.contains("true")) { + ipCameraHandler.setChannelState(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT, OnOffType.ON); + } else if (content.contains("false")) { + ipCameraHandler.setChannelState(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT, OnOffType.OFF); + } + if (content.contains("low")) { + ipCameraHandler.setChannelState(CHANNEL_TRIGGER_EXTERNAL_ALARM_INPUT, OnOffType.OFF); + } else if (content.contains("high")) { + ipCameraHandler.setChannelState(CHANNEL_TRIGGER_EXTERNAL_ALARM_INPUT, OnOffType.ON); + } + break; + case "LineDetection": + ipCameraHandler.storeHttpReply("/ISAPI/Smart/LineDetection/" + nvrChannel + "01", content); + if (content.contains("true")) { + ipCameraHandler.setChannelState(CHANNEL_ENABLE_LINE_CROSSING_ALARM, OnOffType.ON); + } else if (content.contains("false")) { + ipCameraHandler.setChannelState(CHANNEL_ENABLE_LINE_CROSSING_ALARM, OnOffType.OFF); + } + break; + case "TextOverlay version=": + ipCameraHandler.storeHttpReply( + "/ISAPI/System/Video/inputs/channels/" + nvrChannel + "/overlays/text/1", content); + String text = Helper.fetchXML(content, "true", ""); + ipCameraHandler.setChannelState(CHANNEL_TEXT_OVERLAY, StringType.valueOf(text)); + break; + case "AudioDetection version=": + ipCameraHandler.storeHttpReply("/ISAPI/Smart/AudioDetection/channels/" + nvrChannel + "01", + content); + if (content.contains("true")) { + ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON); + } else if (content.contains("false")) { + ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.OFF); + } + break; + case "IOPortStatus version=": + if (content.contains("active")) { + ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT, OnOffType.ON); + } else if (content.contains("inactive")) { + ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT, OnOffType.OFF); + } + break; + case "FieldDetection version=": + ipCameraHandler.storeHttpReply("/ISAPI/Smart/FieldDetection/" + nvrChannel + "01", content); + if (content.contains("true")) { + ipCameraHandler.setChannelState(CHANNEL_ENABLE_FIELD_DETECTION_ALARM, OnOffType.ON); + } else if (content.contains("false")) { + ipCameraHandler.setChannelState(CHANNEL_ENABLE_FIELD_DETECTION_ALARM, OnOffType.OFF); + } + break; + case "ResponseStatus version=": + ////////////////// External Alarm Input /////////////// + if (content + .contains("/ISAPI/System/IO/inputs/" + nvrChannel + "/status")) { + // Stops checking the external alarm if camera does not have feature. + if (content.contains("Invalid Operation")) { + ipCameraHandler.lowPriorityRequests.remove(0); + ipCameraHandler.logger.debug( + "Stopping checks for alarm inputs as camera appears to be missing this feature."); + } + } + break; } + } finally { ReferenceCountUtil.release(msg); } diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/IpCameraBindingConstants.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/IpCameraBindingConstants.java index 4d9d96fd21aa..0c3f5f2ab705 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/IpCameraBindingConstants.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/IpCameraBindingConstants.java @@ -34,6 +34,7 @@ public class IpCameraBindingConstants { public static final String COMMON_HANDLER = "commonHandler"; public static final String INSTAR_HANDLER = "instarHandler"; public static final String REOLINK_HANDLER = "reolinkHandler"; + public static final String HIKVISION_HANDLER = "hikvisionHandler"; public enum FFmpegFormat { HLS, 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 e43c05f09aac..a973dfd651c3 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 @@ -583,8 +583,8 @@ public void initChannel(SocketChannel socketChannel) throws Exception { new FoscamHandler(getHandle(), cameraConfig.getUser(), cameraConfig.getPassword())); break; case HIKVISION_THING: - socketChannel.pipeline() - .addLast(new HikvisionHandler(getHandle(), cameraConfig.getNvrChannel())); + socketChannel.pipeline().addLast(HIKVISION_HANDLER, + new HikvisionHandler(getHandle(), cameraConfig.getNvrChannel())); break; case INSTAR_THING: socketChannel.pipeline().addLast(INSTAR_HANDLER, new InstarHandler(getHandle())); @@ -654,6 +654,11 @@ public void operationComplete(@Nullable ChannelFuture future) { AmcrestHandler amcrestHandler = (AmcrestHandler) ch.pipeline().get(AMCREST_HANDLER); amcrestHandler.setURL(httpRequestURL); break; + case HIKVISION_THING: + HikvisionHandler hikvisionHandler = (HikvisionHandler) ch.pipeline() + .get(HIKVISION_HANDLER); + hikvisionHandler.setURL(httpRequestURL); + break; case INSTAR_THING: InstarHandler instarHandler = (InstarHandler) ch.pipeline().get(INSTAR_HANDLER); instarHandler.setURL(httpRequestURL); @@ -1701,7 +1706,7 @@ public void initialize() { snapshotUri = "/ISAPI/Streaming/channels/" + cameraConfig.getNvrChannel() + "01/picture"; } if (lowPriorityRequests.isEmpty()) { - lowPriorityRequests.add("/ISAPI/System/IO/inputs/" + cameraConfig.getNvrChannel() + "/status"); + lowPriorityRequests.add("/ISAPI/System/IO/capabilities"); } break; case INSTAR_THING: