Skip to content

Commit

Permalink
[ipcamera] Improve Dahua alarms (openhab#10078)
Browse files Browse the repository at this point in the history
Signed-off-by: Matthew Skinner <[email protected]>
  • Loading branch information
Skinah authored and thinkingstone committed Nov 7, 2021
1 parent febd308 commit fe6d86f
Show file tree
Hide file tree
Showing 10 changed files with 230 additions and 93 deletions.
5 changes: 5 additions & 0 deletions bundles/org.openhab.binding.ipcamera/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ The channels are kept consistent as much as possible from brand to brand to make
| `activateAlarmOutput2` | Switch | Toggles a cameras relay output 2. |
| `audioAlarm` | Switch (read only) | When the camera detects noise above a threshold this switch will move to ON. |
| `autoLED` | Switch | When ON this sets a cameras IR LED to automatically turn on or off. |
| `carAlarm` | Switch | When a car is detected the switch will turn ON. |
| `cellMotionAlarm` | Switch (read only) | ONVIF cameras only will reflect the status of the ONVIF event of the same name. |
| `doorBell` | Switch (read only) | Doorbird only, will reflect the status of the doorbell button. |
| `enableAudioAlarm` | Switch | Allows the audio alarm to be turned ON or OFF. |
Expand All @@ -234,6 +235,7 @@ The channels are kept consistent as much as possible from brand to brand to make
| `gifHistoryLength` | Number | How many filenames are in the `gifHistory`. |
| `gotoPreset` | String | ONVIF cameras that can move only. Will cause the camera to move to a preset location. |
| `hlsUrl` | String | The URL for the ipcamera.m3u8 file. |
| `humanAlarm` | Switch | When a camera detects a human this switch will turn ON. |
| `imageUrl` | String | The URL for the ipcamera.jpg file. |
| `itemLeft` | Switch (read only) | Will turn ON if an API camera detects an item has been left behind. |
| `itemTaken` | Switch (read only) | Will turn ON if an API camera detects an item has been stolen. |
Expand Down Expand Up @@ -379,6 +381,9 @@ See this forum thread for examples of how to use snapshots and streams in a site

## Video Streams

To get video streams working, this forum thread has working widget examples that you can use.
<https://community.openhab.org/t/oh3-widget-building-a-camera-widget/110069>

To get some of the video formats working, you need to install FFmpeg.
Visit their site here to learn how <https://ffmpeg.org/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import static org.openhab.binding.ipcamera.internal.IpCameraBindingConstants.*;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -48,6 +48,150 @@ public DahuaHandler(IpCameraHandler handler, int nvrChannel) {
this.nvrChannel = nvrChannel;
}

