mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[ipcamera] Improve Hikvision alarm reliability (#10319)
Signed-off-by: Matthew Skinner <matt@pcmus.com>
This commit is contained in:
parent
04da89cc4f
commit
16fba31556
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
|
Loading…
Reference in New Issue
Block a user