[ipcamera] Instar API updates for new 2k+ range (#13805)

* Instar updates
* Detect which API to use from reply.
* Add handling of REFRESH to instar.

Signed-off-by: Matthew Skinner <matt@pcmus.com>
This commit is contained in:
Matthew Skinner 2022-12-03 20:20:11 +11:00 committed by GitHub
parent 75b639e9b3
commit 2a78b306d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 215 additions and 77 deletions

View File

@ -14,6 +14,7 @@ package org.openhab.binding.ipcamera.internal;
import static org.openhab.binding.ipcamera.internal.IpCameraBindingConstants.*; import static org.openhab.binding.ipcamera.internal.IpCameraBindingConstants.*;
import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
@ -62,43 +63,61 @@ public class InstarHandler extends ChannelDuplexHandler {
ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content); ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content);
switch (requestUrl) { switch (requestUrl) {
case "/param.cgi?cmd=getinfrared": case "/param.cgi?cmd=getinfrared":
if (content.contains("var infraredstat=\"auto")) { if (content.contains("var infraredstat=\"auto") || content.contains("infraredstat=\"2\"")) {
ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.ON); ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.ON);
} else { } else {
ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.OFF); ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.OFF);
} }
break; break;
case "/param.cgi?cmd=getoverlayattr&-region=1":// Text Overlays case "/param.cgi?cmd=getoverlayattr&-region=1":// Text Overlays
if (content.contains("var show_1=\"0\"")) { if (content.contains("var show_1=\"0\"") || content.contains("show=\"0\"")) {
ipCameraHandler.setChannelState(CHANNEL_TEXT_OVERLAY, StringType.EMPTY); ipCameraHandler.setChannelState(CHANNEL_TEXT_OVERLAY, StringType.EMPTY);
} else { } else {
value1 = Helper.searchString(content, "var name_1=\""); value1 = Helper.searchString(content, "var name_1=\"");
if (!value1.isEmpty()) { if (!value1.isEmpty()) {
ipCameraHandler.setChannelState(CHANNEL_TEXT_OVERLAY, StringType.valueOf(value1)); ipCameraHandler.setChannelState(CHANNEL_TEXT_OVERLAY, StringType.valueOf(value1));
} else {
value1 = Helper.searchString(content, "name=\"");
if (!value1.isEmpty()) {
ipCameraHandler.setChannelState(CHANNEL_TEXT_OVERLAY, StringType.valueOf(value1));
}
} }
} }
break; break;
case "/cgi-bin/hi3510/param.cgi?cmd=getmdattr":// Motion Alarm case "/cgi-bin/hi3510/param.cgi?cmd=getmdattr":// Motion Alarm old
// Motion Alarm
if (content.contains("var m1_enable=\"1\"")) { if (content.contains("var m1_enable=\"1\"")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON); ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON);
} else { } else {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.OFF); ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.OFF);
} }
break; break;
case "/cgi-bin/hi3510/param.cgi?cmd=getaudioalarmattr":// Audio Alarm case "/param.cgi?cmd=getalarmattr":// Motion Alarm new
if (content.contains("var aa_enable=\"1\"")) { if (content.contains("armed=\"1\"")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON);
} else {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.OFF);
}
break;
case "/param.cgi?cmd=getaudioalarmattr":// Audio Alarm
if (content.contains("enable=\"1\"")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON); ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON);
value1 = Helper.searchString(content, "var aa_value=\""); value1 = Helper.searchString(content, "aa_value=\"");
if (!value1.isEmpty()) { if (!value1.isEmpty()) {// old cameras have threshold in percentage
ipCameraHandler.setChannelState(CHANNEL_THRESHOLD_AUDIO_ALARM, PercentType.valueOf(value1)); ipCameraHandler.setChannelState(CHANNEL_THRESHOLD_AUDIO_ALARM, PercentType.valueOf(value1));
} else {
value1 = Helper.searchString(content, "threshold=\"");
if (!value1.isEmpty()) {// newer cameras have values up to 10
ipCameraHandler.setChannelState(CHANNEL_THRESHOLD_AUDIO_ALARM,
PercentType.valueOf(value1 + "0"));
}
} }
} else { } else {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.OFF); ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.OFF);
ipCameraHandler.setChannelState(CHANNEL_THRESHOLD_AUDIO_ALARM, OnOffType.OFF);
} }
break; break;
case "param.cgi?cmd=getpirattr":// PIR Alarm case "/param.cgi?cmd=getpirattr":// PIR Alarm
if (content.contains("var pir_enable=\"1\"")) { if (content.contains("enable=\"1\"")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_PIR_ALARM, OnOffType.ON); ipCameraHandler.setChannelState(CHANNEL_ENABLE_PIR_ALARM, OnOffType.ON);
} else { } else {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_PIR_ALARM, OnOffType.OFF); ipCameraHandler.setChannelState(CHANNEL_ENABLE_PIR_ALARM, OnOffType.OFF);
@ -107,33 +126,127 @@ public class InstarHandler extends ChannelDuplexHandler {
ipCameraHandler.noMotionDetected(CHANNEL_PIR_ALARM); ipCameraHandler.noMotionDetected(CHANNEL_PIR_ALARM);
break; break;
case "/param.cgi?cmd=getioattr":// External Alarm Input case "/param.cgi?cmd=getioattr":// External Alarm Input
if (content.contains("var io_enable=\"1\"")) { if (content.contains("enable=\"1\"")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT, OnOffType.ON); ipCameraHandler.setChannelState(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT, OnOffType.ON);
} else { } else {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT, OnOffType.OFF); ipCameraHandler.setChannelState(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT, OnOffType.OFF);
} }
break; break;
default:
if (requestUrl.startsWith("/param.cgi?cmd=setasaction&-server=1&enable=1")
&& content.contains("response=\"200\";")) {// new
ipCameraHandler.newInstarApi = true;
ipCameraHandler.logger.debug("Alarm server sucessfully setup for a 2k+ Instar camera");
} else if (requestUrl.startsWith("/param.cgi?cmd=setmdalarm&-aname=server2&-switch=on&-interval=1")
&& content.startsWith("[Succeed]set ok")) {
ipCameraHandler.newInstarApi = false;
ipCameraHandler.logger.debug("Alarm server sucessfully setup for a 1080p Instar camera");
} else {
ipCameraHandler.logger.debug("Unknown reply from URI:{}", requestUrl);
}
} }
} finally { } finally {
ReferenceCountUtil.release(msg); ReferenceCountUtil.release(msg);
} }
} }
// This handles the commands that come from the Openhab event bus. // This handles the commands that come from the openHAB event bus.
public void handleCommand(ChannelUID channelUID, Command command) { public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) { if (command instanceof RefreshType) {
return;
} // end of "REFRESH"
switch (channelUID.getId()) { switch (channelUID.getId()) {
case CHANNEL_THRESHOLD_AUDIO_ALARM: case CHANNEL_THRESHOLD_AUDIO_ALARM:
int value = Math.round(Float.valueOf(command.toString())); case CHANNEL_ENABLE_AUDIO_ALARM:
if (value == 0) { ipCameraHandler.sendHttpGET("/param.cgi?cmd=getaudioalarmattr");
ipCameraHandler.sendHttpGET("/cgi-bin/hi3510/param.cgi?cmd=setaudioalarmattr&-aa_enable=0"); break;
case CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT:
ipCameraHandler.sendHttpGET("/param.cgi?cmd=getioattr");
break;
case CHANNEL_ENABLE_MOTION_ALARM:
if (ipCameraHandler.newInstarApi) {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=getalarmattr");
} else { } else {
ipCameraHandler.sendHttpGET("/cgi-bin/hi3510/param.cgi?cmd=getmdattr");
}
break;
case CHANNEL_ENABLE_PIR_ALARM:
ipCameraHandler.sendHttpGET("/param.cgi?cmd=getpirattr");
break;
case CHANNEL_AUTO_LED:
ipCameraHandler.sendHttpGET("/param.cgi?cmd=getinfrared");
break;
case CHANNEL_TEXT_OVERLAY:
ipCameraHandler.sendHttpGET("/param.cgi?cmd=getoverlayattr&-region=1");
break;
}
return;
} // end of "REFRESH"
if (ipCameraHandler.newInstarApi) {
switch (channelUID.getId()) {
case CHANNEL_THRESHOLD_AUDIO_ALARM:
if (OnOffType.OFF.equals(command) || PercentType.ZERO.equals(command)) {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setaudioalarmattr&enable=0");
} else if (OnOffType.ON.equals(command)) {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setaudioalarmattr&enable=1");
} else if (command instanceof PercentType) {
int value = ((PercentType) command).toBigDecimal().divide(BigDecimal.TEN).intValue();
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setaudioalarmattr&enable=1&threshold=" + value);
}
return;
case CHANNEL_ENABLE_AUDIO_ALARM:
if (OnOffType.ON.equals(command)) {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setaudioalarmattr&enable=1");
} else {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setaudioalarmattr&enable=0");
}
return;
case CHANNEL_ENABLE_MOTION_ALARM:
if (OnOffType.ON.equals(command)) {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setalarmattr&armed=1");
} else {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setalarmattr&armed=0");
}
return;
case CHANNEL_TEXT_OVERLAY:
String text = Helper.encodeSpecialChars(command.toString());
if (text.isEmpty()) {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setoverlayattr&-region=1&-show=0");
} else {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setoverlayattr&-region=1&-show=1&-name=" + text);
}
return;
case CHANNEL_AUTO_LED:
if (OnOffType.ON.equals(command)) {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setinfrared&-infraredstat=2");
} else {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setinfrared&-infraredstat=0");
}
return;
case CHANNEL_ENABLE_PIR_ALARM:
if (OnOffType.ON.equals(command)) {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setpirattr&enable=1");
} else {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setpirattr&enable=0");
}
return;
case CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT:
if (OnOffType.ON.equals(command)) {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setioattr&enable=1");
} else {
ipCameraHandler.sendHttpGET("/param.cgi?cmd=setioattr&enable=0");
}
return;
}
} else {
switch (channelUID.getId()) {
case CHANNEL_THRESHOLD_AUDIO_ALARM:
if (OnOffType.OFF.equals(command) || PercentType.ZERO.equals(command)) {
ipCameraHandler.sendHttpGET("/cgi-bin/hi3510/param.cgi?cmd=setaudioalarmattr&-aa_enable=0");
} else if (OnOffType.ON.equals(command)) {
ipCameraHandler.sendHttpGET("/cgi-bin/hi3510/param.cgi?cmd=setaudioalarmattr&-aa_enable=1"); ipCameraHandler.sendHttpGET("/cgi-bin/hi3510/param.cgi?cmd=setaudioalarmattr&-aa_enable=1");
ipCameraHandler } else if (command instanceof PercentType) {
.sendHttpGET("/cgi-bin/hi3510/param.cgi?cmd=setaudioalarmattr&-aa_enable=1&-aa_value=" int value = ((PercentType) command).toBigDecimal().divide(BigDecimal.TEN).intValue();
+ command.toString()); ipCameraHandler.sendHttpGET(
"/cgi-bin/hi3510/param.cgi?cmd=setaudioalarmattr&-aa_enable=1&-aa_value=" + value * 10);
} }
return; return;
case CHANNEL_ENABLE_AUDIO_ALARM: case CHANNEL_ENABLE_AUDIO_ALARM:
@ -183,6 +296,7 @@ public class InstarHandler extends ChannelDuplexHandler {
return; return;
} }
} }
}
public void alarmTriggered(String alarm) { public void alarmTriggered(String alarm) {
// older cameras placed the & for the first query, whilst newer cameras do not. // older cameras placed the & for the first query, whilst newer cameras do not.
@ -216,20 +330,39 @@ public class InstarHandler extends ChannelDuplexHandler {
} }
if (!objectCode.isEmpty()) { if (!objectCode.isEmpty()) {
switch (objectCode) { switch (objectCode) {
// person=1, car=2, animal=4 so 1+2+4=7 means one of each.
case "0":// no object case "0":// no object
break; break;
case "1":// person/human case "1":
ipCameraHandler.motionDetected(CHANNEL_HUMAN_ALARM); ipCameraHandler.motionDetected(CHANNEL_HUMAN_ALARM);
break; break;
case "2":// car/vehicles case "2":
ipCameraHandler.motionDetected(CHANNEL_CAR_ALARM);
break;
case "3":
ipCameraHandler.motionDetected(CHANNEL_HUMAN_ALARM);
ipCameraHandler.motionDetected(CHANNEL_CAR_ALARM); ipCameraHandler.motionDetected(CHANNEL_CAR_ALARM);
break; break;
case "3":// animals
case "4": case "4":
ipCameraHandler.motionDetected(CHANNEL_ANIMAL_ALARM);
break;
case "5": case "5":
ipCameraHandler.motionDetected(CHANNEL_HUMAN_ALARM);
ipCameraHandler.motionDetected(CHANNEL_ANIMAL_ALARM);
break;
case "6":
ipCameraHandler.motionDetected(CHANNEL_CAR_ALARM);
ipCameraHandler.motionDetected(CHANNEL_ANIMAL_ALARM);
break;
case "7":
ipCameraHandler.motionDetected(CHANNEL_HUMAN_ALARM);
ipCameraHandler.motionDetected(CHANNEL_CAR_ALARM);
ipCameraHandler.motionDetected(CHANNEL_ANIMAL_ALARM); ipCameraHandler.motionDetected(CHANNEL_ANIMAL_ALARM);
break; break;
default: default:
if (objectCode.startsWith("/instar?")) {
return;// has no object due to older Instar camera model
}
ipCameraHandler.logger.debug("Unknown object detection code:{}", objectCode); ipCameraHandler.logger.debug("Unknown object detection code:{}", objectCode);
} }
} }
@ -238,14 +371,14 @@ public class InstarHandler extends ChannelDuplexHandler {
// If a camera does not need to poll a request as often as snapshots, it can be // If a camera does not need to poll a request as often as snapshots, it can be
// added here. Binding steps through the list. // added here. Binding steps through the list.
public ArrayList<String> getLowPriorityRequests() { public ArrayList<String> getLowPriorityRequests() {
ArrayList<String> lowPriorityRequests = new ArrayList<String>(2); ArrayList<String> lowPriorityRequests = new ArrayList<String>(7);
lowPriorityRequests.add("/cgi-bin/hi3510/param.cgi?cmd=getaudioalarmattr"); lowPriorityRequests.add("/param.cgi?cmd=getaudioalarmattr");
lowPriorityRequests.add("/cgi-bin/hi3510/param.cgi?cmd=getmdattr"); lowPriorityRequests.add("/cgi-bin/hi3510/param.cgi?cmd=getmdattr");
lowPriorityRequests.add("/param.cgi?cmd=getalarmattr");
lowPriorityRequests.add("/param.cgi?cmd=getinfrared"); lowPriorityRequests.add("/param.cgi?cmd=getinfrared");
lowPriorityRequests.add("/param.cgi?cmd=getoverlayattr&-region=1"); lowPriorityRequests.add("/param.cgi?cmd=getoverlayattr&-region=1");
lowPriorityRequests.add("/param.cgi?cmd=getpirattr"); lowPriorityRequests.add("/param.cgi?cmd=getpirattr");
lowPriorityRequests.add("/param.cgi?cmd=getioattr"); // ext alarm input on/off lowPriorityRequests.add("/param.cgi?cmd=getioattr"); // ext alarm input on/off
// lowPriorityRequests.add("/param.cgi?cmd=getserverinfo");
return lowPriorityRequests; return lowPriorityRequests;
} }
} }