private void processEvent(String content) {
int startIndex = content.indexOf("Code=", 12) + 5;// skip --myboundary
int endIndex = content.indexOf(";", startIndex + 1);
if (startIndex == -1 || endIndex == -1) {
ipCameraHandler.logger.debug("Code= not found in Dahua event. Content was:{}", content);
return;
}
String code = content.substring(startIndex, endIndex);
startIndex = endIndex + 8;// skip ;action=
endIndex = content.indexOf(";", startIndex);
if (startIndex == -1 || endIndex == -1) {
ipCameraHandler.logger.debug(";action= not found in Dahua event. Content was:{}", content);
return;
}
String action = content.substring(startIndex, endIndex);
switch (code) {
case "VideoMotion":
if (action.equals("Start")) {
ipCameraHandler.motionDetected(CHANNEL_MOTION_ALARM);
} else if (action.equals("Stop")) {
ipCameraHandler.noMotionDetected(CHANNEL_MOTION_ALARM);
}
break;
case "TakenAwayDetection":
if (action.equals("Start")) {
ipCameraHandler.motionDetected(CHANNEL_ITEM_TAKEN);
} else if (action.equals("Stop")) {
ipCameraHandler.noMotionDetected(CHANNEL_ITEM_TAKEN);
}
break;
case "LeftDetection":
if (action.equals("Start")) {
ipCameraHandler.motionDetected(CHANNEL_ITEM_LEFT);
} else if (action.equals("Stop")) {
ipCameraHandler.noMotionDetected(CHANNEL_ITEM_LEFT);
}
break;
case "SmartMotionVehicle":
if (action.equals("Start")) {
ipCameraHandler.motionDetected(CHANNEL_CAR_ALARM);
} else if (action.equals("Stop")) {
ipCameraHandler.noMotionDetected(CHANNEL_CAR_ALARM);
}
break;
case "SmartMotionHuman":
if (action.equals("Start")) {
ipCameraHandler.motionDetected(CHANNEL_HUMAN_ALARM);
} else if (action.equals("Stop")) {
ipCameraHandler.noMotionDetected(CHANNEL_HUMAN_ALARM);
}
break;
case "CrossLineDetection":
if (action.equals("Start")) {
ipCameraHandler.motionDetected(CHANNEL_LINE_CROSSING_ALARM);
} else if (action.equals("Stop")) {
ipCameraHandler.noMotionDetected(CHANNEL_LINE_CROSSING_ALARM);
}
break;
case "AudioMutation":
if (action.equals("Start")) {
ipCameraHandler.audioDetected();
} else if (action.equals("Stop")) {
ipCameraHandler.noAudioDetected();
}
break;
case "FaceDetection":
if (action.equals("Start")) {
ipCameraHandler.motionDetected(CHANNEL_FACE_DETECTED);
} else if (action.equals("Stop")) {
ipCameraHandler.noMotionDetected(CHANNEL_FACE_DETECTED);
}
break;
case "ParkingDetection":
if (action.equals("Start")) {
ipCameraHandler.setChannelState(CHANNEL_PARKING_ALARM, OnOffType.ON);
} else if (action.equals("Stop")) {
ipCameraHandler.setChannelState(CHANNEL_PARKING_ALARM, OnOffType.OFF);
}
break;
case "CrossRegionDetection":
if (action.equals("Start")) {
ipCameraHandler.motionDetected(CHANNEL_FIELD_DETECTION_ALARM);
} else if (action.equals("Stop")) {
ipCameraHandler.noMotionDetected(CHANNEL_FIELD_DETECTION_ALARM);
}
break;
case "VideoLoss":
case "VideoBlind":
if (action.equals("Start")) {
ipCameraHandler.setChannelState(CHANNEL_TOO_DARK_ALARM, OnOffType.ON);
} else if (action.equals("Stop")) {
ipCameraHandler.setChannelState(CHANNEL_TOO_DARK_ALARM, OnOffType.OFF);
}
break;
case "VideoAbnormalDetection":
if (action.equals("Start")) {
ipCameraHandler.setChannelState(CHANNEL_SCENE_CHANGE_ALARM, OnOffType.ON);
} else if (action.equals("Stop")) {
ipCameraHandler.setChannelState(CHANNEL_SCENE_CHANGE_ALARM, OnOffType.OFF);
}
break;
case "VideoUnFocus":
if (action.equals("Start")) {
ipCameraHandler.setChannelState(CHANNEL_TOO_BLURRY_ALARM, OnOffType.ON);
} else if (action.equals("Stop")) {
ipCameraHandler.setChannelState(CHANNEL_TOO_BLURRY_ALARM, OnOffType.OFF);
}
break;
case "AlarmLocal":
if (action.equals("Start")) {
if (content.contains("index=0")) {
ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT, OnOffType.ON);
} else {
ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT2, OnOffType.ON);
}
} else if (action.equals("Stop")) {
if (content.contains("index=0")) {
ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT, OnOffType.OFF);
} else {
ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT2, OnOffType.OFF);
}
}
break;
case "LensMaskOpen":
ipCameraHandler.setChannelState(CHANNEL_ENABLE_PRIVACY_MODE, OnOffType.ON);
break;
case "LensMaskClose":
ipCameraHandler.setChannelState(CHANNEL_ENABLE_PRIVACY_MODE, OnOffType.OFF);
break;
case "TimeChange":
case "NTPAdjustTime":
case "StorageChange":
case "Reboot":
case "NewFile":
case "VideoMotionInfo":
case "RtspSessionDisconnect":
case "LeFunctionStatusSync":
case "RecordDelete":
break;
default:
ipCameraHandler.logger.debug("Unrecognised Dahua event, Code={}, action={}", code, action);
}
}

