mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[ipcamera] Fix ONVIF alarms streams may stop and not restart on some cameras. (#16777)
* Fault find stream Signed-off-by: Matthew Skinner <matt@pcmus.com> Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
parent
8895be2850
commit
38f2751512
@ -178,11 +178,11 @@ public class HikvisionHandler extends ChannelDuplexHandler {
|
|||||||
removeChannels.add(channel);
|
removeChannels.add(channel);
|
||||||
}
|
}
|
||||||
// start checking the input IO status
|
// start checking the input IO status
|
||||||
ipCameraHandler.lowPriorityRequests.set(0,
|
ipCameraHandler.lowPriorityRequests.add(0,
|
||||||
"/ISAPI/System/IO/inputs/" + ipCameraHandler.cameraConfig.getNvrChannel() + "/status");
|
"/ISAPI/System/IO/inputs/" + ipCameraHandler.cameraConfig.getNvrChannel() + "/status");
|
||||||
} else {
|
} else {
|
||||||
// start checking the input IO status
|
// start checking the input IO status
|
||||||
ipCameraHandler.lowPriorityRequests.set(0,
|
ipCameraHandler.lowPriorityRequests.add(0,
|
||||||
"/ISAPI/System/IO/inputs/" + ipCameraHandler.cameraConfig.getNvrChannel() + "/status");
|
"/ISAPI/System/IO/inputs/" + ipCameraHandler.cameraConfig.getNvrChannel() + "/status");
|
||||||
}
|
}
|
||||||
ipCameraHandler.removeChannels(removeChannels);
|
ipCameraHandler.removeChannels(removeChannels);
|
||||||
|
@ -61,6 +61,7 @@ import org.openhab.binding.ipcamera.internal.IpCameraDynamicStateDescriptionProv
|
|||||||
import org.openhab.binding.ipcamera.internal.MyNettyAuthHandler;
|
import org.openhab.binding.ipcamera.internal.MyNettyAuthHandler;
|
||||||
import org.openhab.binding.ipcamera.internal.ReolinkHandler;
|
import org.openhab.binding.ipcamera.internal.ReolinkHandler;
|
||||||
import org.openhab.binding.ipcamera.internal.onvif.OnvifConnection;
|
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.binding.ipcamera.internal.servlet.CameraServlet;
|
||||||
import org.openhab.core.OpenHAB;
|
import org.openhab.core.OpenHAB;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
@ -1556,19 +1557,13 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
// what needs to be done every poll//
|
// what needs to be done every poll//
|
||||||
switch (thing.getThingTypeUID().getId()) {
|
switch (thing.getThingTypeUID().getId()) {
|
||||||
case GENERIC_THING:
|
case GENERIC_THING:
|
||||||
if (!snapshotPolling) {
|
checkCameraConnection();
|
||||||
checkCameraConnection();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ONVIF_THING:
|
case ONVIF_THING:
|
||||||
if (!snapshotPolling) {
|
onvifCamera.sendOnvifRequest(RequestType.Renew, onvifCamera.subscriptionXAddr);
|
||||||
checkCameraConnection();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case INSTAR_THING:
|
case INSTAR_THING:
|
||||||
if (!snapshotPolling) {
|
checkCameraConnection();
|
||||||
checkCameraConnection();
|
|
||||||
}
|
|
||||||
noMotionDetected(CHANNEL_MOTION_ALARM);
|
noMotionDetected(CHANNEL_MOTION_ALARM);
|
||||||
noMotionDetected(CHANNEL_PIR_ALARM);
|
noMotionDetected(CHANNEL_PIR_ALARM);
|
||||||
noMotionDetected(CHANNEL_HUMAN_ALARM);
|
noMotionDetected(CHANNEL_HUMAN_ALARM);
|
||||||
@ -1588,19 +1583,14 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
sendHttpGET("/cgi-bin/eventManager.cgi?action=getEventIndexes&code=AudioMutation");
|
sendHttpGET("/cgi-bin/eventManager.cgi?action=getEventIndexes&code=AudioMutation");
|
||||||
break;
|
break;
|
||||||
case REOLINK_THING:
|
case REOLINK_THING:
|
||||||
if (cameraConfig.getNvrChannel() > 0) {
|
if (cameraConfig.getOnvifPort() == 0) {
|
||||||
sendHttpGET("/api.cgi?cmd=GetAiState&channel=" + cameraConfig.getNvrChannel() + "&user="
|
sendHttpGET("/api.cgi?cmd=GetAiState&channel=" + cameraConfig.getNvrChannel() + reolinkAuth);
|
||||||
+ cameraConfig.getUser() + "&password=" + cameraConfig.getPassword());
|
sendHttpGET("/api.cgi?cmd=GetMdState&channel=" + cameraConfig.getNvrChannel() + reolinkAuth);
|
||||||
sendHttpGET("/api.cgi?cmd=GetMdState&channel=" + cameraConfig.getNvrChannel() + "&user="
|
} else {
|
||||||
+ cameraConfig.getUser() + "&password=" + cameraConfig.getPassword());
|
onvifCamera.sendOnvifRequest(RequestType.Renew, onvifCamera.subscriptionXAddr);
|
||||||
} else if (!snapshotPolling) {
|
|
||||||
checkCameraConnection();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DAHUA_THING:
|
case DAHUA_THING:
|
||||||
if (!snapshotPolling) {
|
|
||||||
checkCameraConnection();
|
|
||||||
}
|
|
||||||
// Check for alarms, channel for NVRs appears not to work at filtering.
|
// Check for alarms, channel for NVRs appears not to work at filtering.
|
||||||
if (streamIsStopped("/cgi-bin/eventManager.cgi?action=attach&codes=[All]")) {
|
if (streamIsStopped("/cgi-bin/eventManager.cgi?action=attach&codes=[All]")) {
|
||||||
logger.info("The alarm stream was not running for camera {}, re-starting it now",
|
logger.info("The alarm stream was not running for camera {}, re-starting it now",
|
||||||
@ -1609,9 +1599,6 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DOORBIRD_THING:
|
case DOORBIRD_THING:
|
||||||
if (!snapshotPolling) {
|
|
||||||
checkCameraConnection();
|
|
||||||
}
|
|
||||||
// Check for alarms, channel for NVRs appears not to work at filtering.
|
// Check for alarms, channel for NVRs appears not to work at filtering.
|
||||||
if (streamIsStopped("/bha-api/monitor.cgi?ring=doorbell,motionsensor")) {
|
if (streamIsStopped("/bha-api/monitor.cgi?ring=doorbell,motionsensor")) {
|
||||||
logger.info("The alarm stream was not running for camera {}, re-starting it now",
|
logger.info("The alarm stream was not running for camera {}, re-starting it now",
|
||||||
@ -1733,20 +1720,14 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
"[{ \"cmd\":\"GetAbility\", \"param\":{ \"User\":{ \"userName\":\"admin\" }}}]");
|
"[{ \"cmd\":\"GetAbility\", \"param\":{ \"User\":{ \"userName\":\"admin\" }}}]");
|
||||||
}
|
}
|
||||||
if (snapshotUri.isEmpty()) {
|
if (snapshotUri.isEmpty()) {
|
||||||
if (cameraConfig.getNvrChannel() < 1) {
|
// ReolinkHandler will change the snapshotUri in the response to /api.cgi?cmd=Login
|
||||||
snapshotUri = "/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=openHAB" + reolinkAuth;
|
snapshotUri = "/cgi-bin/api.cgi?cmd=Snap&channel=" + cameraConfig.getNvrChannel() + "&rs=openHAB"
|
||||||
} else {
|
+ reolinkAuth;
|
||||||
snapshotUri = "/cgi-bin/api.cgi?cmd=Snap&channel=" + (cameraConfig.getNvrChannel() - 1)
|
|
||||||
+ "&rs=openHAB" + reolinkAuth;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// channel numbers for snapshots start at 0, while the rtsp start at 1
|
||||||
if (rtspUri.isEmpty()) {
|
if (rtspUri.isEmpty()) {
|
||||||
if (cameraConfig.getNvrChannel() < 1) {
|
rtspUri = "rtsp://" + cameraConfig.getIp() + ":554/h264Preview_0"
|
||||||
rtspUri = "rtsp://" + cameraConfig.getIp() + ":554/h264Preview_01_main";
|
+ (cameraConfig.getNvrChannel() + 1) + "_main";
|
||||||
} else {
|
|
||||||
rtspUri = "rtsp://" + cameraConfig.getIp() + ":554/h264Preview_0" + cameraConfig.getNvrChannel()
|
|
||||||
+ "_main";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1777,7 +1758,7 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
case ONVIF_THING:
|
case ONVIF_THING:
|
||||||
return true;
|
return true;
|
||||||
case REOLINK_THING:
|
case REOLINK_THING:
|
||||||
if (cameraConfig.getNvrChannel() < 1) {
|
if (cameraConfig.getOnvifPort() > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
import io.netty.channel.ChannelDuplexHandler;
|
import io.netty.channel.ChannelDuplexHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.http.HttpContent;
|
import io.netty.handler.codec.http.HttpContent;
|
||||||
|
import io.netty.handler.codec.http.HttpResponse;
|
||||||
import io.netty.handler.codec.http.LastHttpContent;
|
import io.netty.handler.codec.http.LastHttpContent;
|
||||||
import io.netty.handler.timeout.IdleStateEvent;
|
import io.netty.handler.timeout.IdleStateEvent;
|
||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
@ -46,6 +47,11 @@ public class OnvifCodec extends ChannelDuplexHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
if (msg instanceof HttpResponse response) {
|
||||||
|
if (response.status().code() != 200) {
|
||||||
|
logger.trace("ONVIF replied with code {} message is {}", response.status().code(), msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (msg instanceof HttpContent content) {
|
if (msg instanceof HttpContent content) {
|
||||||
incomingMessage += content.content().toString(CharsetUtil.UTF_8);
|
incomingMessage += content.content().toString(CharsetUtil.UTF_8);
|
||||||
}
|
}
|
||||||
@ -65,11 +71,11 @@ public class OnvifCodec extends ChannelDuplexHandler {
|
|||||||
}
|
}
|
||||||
if (evt instanceof IdleStateEvent) {
|
if (evt instanceof IdleStateEvent) {
|
||||||
IdleStateEvent e = (IdleStateEvent) evt;
|
IdleStateEvent e = (IdleStateEvent) evt;
|
||||||
logger.trace("IdleStateEvent received: {}", e.state());
|
logger.debug("IdleStateEvent received: {}", e.state());
|
||||||
onvifConnection.setIsConnected(false);
|
onvifConnection.setIsConnected(false);
|
||||||
ctx.close();
|
ctx.close();
|
||||||
} else {
|
} else {
|
||||||
logger.trace("Other ONVIF netty channel event occurred: {}", evt);
|
logger.debug("ONVIF netty channel event occurred: {}", evt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ public class OnvifConnection {
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private String imagingXAddr = "http://" + ipAddress + "/onvif/device_service";
|
private String imagingXAddr = "http://" + ipAddress + "/onvif/device_service";
|
||||||
private String ptzXAddr = "http://" + ipAddress + "/onvif/ptz_service";
|
private String ptzXAddr = "http://" + ipAddress + "/onvif/ptz_service";
|
||||||
private String subscriptionXAddr = "http://" + ipAddress + "/onvif/device_service";
|
public String subscriptionXAddr = "http://" + ipAddress + "/onvif/device_service";
|
||||||
private boolean isConnected = false;
|
private boolean isConnected = false;
|
||||||
private int mediaProfileIndex = 0;
|
private int mediaProfileIndex = 0;
|
||||||
private String rtspUri = "";
|
private String rtspUri = "";
|
||||||
@ -269,7 +269,7 @@ public class OnvifConnection {
|
|||||||
+ mediaProfileTokens.get(mediaProfileIndex)
|
+ mediaProfileTokens.get(mediaProfileIndex)
|
||||||
+ "</ProfileToken><Translation><Zoom x=\"-0.0240506344\" xmlns=\"http://www.onvif.org/ver10/schema\"/></Translation></RelativeMove>";
|
+ "</ProfileToken><Translation><Zoom x=\"-0.0240506344\" xmlns=\"http://www.onvif.org/ver10/schema\"/></Translation></RelativeMove>";
|
||||||
case Renew:
|
case Renew:
|
||||||
return "<Renew xmlns=\"http://docs.oasis-open.org/wsn/b-2\"><TerminationTime>PT1M</TerminationTime></Renew>";
|
return "<Renew xmlns=\"http://docs.oasis-open.org/wsn/b-2\"><TerminationTime>PT10S</TerminationTime></Renew>";
|
||||||
case GetConfigurations:
|
case GetConfigurations:
|
||||||
return "<GetConfigurations xmlns=\"http://www.onvif.org/ver20/ptz/wsdl\"></GetConfigurations>";
|
return "<GetConfigurations xmlns=\"http://www.onvif.org/ver20/ptz/wsdl\"></GetConfigurations>";
|
||||||
case GetConfigurationOptions:
|
case GetConfigurationOptions:
|
||||||
@ -310,8 +310,8 @@ public class OnvifConnection {
|
|||||||
logger.trace("ONVIF reply is: {}", message);
|
logger.trace("ONVIF reply is: {}", message);
|
||||||
if (message.contains("PullMessagesResponse")) {
|
if (message.contains("PullMessagesResponse")) {
|
||||||
eventRecieved(message);
|
eventRecieved(message);
|
||||||
} else if (message.contains("RenewResponse")) {
|
|
||||||
sendOnvifRequest(RequestType.PullMessages, subscriptionXAddr);
|
sendOnvifRequest(RequestType.PullMessages, subscriptionXAddr);
|
||||||
|
} else if (message.contains("RenewResponse")) {
|
||||||
} else if (message.contains("GetSystemDateAndTimeResponse")) {// 1st to be sent.
|
} else if (message.contains("GetSystemDateAndTimeResponse")) {// 1st to be sent.
|
||||||
setIsConnected(true);// Instar profile T only cameras need this
|
setIsConnected(true);// Instar profile T only cameras need this
|
||||||
parseDateAndTime(message);
|
parseDateAndTime(message);
|
||||||
@ -380,6 +380,8 @@ public class OnvifConnection {
|
|||||||
ipCameraHandler.rtspUri = rtspUri;
|
ipCameraHandler.rtspUri = rtspUri;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
logger.trace("Unhandled ONVIF reply is: {}", message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,7 +570,7 @@ public class OnvifConnection {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initChannel(SocketChannel socketChannel) throws Exception {
|
public void initChannel(SocketChannel socketChannel) throws Exception {
|
||||||
socketChannel.pipeline().addLast("idleStateHandler", new IdleStateHandler(20, 20, 20));
|
socketChannel.pipeline().addLast("idleStateHandler", new IdleStateHandler(0, 0, 18));
|
||||||
socketChannel.pipeline().addLast("HttpClientCodec", new HttpClientCodec());
|
socketChannel.pipeline().addLast("HttpClientCodec", new HttpClientCodec());
|
||||||
socketChannel.pipeline().addLast("OnvifCodec", new OnvifCodec(getHandle()));
|
socketChannel.pipeline().addLast("OnvifCodec", new OnvifCodec(getHandle()));
|
||||||
}
|
}
|
||||||
@ -583,14 +585,14 @@ public class OnvifConnection {
|
|||||||
if (future == null) {
|
if (future == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (future.isSuccess()) {
|
if (future.isDone() && future.isSuccess()) {
|
||||||
Channel ch = future.channel();
|
Channel ch = future.channel();
|
||||||
ch.writeAndFlush(request);
|
ch.writeAndFlush(request);
|
||||||
} else { // an error occurred
|
} else { // an error occurred
|
||||||
if (future.isDone() && !future.isCancelled()) {
|
if (future.isDone() && !future.isCancelled()) {
|
||||||
Throwable cause = future.cause();
|
Throwable cause = future.cause();
|
||||||
String msg = cause.getMessage();
|
String msg = cause.getMessage();
|
||||||
logger.debug("connect failed - cause {}", cause.getMessage());
|
logger.debug("Connect failed - cause is: {}", cause.getMessage());
|
||||||
if (cause instanceof ConnectTimeoutException) {
|
if (cause instanceof ConnectTimeoutException) {
|
||||||
usingEvents = false;// Prevent Unsubscribe from being sent
|
usingEvents = false;// Prevent Unsubscribe from being sent
|
||||||
ipCameraHandler.cameraCommunicationError(
|
ipCameraHandler.cameraCommunicationError(
|
||||||
@ -601,9 +603,8 @@ public class OnvifConnection {
|
|||||||
ipCameraHandler.cameraCommunicationError(
|
ipCameraHandler.cameraCommunicationError(
|
||||||
"Camera refused to connect when using ONVIF to port:" + port);
|
"Camera refused to connect when using ONVIF to port:" + port);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if (isConnected) {
|
ipCameraHandler.cameraCommunicationError("Camera failed to connect due to being cancelled");
|
||||||
disconnect();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -652,7 +653,7 @@ public class OnvifConnection {
|
|||||||
public void eventRecieved(String eventMessage) {
|
public void eventRecieved(String eventMessage) {
|
||||||
String topic = Helper.fetchXML(eventMessage, "Topic", "tns1:");
|
String topic = Helper.fetchXML(eventMessage, "Topic", "tns1:");
|
||||||
if (topic.isEmpty()) {
|
if (topic.isEmpty()) {
|
||||||
sendOnvifRequest(RequestType.Renew, subscriptionXAddr);
|
logger.debug("No ONVIF Events occured in the last 8 seconds");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String dataName = Helper.fetchXML(eventMessage, "tt:Data", "Name=\"");
|
String dataName = Helper.fetchXML(eventMessage, "tt:Data", "Name=\"");
|
||||||
@ -782,7 +783,6 @@ public class OnvifConnection {
|
|||||||
default:
|
default:
|
||||||
logger.debug("Please report this camera has an un-implemented ONVIF event. Topic: {}", topic);
|
logger.debug("Please report this camera has an un-implemented ONVIF event. Topic: {}", topic);
|
||||||
}
|
}
|
||||||
sendOnvifRequest(RequestType.Renew, subscriptionXAddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean supportsPTZ() {
|
public boolean supportsPTZ() {
|
||||||
|
Loading…
Reference in New Issue
Block a user