View File

@ -170,6 +170,7 @@ public class IpCameraHandler extends BaseThingHandler {
private String basicAuth = ""; private String basicAuth = "";
public boolean useBasicAuth = false; public boolean useBasicAuth = false;
public boolean useDigestAuth = false; public boolean useDigestAuth = false;
public boolean newInstarApi = false;
public String snapshotUri = ""; public String snapshotUri = "";
public String mjpegUri = ""; public String mjpegUri = "";
private byte[] currentSnapshot = new byte[] { (byte) 0x00 }; private byte[] currentSnapshot = new byte[] { (byte) 0x00 };
@ -1642,7 +1643,8 @@ public class IpCameraHandler extends BaseThingHandler {
if (mjpegUri.isEmpty()) { if (mjpegUri.isEmpty()) {
mjpegUri = "/mjpegstream.cgi?-chn=12"; mjpegUri = "/mjpegstream.cgi?-chn=12";
} }
// Newer Instar cameras use this to setup the Alarm Server // Newer Instar cameras use this to setup the Alarm Server, plus it is used to work out which API is
// implemented based on the response to these two requests.
sendHttpGET( sendHttpGET(
"/param.cgi?cmd=setasaction&-server=1&enable=1&-interval=1&cmd=setasattr&-as_index=1&-as_server=" "/param.cgi?cmd=setasaction&-server=1&enable=1&-interval=1&cmd=setasattr&-as_index=1&-as_server="
+ hostIp + "&-as_port=" + SERVLET_PORT + "&-as_path=/ipcamera/" + hostIp + "&-as_port=" + SERVLET_PORT + "&-as_path=/ipcamera/"

View File

@ -409,7 +409,7 @@ public class OnvifConnection {
request.headers().add("Content-Type", request.headers().add("Content-Type",
"application/soap+xml; charset=utf-8; action=\"" + actionString + "/" + requestType + "\""); "application/soap+xml; charset=utf-8; action=\"" + actionString + "/" + requestType + "\"");
request.headers().add("Charset", "utf-8"); request.headers().add("Charset", "utf-8");
request.headers().set("Host", extractIPportFromUrl(xAddr)); request.headers().set("Host", ipAddress + ":" + onvifPort);
request.headers().set("Connection", HttpHeaderValues.CLOSE); request.headers().set("Connection", HttpHeaderValues.CLOSE);
request.headers().set("Accept-Encoding", "gzip, deflate"); request.headers().set("Accept-Encoding", "gzip, deflate");
String fullXml = "<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\"" + extraEnvelope + ">" String fullXml = "<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\"" + extraEnvelope + ">"
@ -578,8 +578,11 @@ public class OnvifConnection {
onvifPort = Integer.parseInt(url.substring(beginIndex + 1, endIndex)); onvifPort = Integer.parseInt(url.substring(beginIndex + 1, endIndex));
} else {// 192.168.1.1 } else {// 192.168.1.1
ipAddress = url; ipAddress = url;
deviceXAddr = "http://" + ipAddress + "/onvif/device_service";
logger.debug("No Onvif Port found when parsing:{}", url); logger.debug("No Onvif Port found when parsing:{}", url);
return;
} }
deviceXAddr = "http://" + ipAddress + ":" + onvifPort + "/onvif/device_service";
} }
public void gotoPreset(int index) { public void gotoPreset(int index) {