// This handles the incoming http replies back from the camera.
@Override
public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object msg) throws Exception {
Expand All @@ -56,109 +200,52 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
}
try {
String content = msg.toString();
if (content.startsWith("--myboundary")) {
processEvent(content);
return;
}
ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content);
// determine if the motion detection is turned on or off.
if (content.contains("table.MotionDetect[0].Enable=true")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON);
} else if (content.contains("table.MotionDetect[" + nvrChannel + "].Enable=false")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.OFF);
}
// Handle motion alarm
if (content.contains("Code=VideoMotion;action=Start;index=0")) {
ipCameraHandler.motionDetected(CHANNEL_MOTION_ALARM);
} else if (content.contains("Code=VideoMotion;action=Stop;index=0")) {
ipCameraHandler.noMotionDetected(CHANNEL_MOTION_ALARM);
}
// Handle item taken alarm
if (content.contains("Code=TakenAwayDetection;action=Start;index=0")) {
ipCameraHandler.motionDetected(CHANNEL_ITEM_TAKEN);
} else if (content.contains("Code=TakenAwayDetection;action=Stop;index=0")) {
ipCameraHandler.noMotionDetected(CHANNEL_ITEM_TAKEN);
}
// Handle item left alarm
if (content.contains("Code=LeftDetection;action=Start;index=0")) {
ipCameraHandler.motionDetected(CHANNEL_ITEM_LEFT);
} else if (content.contains("Code=LeftDetection;action=Stop;index=0")) {
ipCameraHandler.noMotionDetected(CHANNEL_ITEM_LEFT);
}
// Handle CrossLineDetection alarm
if (content.contains("Code=CrossLineDetection;action=Start;index=0")) {
ipCameraHandler.motionDetected(CHANNEL_LINE_CROSSING_ALARM);
} else if (content.contains("Code=CrossLineDetection;action=Stop;index=0")) {
ipCameraHandler.noMotionDetected(CHANNEL_LINE_CROSSING_ALARM);
}

// determine if the audio alarm is turned on or off.
if (content.contains("table.AudioDetect[0].MutationDetect=true")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON);
} else if (content.contains("table.AudioDetect[0].MutationDetect=false")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.OFF);
}
// Handle AudioMutation alarm
if (content.contains("Code=AudioMutation;action=Start;index=0")) {
ipCameraHandler.audioDetected();
} else if (content.contains("Code=AudioMutation;action=Stop;index=0")) {
ipCameraHandler.noAudioDetected();
}

// Handle AudioMutationThreshold alarm
if (content.contains("table.AudioDetect[0].MutationThreold=")) {
String value = ipCameraHandler.returnValueFromString(content, "table.AudioDetect[0].MutationThreold=");
ipCameraHandler.setChannelState(CHANNEL_THRESHOLD_AUDIO_ALARM, PercentType.valueOf(value));
}
// Handle FaceDetection alarm
if (content.contains("Code=FaceDetection;action=Start;index=0")) {
ipCameraHandler.motionDetected(CHANNEL_FACE_DETECTED);
} else if (content.contains("Code=FaceDetection;action=Stop;index=0")) {
ipCameraHandler.noMotionDetected(CHANNEL_FACE_DETECTED);
}
// Handle ParkingDetection alarm
if (content.contains("Code=ParkingDetection;action=Start;index=0")) {
ipCameraHandler.motionDetected(CHANNEL_PARKING_ALARM);
} else if (content.contains("Code=ParkingDetection;action=Stop;index=0")) {
ipCameraHandler.noMotionDetected(CHANNEL_PARKING_ALARM);
}
// Handle CrossRegionDetection alarm
if (content.contains("Code=CrossRegionDetection;action=Start;index=0")) {
ipCameraHandler.motionDetected(CHANNEL_FIELD_DETECTION_ALARM);
} else if (content.contains("Code=CrossRegionDetection;action=Stop;index=0")) {
ipCameraHandler.noMotionDetected(CHANNEL_FIELD_DETECTION_ALARM);
}
// Handle External Input alarm
if (content.contains("Code=AlarmLocal;action=Start;index=0")) {
ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT, OnOffType.ON);
} else if (content.contains("Code=AlarmLocal;action=Stop;index=0")) {
ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT, OnOffType.OFF);
}
// Handle External Input alarm2
if (content.contains("Code=AlarmLocal;action=Start;index=1")) {
ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT2, OnOffType.ON);
} else if (content.contains("Code=AlarmLocal;action=Stop;index=1")) {
ipCameraHandler.setChannelState(CHANNEL_EXTERNAL_ALARM_INPUT2, OnOffType.OFF);
}

