Skip to content

Commit

Permalink
Remove channels and checking IO status when camera does not support IO
Browse files Browse the repository at this point in the history
Signed-off-by: Matthew Skinner <matt@pcmus.com>
  • Loading branch information
Skinah committed Dec 19, 2023
1 parent 6763100 commit 28d22af
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 78 deletions.
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -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, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "<");
switch (replyElement) {
case "MotionDetection version=":
ipCameraHandler.storeHttpReply(
"/ISAPI/System/Video/inputs/channels/" + nvrChannel + "01/motionDetection", content);
if (content.contains("<enabled>true</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON);
} else if (content.contains("<enabled>false</enabled>")) {
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<org.openhab.core.thing.Channel> removeChannels = new ArrayList<>();
org.openhab.core.thing.Channel channel;
if (content.contains("<IOOutputPortNums>0<") || !content.contains("<IOOutputPortNums>")) {
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("<enabled>true</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT, OnOffType.ON);
} else if (content.contains("<enabled>false</enabled>")) {
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("<triggering>low</triggering>")) {
ipCameraHandler.setChannelState(CHANNEL_TRIGGER_EXTERNAL_ALARM_INPUT, OnOffType.OFF);
} else if (content.contains("<triggering>high</triggering>")) {
ipCameraHandler.setChannelState(CHANNEL_TRIGGER_EXTERNAL_ALARM_INPUT, OnOffType.ON);
} else if (content.contains("<IOOutputPortNums>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("<enabled>true</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_LINE_CROSSING_ALARM, OnOffType.ON);
} else if (content.contains("<enabled>false</enabled>")) {
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("<IOInputPortNums>0<") || !content.contains("<IOInputPortNums>")) {
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, "<enabled>true</enabled>", "<displayText>");
ipCameraHandler.setChannelState(CHANNEL_TEXT_OVERLAY, StringType.valueOf(text));
break;
case "AudioDetection version=":
ipCameraHandler.storeHttpReply("/ISAPI/Smart/AudioDetection/channels/" + nvrChannel + "01",
content);
if (content.contains("<enabled>true</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON);
} else if (content.contains("<enabled>false</enabled>")) {
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("<ioState>active</ioState>")) {
ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT, OnOffType.ON);
} else if (content.contains("<ioState>inactive</ioState>")) {
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("<enabled>true</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_FIELD_DETECTION_ALARM, OnOffType.ON);
} else if (content.contains("<enabled>false</enabled>")) {
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(
"<requestURL>/ISAPI/System/IO/inputs/" + nvrChannel + "/status</requestURL>")) {
// Stops checking the external alarm if camera does not have feature.
if (content.contains("<statusString>Invalid Operation</statusString>")) {
ipCameraHandler.lowPriorityRequests.remove(0);
ipCameraHandler.logger.debug(
"Stopping checks for alarm inputs as camera appears to be missing this feature.");
}
} else if (content.contains("<IOInputPortNums>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, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "<");
switch (replyElement) {
case "MotionDetection version=":
ipCameraHandler.storeHttpReply(
"/ISAPI/System/Video/inputs/channels/" + nvrChannel + "01/motionDetection", content);
if (content.contains("<enabled>true</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON);
} else if (content.contains("<enabled>false</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.OFF);
}
break;
case "IOInputPort version=":
ipCameraHandler.storeHttpReply("/ISAPI/System/IO/inputs/" + nvrChannel, content);
if (content.contains("<enabled>true</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT, OnOffType.ON);
} else if (content.contains("<enabled>false</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT, OnOffType.OFF);
}
if (content.contains("<triggering>low</triggering>")) {
ipCameraHandler.setChannelState(CHANNEL_TRIGGER_EXTERNAL_ALARM_INPUT, OnOffType.OFF);
} else if (content.contains("<triggering>high</triggering>")) {
ipCameraHandler.setChannelState(CHANNEL_TRIGGER_EXTERNAL_ALARM_INPUT, OnOffType.ON);
}
break;
case "LineDetection":
ipCameraHandler.storeHttpReply("/ISAPI/Smart/LineDetection/" + nvrChannel + "01", content);
if (content.contains("<enabled>true</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_LINE_CROSSING_ALARM, OnOffType.ON);
} else if (content.contains("<enabled>false</enabled>")) {
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, "<enabled>true</enabled>", "<displayText>");
ipCameraHandler.setChannelState(CHANNEL_TEXT_OVERLAY, StringType.valueOf(text));
break;
case "AudioDetection version=":
ipCameraHandler.storeHttpReply("/ISAPI/Smart/AudioDetection/channels/" + nvrChannel + "01",
content);
if (content.contains("<enabled>true</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON);
} else if (content.contains("<enabled>false</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.OFF);
}
break;
case "IOPortStatus version=":
if (content.contains("<ioState>active</ioState>")) {
ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT, OnOffType.ON);
} else if (content.contains("<ioState>inactive</ioState>")) {
ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT, OnOffType.OFF);
}
break;
case "FieldDetection version=":
ipCameraHandler.storeHttpReply("/ISAPI/Smart/FieldDetection/" + nvrChannel + "01", content);
if (content.contains("<enabled>true</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_FIELD_DETECTION_ALARM, OnOffType.ON);
} else if (content.contains("<enabled>false</enabled>")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_FIELD_DETECTION_ALARM, OnOffType.OFF);
}
break;
case "ResponseStatus version=":
////////////////// External Alarm Input ///////////////
if (content
.contains("<requestURL>/ISAPI/System/IO/inputs/" + nvrChannel + "/status</requestURL>")) {
// Stops checking the external alarm if camera does not have feature.
if (content.contains("<statusString>Invalid Operation</statusString>")) {
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);
}
Expand Down
Expand Up @@ -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,
Expand Down
Expand Up @@ -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()));
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit 28d22af

Please sign in to comment.