// CrossLineDetection alarm on/off
if (content.contains("table.VideoAnalyseRule[0][1].Enable=true")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_LINE_CROSSING_ALARM, OnOffType.ON);
} else if (content.contains("table.VideoAnalyseRule[0][1].Enable=false")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_LINE_CROSSING_ALARM, OnOffType.OFF);
}
// Privacy Mode on/off
if (content.contains("Code=LensMaskOpen;") || content.contains("table.LeLensMask[0].Enable=true")) {
if (content.contains("table.LeLensMask[0].Enable=true")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_PRIVACY_MODE, OnOffType.ON);
} else if (content.contains("Code=LensMaskClose;")
|| content.contains("table.LeLensMask[0].Enable=false")) {
} else if (content.contains("table.LeLensMask[0].Enable=false")) {
ipCameraHandler.setChannelState(CHANNEL_ENABLE_PRIVACY_MODE, OnOffType.OFF);
}
} finally {
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) {
if (command instanceof RefreshType) {
switch (channelUID.getId()) {
case CHANNEL_THRESHOLD_AUDIO_ALARM:
// ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=getConfig&name=AudioDetect[0]");
return;
case CHANNEL_ENABLE_AUDIO_ALARM:
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=getConfig&name=AudioDetect[0]");
return;
Expand All @@ -172,8 +259,7 @@ public void handleCommand(ChannelUID channelUID, Command command) {
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=getConfig&name=LeLensMask[0]");
return;
}
return; // Return as we have handled the refresh command above and don't need to
// continue further.
return;
} // end of "REFRESH"
switch (channelUID.getId()) {
case CHANNEL_TEXT_OVERLAY:
Expand Down Expand Up @@ -272,8 +358,7 @@ public void handleCommand(ChannelUID channelUID, Command command) {

// If a camera does not need to poll a request as often as snapshots, it can be
// added here. Binding steps through the list.
public ArrayList<String> getLowPriorityRequests() {
ArrayList<String> lowPriorityRequests = new ArrayList<String>(1);
return lowPriorityRequests;
public List<String> getLowPriorityRequests() {
return List.of();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,14 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms
try {
String content = msg.toString();
ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content);
if (content.contains("doorbell:H")) {
ipCameraHandler.setChannelState(CHANNEL_DOORBELL, OnOffType.ON);
}
if (content.contains("doorbell:L")) {
ipCameraHandler.setChannelState(CHANNEL_DOORBELL, OnOffType.OFF);
} else if (content.contains("doorbell:H")) {
ipCameraHandler.setChannelState(CHANNEL_DOORBELL, OnOffType.ON);
}
if (content.contains("motionsensor:L")) {
ipCameraHandler.noMotionDetected(CHANNEL_MOTION_ALARM);
}
if (content.contains("motionsensor:H")) {
} else if (content.contains("motionsensor:H")) {
ipCameraHandler.motionDetected(CHANNEL_MOTION_ALARM);
}
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import static org.openhab.binding.ipcamera.internal.IpCameraBindingConstants.*;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -212,9 +212,7 @@ public void handleCommand(ChannelUID channelUID, Command command) {

// If a camera does not need to poll a request as often as snapshots, it can be
// added here. Binding steps through the list.
public ArrayList<String> getLowPriorityRequests() {
ArrayList<String> lowPriorityRequests = new ArrayList<String>(1);
lowPriorityRequests.add("/cgi-bin/CGIProxy.fcgi?cmd=getDevState&usr=" + username + "&pwd=" + password);
return lowPriorityRequests;
public List<String> getLowPriorityRequests() {
return List.of();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,6 @@ public static enum FFmpegFormat {
public static final String CHANNEL_GOTO_PRESET = "gotoPreset";
public static final String CHANNEL_START_STREAM = "startStream";
public static final String CHANNEL_ENABLE_PRIVACY_MODE = "enablePrivacyMode";
public static final String CHANNEL_CAR_ALARM = "carAlarm";
public static final String CHANNEL_HUMAN_ALARM = "humanAlarm";
}
Loading

0 comments on commit fe6d86f

Please sign in to comment.