mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 23:22:02 +01:00
[ipcamera] Add white LED controls for Dahua and also Email and Push for Reolink with v20 command support (#16144)
* New reolink channels * extra channel for Dahua. * Reolink NPE fix * Fix LED modes and auto. * Handle NVR channels for new channels * add nvr channels to Dahua. Signed-off-by: Matthew Skinner <matt@pcmus.com>
This commit is contained in:
parent
2cd961f442
commit
5a29d7eb74
@ -213,68 +213,72 @@ If you do not specify any of these, the binding will use the default which shoul
|
|||||||
Each camera brand will have different channels depending on how much of the support for an API has been added.
|
Each camera brand will have different channels depending on how much of the support for an API has been added.
|
||||||
The channels are kept consistent as much as possible from brand to brand to make upgrading to a different camera easier.
|
The channels are kept consistent as much as possible from brand to brand to make upgrading to a different camera easier.
|
||||||
|
|
||||||
| Channel | Type | Description |
|
| Channel | Type | Read/Write | Description |
|
||||||
|-|-|-|
|
|-------------------------------|---------|------------|------------------------------------------------------------------------------------------|
|
||||||
| `activateAlarmOutput` | Switch | Toggles a cameras relay output 1. |
|
| `activateAlarmOutput` | Switch | RW |Toggles a cameras relay output 1. |
|
||||||
| `activateAlarmOutput2` | Switch | Toggles a cameras relay output 2. |
|
| `activateAlarmOutput2` | Switch | RW | Toggles a cameras relay output 2. |
|
||||||
| `animalAlarm` | Switch | Toggles when an animal is in view. |
|
| `animalAlarm` | Switch | RW | Toggles when an animal is in view. |
|
||||||
| `audioAlarm` | Switch (read only) | When the camera detects noise above a threshold this switch will move to ON. |
|
| `audioAlarm` | Switch | R | 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. |
|
| `autoLED` | Switch | RW |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. |
|
| `autoWhiteLED` | Switch | RW |When ON this sets a cameras visible white LED to automatically turn on or off. |
|
||||||
| `cellMotionAlarm` | Switch (read only) | ONVIF cameras only will reflect the status of the ONVIF event of the same name. |
|
| `carAlarm` | Switch | RW | When a car is detected the switch will turn ON. |
|
||||||
| `doorBell` | Switch (read only) | Doorbird only, will reflect the status of the doorbell button. |
|
| `cellMotionAlarm` | Switch | R | ONVIF cameras only will reflect the status of the ONVIF event of the same name. |
|
||||||
| `enableAudioAlarm` | Switch | Allows the audio alarm to be turned ON or OFF. |
|
| `doorBell` | Switch | R | Doorbird only, will reflect the status of the doorbell button. |
|
||||||
| `enableExternalAlarmInput` | Switch | Hikvision and Instar allow the Alarm input terminals to be disabled by this control. |
|
| `enableAudioAlarm` | Switch | RW |Allows the audio alarm to be turned ON or OFF. |
|
||||||
| `enableFieldDetectionAlarm` | Switch | Allows the field detection alarm to be turned ON or OFF. Some cameras will call this the Intrusion Alarm. |
|
| `enableEmail` | Switch | RW |Allows the email features to be turned ON or OFF. |
|
||||||
| `enableFTP` | Switch | Turn the cameras internal FTP recordings ON or OFF. |
|
| `enableExternalAlarmInput` | Switch | RW |Hikvision and Instar allow the Alarm input terminals to be disabled by this control. |
|
||||||
| `enableLED` | Switch | Turn the IR LED ON or OFF. Some cameras have 3 states the LED can be in, so see the `autoLED` channel. |
|
| `enableFieldDetectionAlarm`| Switch | RW |Allows the field detection alarm to be turned ON or OFF. Some cameras will call this the Intrusion Alarm. |
|
||||||
| `enableLineCrossingAlarm` | Switch | Turns the line crossing alarm for API cameras, ON and OFF. |
|
| `enableFTP` | Switch | RW |Turn the cameras internal FTP recordings ON or OFF. |
|
||||||
| `enableMotionAlarm` | Switch | Turns the motion alarm ON and OFF for API cameras. This will not effect FFmpeg based alarms which have their own control. |
|
| `enableLED` | Switch | RW |Turn the IR LED ON or OFF. Some cameras have 3 states the LED can be in, so see the `autoLED` channel. |
|
||||||
| `enablePirAlarm` | Switch | Turn PIR sensor ON or OFF. |
|
| `enableLineCrossingAlarm` | Switch | RW |Turns the line crossing alarm for API cameras, ON and OFF. |
|
||||||
| `enableRecordings` | Switch | Turn the cameras internal recordings ON or OFF. |
|
| `enableMotionAlarm` | Switch | RW |Turns the motion alarm ON and OFF for API cameras. This will not effect FFmpeg based alarms which have their own control. |
|
||||||
| `externalAlarmInput` | Switch (read only) | Reflects the status of the alarm input terminals on some cameras. |
|
| `enablePirAlarm` | Switch | RW |Turn PIR sensor ON or OFF. |
|
||||||
| `externalAlarmInput2` | Switch (read only) | Reflects the status of the alarm input 2 terminals on some cameras. |
|
| `enablePush` | Switch | RW | Allows the push notification features to be turned ON or OFF. |
|
||||||
| `externalLight` | Switch | Some cameras have a dedicated relay output for turning lights on and off with. |
|
| `enableRecordings` | Switch | RW |Turn the cameras internal recordings ON or OFF. |
|
||||||
| `externalMotion` | Switch | Can be used to inform the camera if it has motion in its view area. Handy if you own a PIR or any other kind of external sensor. If you use the autofps.mjpeg feature, this could increase the frame rate when a door that was closed is opened. Note: It will not be passed onto your camera and will not trigger any recordings. |
|
| `externalAlarmInput` | Switch | R | Reflects the status of the alarm input terminals on some cameras. |
|
||||||
| `faceDetected` | Switch (read only) | When a camera detects a face (API cameras only) this switch will move to ON. |
|
| `externalAlarmInput2` | Switch | R | | Reflects the status of the alarm input 2 terminals on some cameras. |
|
||||||
| `fieldDetectionAlarm` | Switch (read only) | Reflects the cameras status for the field or intrusion alarm. |
|
| `externalLight` | Switch | RW |Some cameras have a dedicated relay output for turning lights on and off with. |
|
||||||
| `ffmpegMotionAlarm` | Switch (read only) | The status of the FFmpeg based motion alarm. |
|
| `externalMotion` | Switch | RW |Can be used to inform the camera if it has motion in its view area. Handy if you own a PIR or any other kind of external sensor. If you use the autofps.mjpeg feature, this could increase the frame rate when a door that was closed is opened. Note: It will not be passed onto your camera and will not trigger any recordings. |
|
||||||
| `ffmpegMotionControl` | Dimmer | This control allows FFmpeg to detect movement from a RTSP or HTTP source and inform openHAB. The channel that will move is called `ffmpegMotionAlarm`. |
|
| `faceDetected` | Switch | R | When a camera detects a face (API cameras only) this switch will move to ON. |
|
||||||
| `gifHistory` | String | The 50 most recent filenames the binding has used unless reset. |
|
| `fieldDetectionAlarm` | Switch | R | Reflects the cameras status for the field or intrusion alarm. |
|
||||||
| `gifHistoryLength` | Number | How many filenames are in the `gifHistory`. |
|
| `ffmpegMotionAlarm` | Switch | R | The status of the FFmpeg based motion alarm. |
|
||||||
| `gotoPreset` | String | ONVIF cameras that can move only. Will cause the camera to move to a preset location. |
|
| `ffmpegMotionControl` | Dimmer | RW | This control allows FFmpeg to detect movement from a RTSP or HTTP source and inform openHAB. The channel that will move is called `ffmpegMotionAlarm`. |
|
||||||
| `hlsUrl` | String | The URL for the ipcamera.m3u8 file. |
|
| `gifHistory` | String | RW |The 50 most recent filenames the binding has used unless reset. |
|
||||||
| `humanAlarm` | Switch | When a camera detects a human this switch will turn ON. |
|
| `gifHistoryLength` | Number | RW |How many filenames are in the `gifHistory`. |
|
||||||
| `imageUrl` | String | The URL for the ipcamera.jpg file. |
|
| `gotoPreset` | String | RW |ONVIF cameras that can move only. Will cause the camera to move to a preset location. |
|
||||||
| `itemLeft` | Switch (read only) | Will turn ON if an API camera detects an item has been left behind. |
|
| `hlsUrl` | String | RW |The URL for the ipcamera.m3u8 file. |
|
||||||
| `itemTaken` | Switch (read only) | Will turn ON if an API camera detects an item has been stolen. |
|
| `humanAlarm` | Switch | RW |When a camera detects a human this switch will turn ON. |
|
||||||
| `lastMotionType` | String | Cameras with multiple alarm types will update this with which alarm last detected motion, i.e. a lineCrossing, faceDetection or item stolen alarm. You can also use this to create a timestamp of when the last motion was detected by creating a rule when this channel changes. |
|
| `imageUrl` | String | RW |The URL for the ipcamera.jpg file. |
|
||||||
| `lastEventData` | String | Detailed information about the last smart alarm that can contain information like which Line number was crossed and in which direction. The channel `lastMotionType` will hold the name of the alarm that this data belongs to. |
|
| `itemLeft` | Switch | R | | Will turn ON if an API camera detects an item has been left behind. |
|
||||||
| `lineCrossingAlarm` | Switch (read only) | Will turn on if the API camera detects motion has crossed a line. |
|
| `itemTaken` | Switch | R | Will turn ON if an API camera detects an item has been stolen. |
|
||||||
| `mjpegUrl` | String | The URL for the ipcamera.mjpeg stream. |
|
| `lastMotionType` | String | RW |Cameras with multiple alarm types will update this with which alarm last detected motion, i.e. a lineCrossing, faceDetection or item stolen alarm. You can also use this to create a timestamp of when the last motion was detected by creating a rule when this channel changes. |
|
||||||
| `motionAlarm` | Switch (read only) | The status of the 'video motion' events in ONVIF and API cameras. Also see `cellMotionAlarm` as these can give different results. |
|
| `lastEventData` | String | RW | Detailed information about the last smart alarm that can contain information like which Line number was crossed and in which direction. The channel `lastMotionType` will hold the name of the alarm that this data belongs to. |
|
||||||
| `mp4History` | String | The 50 most recent filenames the binding has used unless reset. |
|
| `lineCrossingAlarm` | Switch | R | Will turn on if the API camera detects motion has crossed a line. |
|
||||||
| `mp4HistoryLength` | Number | How many filenames are in the `mp4History`. Setting this to 0 will clear the history. |
|
| `mjpegUrl` | String | RW | The URL for the ipcamera.mjpeg stream. |
|
||||||
| `pan` | Dimmer | Works with ONVIF cameras that can be moved. |
|
| `motionAlarm` | Switch | R | The status of the 'video motion' events in ONVIF and API cameras. Also see `cellMotionAlarm` as these can give different results. |
|
||||||
| `parkingAlarm` | Switch (read only) | When an API camera detects a car, this will turn ON. |
|
| `mp4History` | String | RW | The 50 most recent filenames the binding has used unless reset. |
|
||||||
| `pirAlarm` | Switch (read only) | When a camera with PIR ability detects motion, this turns ON. |
|
| `mp4HistoryLength` | Number | RW | How many filenames are in the `mp4History`. Setting this to 0 will clear the history. |
|
||||||
| `privacyMode` | Switch | Enable or disable the Privacy Mode of newer Amcrest/Dahua cameras. The camera will move the lens way down and stop the stream. |
|
| `pan` | Dimmer | RW | Works with ONVIF cameras that can be moved. |
|
||||||
| `recordingGif` | Number (read only) | How many seconds recording to GIF for. 0 when file ready. |
|
| `parkingAlarm` | Switch | R | When an API camera detects a car, this will turn ON. |
|
||||||
| `recordingMp4` | Number (read only) | How many seconds recording to MP4 for. 0 when file ready. |
|
| `pirAlarm` | Switch | R | When a camera with PIR ability detects motion, this turns ON. |
|
||||||
| `rtspUrl` | String | The URL for the cameras auto detected RTSP stream. |
|
| `privacyMode` | Switch | RW | Enable or disable the Privacy Mode of newer Amcrest/Dahua cameras. The camera will move the lens way down and stop the stream. |
|
||||||
| `sceneChangeAlarm` | Switch (read only) | When an API camera detects the camera has moved, this turns ON. |
|
| `recordingGif` | Number | R | How many seconds recording to GIF for. 0 when file ready. |
|
||||||
| `startStream` | Switch | Starts the HLS files being created, if it not manually moved it will indicate if the files are being created on demand. |
|
| `recordingMp4` | Number | R | How many seconds recording to MP4 for. 0 when file ready. |
|
||||||
| `storageAlarm` | Switch (read only) | When an ONVIF cameras storage is full and/or removed, this turns ON. |
|
| `rtspUrl` | String | RW | The URL for the cameras auto detected RTSP stream. |
|
||||||
| `tamperAlarm` | Switch (read only) | When an ONVIF cameras tamper switch is tripped, this turns ON. |
|
| `sceneChangeAlarm` | Switch | R | When an API camera detects the camera has moved, this turns ON. |
|
||||||
| `textOverlay` | String | Dahua, Instar and Hikvision can overlay any text you enter here over the video stream. |
|
| `startStream` | Switch | RW | Starts the HLS files being created, if it not manually moved it will indicate if the files are being created on demand. |
|
||||||
| `thresholdAudioAlarm` | Dimmer | This channel can be linked to a Switch and a Slider. The value of the slider is the value in dB that is detected as noise/alarm down from digital full scale. Higher values are more sensitive and will trigger the alarm with quieter / less noise. |
|
| `storageAlarm` | Switch | R | When an ONVIF cameras storage is full and/or removed, this turns ON. |
|
||||||
| `tilt` | Dimmer | Works with ONVIF cameras that can be moved. |
|
| `tamperAlarm` | Switch | R | When an ONVIF cameras tamper switch is tripped, this turns ON. |
|
||||||
| `triggerExternalAlarmInput` | Switch | Hikvision cameras can change if the alarm input terminal is ON when high or low. This can be used to manually cause an alarm input event to occur. |
|
| `textOverlay` | String | RW | Dahua, Instar and Hikvision can overlay any text you enter here over the video stream. |
|
||||||
| `tooBlurryAlarm` | Switch (read only) | ONVIF cameras only will reflect the status of the ONVIF event of the same name. |
|
| `thresholdAudioAlarm` | Dimmer | RW |This channel can be linked to a Switch and a Slider. The value of the slider is the value in dB that is detected as noise/alarm down from digital full scale. Higher values are more sensitive and will trigger the alarm with quieter / less noise. |
|
||||||
| `tooBrightAlarm` | Switch (read only) | ONVIF cameras only will reflect the status of the ONVIF event of the same name. |
|
| `tilt` | Dimmer | RW |Works with ONVIF cameras that can be moved. |
|
||||||
| `tooDarkAlarm` | Switch (read only) | ONVIF cameras only will reflect the status of the ONVIF event of the same name. |
|
| `triggerExternalAlarmInput` | Switch | RW | Hikvision cameras can change if the alarm input terminal is ON when high or low. This can be used to manually cause an alarm input event to occur. |
|
||||||
| `pollImage` | Switch | This control can be used to manually start and stop using your CPU to create snapshots from a RTSP source. If you have a snapshot URL setup in the binding, only then can this control can be used to update the Image channel. |
|
| `tooBlurryAlarm` | Switch | R | ONVIF cameras only will reflect the status of the ONVIF event of the same name. |
|
||||||
| `zoom` | Dimmer | Works with ONVIF cameras that can be moved. |
|
| `tooBrightAlarm` | Switch | R | ONVIF cameras only will reflect the status of the ONVIF event of the same name. |
|
||||||
|
| `tooDarkAlarm` | Switch | R | ONVIF cameras only will reflect the status of the ONVIF event of the same name. |
|
||||||
|
| `pollImage` | Switch | RW | This control can be used to manually start and stop using your CPU to create snapshots from a RTSP source. If you have a snapshot URL setup in the binding, only then can this control can be used to update the Image channel. |
|
||||||
|
| `whiteLED` | Dimmer | RW | Turn the visible white LED ON or OFF and if supported dim from 0-100%. |
|
||||||
|
| `zoom` | Dimmer | RW | Works with ONVIF cameras that can be moved. |
|
||||||
|
|
||||||
## Moving PTZ Cameras
|
## Moving PTZ Cameras
|
||||||
|
|
||||||
|
@ -43,12 +43,13 @@ import io.netty.util.ReferenceCountUtil;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class DahuaHandler extends ChannelDuplexHandler {
|
public class DahuaHandler extends ChannelDuplexHandler {
|
||||||
private IpCameraHandler ipCameraHandler;
|
private IpCameraHandler ipCameraHandler;
|
||||||
private int nvrChannel;
|
private int nvrChannelAdjusted;
|
||||||
private Pattern boundaryPattern;
|
private Pattern boundaryPattern;
|
||||||
|
|
||||||
public DahuaHandler(IpCameraHandler handler, int nvrChannel) {
|
public DahuaHandler(IpCameraHandler handler, int nvrChannel) {
|
||||||
ipCameraHandler = handler;
|
ipCameraHandler = handler;
|
||||||
this.nvrChannel = nvrChannel;
|
// Most of the API is the NVR channel -1, but some of it is not, like streams and snapshot URLS.
|
||||||
|
nvrChannelAdjusted = nvrChannel - 1;
|
||||||
boundaryPattern = Pattern.compile("^-- ?myboundary$", Pattern.MULTILINE);
|
boundaryPattern = Pattern.compile("^-- ?myboundary$", Pattern.MULTILINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,35 +210,36 @@ public class DahuaHandler extends ChannelDuplexHandler {
|
|||||||
|
|
||||||
private void processSettings(String content) {
|
private void processSettings(String content) {
|
||||||
// determine if the motion detection is turned on or off.
|
// determine if the motion detection is turned on or off.
|
||||||
if (content.contains("table.MotionDetect[0].Enable=true")) {
|
if (content.contains("table.MotionDetect[" + nvrChannelAdjusted + "].Enable=true")) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON);
|
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON);
|
||||||
} else if (content.contains("table.MotionDetect[" + nvrChannel + "].Enable=false")) {
|
} else if (content.contains("table.MotionDetect[" + nvrChannelAdjusted + "].Enable=false")) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.OFF);
|
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine if the audio alarm is turned on or off.
|
// determine if the audio alarm is turned on or off.
|
||||||
if (content.contains("table.AudioDetect[0].MutationDetect=true")) {
|
if (content.contains("table.AudioDetect[" + nvrChannelAdjusted + "].MutationDetect=true")) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON);
|
ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON);
|
||||||
} else if (content.contains("table.AudioDetect[0].MutationDetect=false")) {
|
} else if (content.contains("table.AudioDetect[" + nvrChannelAdjusted + "].MutationDetect=false")) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.OFF);
|
ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle AudioMutationThreshold alarm
|
// Handle AudioMutationThreshold alarm
|
||||||
if (content.contains("table.AudioDetect[0].MutationThreold=")) {
|
if (content.contains("table.AudioDetect[" + nvrChannelAdjusted + "].MutationThreold=")) {
|
||||||
String value = ipCameraHandler.returnValueFromString(content, "table.AudioDetect[0].MutationThreold=");
|
String value = ipCameraHandler.returnValueFromString(content,
|
||||||
|
"table.AudioDetect[" + nvrChannelAdjusted + "].MutationThreold=");
|
||||||
ipCameraHandler.setChannelState(CHANNEL_THRESHOLD_AUDIO_ALARM, PercentType.valueOf(value));
|
ipCameraHandler.setChannelState(CHANNEL_THRESHOLD_AUDIO_ALARM, PercentType.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
// CrossLineDetection alarm on/off
|
// CrossLineDetection alarm on/off
|
||||||
if (content.contains("table.VideoAnalyseRule[0][1].Enable=true")) {
|
if (content.contains("table.VideoAnalyseRule[" + nvrChannelAdjusted + "][1].Enable=true")) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_ENABLE_LINE_CROSSING_ALARM, OnOffType.ON);
|
ipCameraHandler.setChannelState(CHANNEL_ENABLE_LINE_CROSSING_ALARM, OnOffType.ON);
|
||||||
} else if (content.contains("table.VideoAnalyseRule[0][1].Enable=false")) {
|
} else if (content.contains("table.VideoAnalyseRule[" + nvrChannelAdjusted + "][1].Enable=false")) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_ENABLE_LINE_CROSSING_ALARM, OnOffType.OFF);
|
ipCameraHandler.setChannelState(CHANNEL_ENABLE_LINE_CROSSING_ALARM, OnOffType.OFF);
|
||||||
}
|
}
|
||||||
// Privacy Mode on/off
|
// Privacy Mode on/off
|
||||||
if (content.contains("table.LeLensMask[0].Enable=true")) {
|
if (content.contains("table.LeLensMask[" + nvrChannelAdjusted + "].Enable=true")) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_ENABLE_PRIVACY_MODE, OnOffType.ON);
|
ipCameraHandler.setChannelState(CHANNEL_ENABLE_PRIVACY_MODE, OnOffType.ON);
|
||||||
} else if (content.contains("table.LeLensMask[0].Enable=false")) {
|
} else if (content.contains("table.LeLensMask[" + nvrChannelAdjusted + "].Enable=false")) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_ENABLE_PRIVACY_MODE, OnOffType.OFF);
|
ipCameraHandler.setChannelState(CHANNEL_ENABLE_PRIVACY_MODE, OnOffType.OFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,16 +271,30 @@ public class DahuaHandler extends ChannelDuplexHandler {
|
|||||||
if (command instanceof RefreshType) {
|
if (command instanceof RefreshType) {
|
||||||
switch (channelUID.getId()) {
|
switch (channelUID.getId()) {
|
||||||
case CHANNEL_ENABLE_AUDIO_ALARM:
|
case CHANNEL_ENABLE_AUDIO_ALARM:
|
||||||
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=getConfig&name=AudioDetect[0]");
|
ipCameraHandler.sendHttpGET(
|
||||||
|
"/cgi-bin/configManager.cgi?action=getConfig&name=AudioDetect[" + nvrChannelAdjusted + "]");
|
||||||
return;
|
return;
|
||||||
case CHANNEL_ENABLE_LINE_CROSSING_ALARM:
|
case CHANNEL_ENABLE_LINE_CROSSING_ALARM:
|
||||||
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=getConfig&name=VideoAnalyseRule");
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=getConfig&name=VideoAnalyseRule["
|
||||||
|
+ nvrChannelAdjusted + "]");
|
||||||
return;
|
return;
|
||||||
case CHANNEL_ENABLE_MOTION_ALARM:
|
case CHANNEL_ENABLE_MOTION_ALARM:
|
||||||
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=getConfig&name=MotionDetect[0]");
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=getConfig&name=MotionDetect["
|
||||||
|
+ nvrChannelAdjusted + "]");
|
||||||
return;
|
return;
|
||||||
case CHANNEL_ENABLE_PRIVACY_MODE:
|
case CHANNEL_ENABLE_PRIVACY_MODE:
|
||||||
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=getConfig&name=LeLensMask[0]");
|
ipCameraHandler.sendHttpGET(
|
||||||
|
"/cgi-bin/configManager.cgi?action=getConfig&name=LeLensMask[" + nvrChannelAdjusted + "]");
|
||||||
|
return;
|
||||||
|
case CHANNEL_AUTO_LED:
|
||||||
|
case CHANNEL_ENABLE_LED:
|
||||||
|
ipCameraHandler.sendHttpGET(
|
||||||
|
"/cgi-bin/configManager.cgi?action=getConfig&name=Light[" + nvrChannelAdjusted + "]");
|
||||||
|
return;
|
||||||
|
case CHANNEL_AUTO_WHITE_LED:
|
||||||
|
case CHANNEL_WHITE_LED:
|
||||||
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=getConfig&name=Lighting_V2["
|
||||||
|
+ nvrChannelAdjusted + "][0][1].Mode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -287,76 +303,109 @@ public class DahuaHandler extends ChannelDuplexHandler {
|
|||||||
case CHANNEL_TEXT_OVERLAY:
|
case CHANNEL_TEXT_OVERLAY:
|
||||||
String text = Helper.encodeSpecialChars(command.toString());
|
String text = Helper.encodeSpecialChars(command.toString());
|
||||||
if (text.isEmpty()) {
|
if (text.isEmpty()) {
|
||||||
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&VideoWidget["
|
||||||
|
+ nvrChannelAdjusted + "].CustomTitle[1].EncodeBlend=false");
|
||||||
|
} else {
|
||||||
|
ipCameraHandler
|
||||||
|
.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[" + nvrChannelAdjusted
|
||||||
|
+ "].CustomTitle[1].EncodeBlend=true&VideoWidget[0].CustomTitle[1].Text=" + text);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case CHANNEL_WHITE_LED:
|
||||||
|
if (DecimalType.ZERO.equals(command) || OnOffType.OFF.equals(command)) {
|
||||||
|
// IR to auto and white light off.
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.ON);
|
||||||
|
ipCameraHandler
|
||||||
|
.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&Lighting_V2[" + nvrChannelAdjusted
|
||||||
|
+ "][0][1].Mode=Off&Lighting_V2[" + nvrChannelAdjusted + "][0][0].Mode=Auto");
|
||||||
|
} else if (OnOffType.ON.equals(command)) {
|
||||||
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&Lighting_V2["
|
||||||
|
+ nvrChannelAdjusted + "][0][1].Mode=Manual");
|
||||||
|
} else if (command instanceof PercentType percentCommand) {
|
||||||
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&Lighting_V2["
|
||||||
|
+ nvrChannelAdjusted + "][0][1].Mode=Manual&Lighting_V2[" + nvrChannelAdjusted
|
||||||
|
+ "][0][1].NearLight[0].Light=" + command.toString());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case CHANNEL_AUTO_WHITE_LED:
|
||||||
|
if (OnOffType.ON.equals(command)) {
|
||||||
|
// we do not know the state anymore as it now will turns on and off via motion
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_WHITE_LED, UnDefType.UNDEF);
|
||||||
ipCameraHandler.sendHttpGET(
|
ipCameraHandler.sendHttpGET(
|
||||||
"/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].EncodeBlend=false");
|
"/cgi-bin/configManager.cgi?action=setConfig&AlarmLighting[" + nvrChannelAdjusted
|
||||||
|
+ "][0].Enable=true&Alarm[2].EventHandler.LightingLink.LightDuration=300");
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler.sendHttpGET(
|
ipCameraHandler.sendHttpGET(
|
||||||
"/cgi-bin/configManager.cgi?action=setConfig&VideoWidget[0].CustomTitle[1].EncodeBlend=true&VideoWidget[0].CustomTitle[1].Text="
|
"/cgi-bin/configManager.cgi?action=setConfig&AlarmLighting[" + nvrChannelAdjusted
|
||||||
+ text);
|
+ "][0].Enable=false&Alarm[2].EventHandler.LightingLink.LightDuration=0");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case CHANNEL_ENABLE_LED:
|
case CHANNEL_ENABLE_LED:
|
||||||
ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.OFF);
|
ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.OFF);
|
||||||
if (DecimalType.ZERO.equals(command) || OnOffType.OFF.equals(command)) {
|
if (DecimalType.ZERO.equals(command) || OnOffType.OFF.equals(command)) {
|
||||||
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&Lighting[0][0].Mode=Off");
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&Lighting["
|
||||||
|
+ nvrChannelAdjusted + "][0].Mode=Off");
|
||||||
} else if (OnOffType.ON.equals(command)) {
|
} else if (OnOffType.ON.equals(command)) {
|
||||||
ipCameraHandler
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&Lighting["
|
||||||
.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&Lighting[0][0].Mode=Manual");
|
+ nvrChannelAdjusted + "][0].Mode=Manual");
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler.sendHttpGET(
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&Lighting["
|
||||||
"/cgi-bin/configManager.cgi?action=setConfig&Lighting[0][0].Mode=Manual&Lighting[0][0].MiddleLight[0].Light="
|
+ nvrChannelAdjusted + "][0].Mode=Manual&Lighting[" + nvrChannelAdjusted
|
||||||
+ command.toString());
|
+ "][0].MiddleLight[0].Light=" + command.toString());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case CHANNEL_AUTO_LED:
|
case CHANNEL_AUTO_LED:
|
||||||
if (OnOffType.ON.equals(command)) {
|
if (OnOffType.ON.equals(command)) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_ENABLE_LED, UnDefType.UNDEF);
|
ipCameraHandler.setChannelState(CHANNEL_ENABLE_LED, UnDefType.UNDEF);
|
||||||
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&Lighting[0][0].Mode=Auto");
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&Lighting["
|
||||||
|
+ nvrChannelAdjusted + "][0].Mode=Auto");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case CHANNEL_THRESHOLD_AUDIO_ALARM:
|
case CHANNEL_THRESHOLD_AUDIO_ALARM:
|
||||||
int threshold = Math.round(Float.valueOf(command.toString()));
|
int threshold = Math.round(Float.valueOf(command.toString()));
|
||||||
|
|
||||||
if (threshold == 0) {
|
if (threshold == 0) {
|
||||||
ipCameraHandler.sendHttpGET(
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&AudioDetect["
|
||||||
"/cgi-bin/configManager.cgi?action=setConfig&AudioDetect[0].MutationThreold=1");
|
+ nvrChannelAdjusted + "].MutationThreold=1");
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler.sendHttpGET(
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&AudioDetect["
|
||||||
"/cgi-bin/configManager.cgi?action=setConfig&AudioDetect[0].MutationThreold=" + threshold);
|
+ nvrChannelAdjusted + "].MutationThreold=" + threshold);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case CHANNEL_ENABLE_AUDIO_ALARM:
|
case CHANNEL_ENABLE_AUDIO_ALARM:
|
||||||
if (OnOffType.ON.equals(command)) {
|
if (OnOffType.ON.equals(command)) {
|
||||||
ipCameraHandler.sendHttpGET(
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&AudioDetect["
|
||||||
"/cgi-bin/configManager.cgi?action=setConfig&AudioDetect[0].MutationDetect=true&AudioDetect[0].EventHandler.Dejitter=1");
|
+ nvrChannelAdjusted + "].MutationDetect=true&AudioDetect[0].EventHandler.Dejitter=1");
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler.sendHttpGET(
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&AudioDetect["
|
||||||
"/cgi-bin/configManager.cgi?action=setConfig&AudioDetect[0].MutationDetect=false");
|
+ nvrChannelAdjusted + "].MutationDetect=false");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case CHANNEL_ENABLE_LINE_CROSSING_ALARM:
|
case CHANNEL_ENABLE_LINE_CROSSING_ALARM:
|
||||||
if (OnOffType.ON.equals(command)) {
|
if (OnOffType.ON.equals(command)) {
|
||||||
ipCameraHandler.sendHttpGET(
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&VideoAnalyseRule["
|
||||||
"/cgi-bin/configManager.cgi?action=setConfig&VideoAnalyseRule[0][1].Enable=true");
|
+ nvrChannelAdjusted + "][1].Enable=true");
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler.sendHttpGET(
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&VideoAnalyseRule["
|
||||||
"/cgi-bin/configManager.cgi?action=setConfig&VideoAnalyseRule[0][1].Enable=false");
|
+ nvrChannelAdjusted + "][1].Enable=false");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case CHANNEL_ENABLE_MOTION_ALARM:
|
case CHANNEL_ENABLE_MOTION_ALARM:
|
||||||
if (OnOffType.ON.equals(command)) {
|
if (OnOffType.ON.equals(command)) {
|
||||||
ipCameraHandler.sendHttpGET(
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&MotionDetect["
|
||||||
"/cgi-bin/configManager.cgi?action=setConfig&MotionDetect[0].Enable=true&MotionDetect[0].EventHandler.Dejitter=1");
|
+ nvrChannelAdjusted + "].Enable=true&MotionDetect[0].EventHandler.Dejitter=1");
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&MotionDetect["
|
||||||
.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&MotionDetect[0].Enable=false");
|
+ nvrChannelAdjusted + "].Enable=false");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case CHANNEL_ACTIVATE_ALARM_OUTPUT:
|
case CHANNEL_ACTIVATE_ALARM_OUTPUT:
|
||||||
if (OnOffType.ON.equals(command)) {
|
if (OnOffType.ON.equals(command)) {
|
||||||
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&AlarmOut[0].Mode=1");
|
ipCameraHandler.sendHttpGET(
|
||||||
|
"/cgi-bin/configManager.cgi?action=setConfig&AlarmOut[" + nvrChannelAdjusted + "].Mode=1");
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&AlarmOut[0].Mode=0");
|
ipCameraHandler.sendHttpGET(
|
||||||
|
"/cgi-bin/configManager.cgi?action=setConfig&AlarmOut[" + nvrChannelAdjusted + "].Mode=0");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case CHANNEL_ACTIVATE_ALARM_OUTPUT2:
|
case CHANNEL_ACTIVATE_ALARM_OUTPUT2:
|
||||||
@ -368,11 +417,11 @@ public class DahuaHandler extends ChannelDuplexHandler {
|
|||||||
return;
|
return;
|
||||||
case CHANNEL_ENABLE_PRIVACY_MODE:
|
case CHANNEL_ENABLE_PRIVACY_MODE:
|
||||||
if (OnOffType.OFF.equals(command)) {
|
if (OnOffType.OFF.equals(command)) {
|
||||||
ipCameraHandler
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&LeLensMask["
|
||||||
.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&LeLensMask[0].Enable=false");
|
+ nvrChannelAdjusted + "].Enable=false");
|
||||||
} else if (OnOffType.ON.equals(command)) {
|
} else if (OnOffType.ON.equals(command)) {
|
||||||
ipCameraHandler
|
ipCameraHandler.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&LeLensMask["
|
||||||
.sendHttpGET("/cgi-bin/configManager.cgi?action=setConfig&LeLensMask[0].Enable=true");
|
+ nvrChannelAdjusted + "].Enable=true");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -117,8 +117,10 @@ public class IpCameraBindingConstants {
|
|||||||
public static final String CHANNEL_TRIGGER_EXTERNAL_ALARM_INPUT = "triggerExternalAlarmInput";
|
public static final String CHANNEL_TRIGGER_EXTERNAL_ALARM_INPUT = "triggerExternalAlarmInput";
|
||||||
public static final String CHANNEL_EXTERNAL_ALARM_INPUT = "externalAlarmInput";
|
public static final String CHANNEL_EXTERNAL_ALARM_INPUT = "externalAlarmInput";
|
||||||
public static final String CHANNEL_EXTERNAL_ALARM_INPUT2 = "externalAlarmInput2";
|
public static final String CHANNEL_EXTERNAL_ALARM_INPUT2 = "externalAlarmInput2";
|
||||||
|
public static final String CHANNEL_AUTO_WHITE_LED = "autoWhiteLED";
|
||||||
public static final String CHANNEL_AUTO_LED = "autoLED";
|
public static final String CHANNEL_AUTO_LED = "autoLED";
|
||||||
public static final String CHANNEL_ENABLE_LED = "enableLED";
|
public static final String CHANNEL_ENABLE_LED = "enableLED";
|
||||||
|
public static final String CHANNEL_WHITE_LED = "whiteLED";
|
||||||
public static final String CHANNEL_ENABLE_PIR_ALARM = "enablePirAlarm";
|
public static final String CHANNEL_ENABLE_PIR_ALARM = "enablePirAlarm";
|
||||||
public static final String CHANNEL_PIR_ALARM = "pirAlarm";
|
public static final String CHANNEL_PIR_ALARM = "pirAlarm";
|
||||||
public static final String CHANNEL_CELL_MOTION_ALARM = "cellMotionAlarm";
|
public static final String CHANNEL_CELL_MOTION_ALARM = "cellMotionAlarm";
|
||||||
@ -143,5 +145,7 @@ public class IpCameraBindingConstants {
|
|||||||
public static final String CHANNEL_HUMAN_ALARM = "humanAlarm";
|
public static final String CHANNEL_HUMAN_ALARM = "humanAlarm";
|
||||||
public static final String CHANNEL_ANIMAL_ALARM = "animalAlarm";
|
public static final String CHANNEL_ANIMAL_ALARM = "animalAlarm";
|
||||||
public static final String CHANNEL_ENABLE_FTP = "enableFTP";
|
public static final String CHANNEL_ENABLE_FTP = "enableFTP";
|
||||||
|
public static final String CHANNEL_ENABLE_EMAIL = "enableEmail";
|
||||||
|
public static final String CHANNEL_ENABLE_PUSH = "enablePush";
|
||||||
public static final String CHANNEL_ENABLE_RECORDINGS = "enableRecordings";
|
public static final String CHANNEL_ENABLE_RECORDINGS = "enableRecordings";
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.ipcamera.internal.ReolinkState.GetAbilityResponse;
|
||||||
import org.openhab.binding.ipcamera.internal.ReolinkState.GetAiStateResponse;
|
import org.openhab.binding.ipcamera.internal.ReolinkState.GetAiStateResponse;
|
||||||
import org.openhab.binding.ipcamera.internal.handler.IpCameraHandler;
|
import org.openhab.binding.ipcamera.internal.handler.IpCameraHandler;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
@ -27,8 +28,10 @@ import org.openhab.core.library.types.StringType;
|
|||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
import org.openhab.core.types.RefreshType;
|
import org.openhab.core.types.RefreshType;
|
||||||
|
import org.openhab.core.types.UnDefType;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
|
||||||
import io.netty.channel.ChannelDuplexHandler;
|
import io.netty.channel.ChannelDuplexHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
@ -80,67 +83,157 @@ public class ReolinkHandler extends ChannelDuplexHandler {
|
|||||||
ipCameraHandler.snapshotUri = "/cgi-bin/api.cgi?cmd=Snap&channel="
|
ipCameraHandler.snapshotUri = "/cgi-bin/api.cgi?cmd=Snap&channel="
|
||||||
+ ipCameraHandler.cameraConfig.getNvrChannel() + "&rs=openHAB"
|
+ ipCameraHandler.cameraConfig.getNvrChannel() + "&rs=openHAB"
|
||||||
+ ipCameraHandler.reolinkAuth;
|
+ ipCameraHandler.reolinkAuth;
|
||||||
|
// admin user in case username in config is a restricted user account. This may cause channels
|
||||||
|
// to be removed due to restricted user, causing missing channels to be falsely reported as a
|
||||||
|
// bug.
|
||||||
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetAbility" + ipCameraHandler.reolinkAuth,
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetAbility" + ipCameraHandler.reolinkAuth,
|
||||||
"[{ \"cmd\":\"GetAbility\", \"param\":{ \"User\":{ \"userName\":\""
|
"[{ \"cmd\":\"GetAbility\", \"param\":{ \"User\":{ \"userName\":\"admin\" }}}]");
|
||||||
+ ipCameraHandler.cameraConfig.getUser() + "\" }}}]");
|
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler.logger.info("Your Reolink camera gave a bad login response:{}", content);
|
ipCameraHandler.logger.info("Your Reolink camera gave a bad login response:{}", content);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "/api.cgi?cmd=GetAbility": // Used to check what channels the camera supports
|
case "/api.cgi?cmd=GetAbility": // Used to check what channels the camera supports
|
||||||
List<org.openhab.core.thing.Channel> removeChannels = new ArrayList<>();
|
List<org.openhab.core.thing.Channel> removeChannels = new ArrayList<>();
|
||||||
org.openhab.core.thing.Channel channel;
|
org.openhab.core.thing.Channel channel = null;
|
||||||
if (content.contains("\"supportFtpEnable\": { \"permit\": 0")) {
|
try {
|
||||||
ipCameraHandler.logger.debug("Camera has no Enable FTP support.");
|
GetAbilityResponse[] getAbilityResponse = gson.fromJson(content, GetAbilityResponse[].class);
|
||||||
channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_FTP);
|
if (getAbilityResponse == null) {
|
||||||
if (channel != null) {
|
return;
|
||||||
removeChannels.add(channel);
|
|
||||||
}
|
}
|
||||||
}
|
if (getAbilityResponse[0].value == null || getAbilityResponse[0].value.ability == null) {
|
||||||
if (content.contains("\"supportRecordEnable\": { \"permit\": 0")) {
|
ipCameraHandler.logger.warn("The GetAbilityResponse could not be parsed: {}",
|
||||||
ipCameraHandler.logger.debug("Camera has no enable recording support.");
|
getAbilityResponse[0].error.detail);
|
||||||
channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_RECORDINGS);
|
return;
|
||||||
if (channel != null) {
|
|
||||||
removeChannels.add(channel);
|
|
||||||
}
|
}
|
||||||
}
|
ipCameraHandler.reolinkScheduleVersion = getAbilityResponse[0].value.ability.scheduleVersion.ver;
|
||||||
if (content.contains("\"floodLight\": { \"permit\": 0")) {
|
if (getAbilityResponse[0].value.ability.supportFtpEnable == null
|
||||||
ipCameraHandler.logger.debug("Camera has no Flood light support.");
|
|| getAbilityResponse[0].value.ability.supportFtpEnable.permit == 0) {
|
||||||
channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_LED);
|
ipCameraHandler.logger.debug("Camera has no Enable FTP support.");
|
||||||
if (channel != null) {
|
channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_FTP);
|
||||||
removeChannels.add(channel);
|
if (channel != null) {
|
||||||
|
removeChannels.add(channel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (getAbilityResponse[0].value.ability.supportRecordEnable == null
|
||||||
|
|| getAbilityResponse[0].value.ability.supportRecordEnable.permit == 0) {
|
||||||
|
ipCameraHandler.logger.debug("Camera has no enable recording support.");
|
||||||
|
channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_RECORDINGS);
|
||||||
|
if (channel != null) {
|
||||||
|
removeChannels.add(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getAbilityResponse[0].value.ability.abilityChn[0].supportAiDogCat == null
|
||||||
|
|| getAbilityResponse[0].value.ability.abilityChn[0].supportAiDogCat.permit == 0) {
|
||||||
|
ipCameraHandler.logger.debug("Camera has no AiDogCat support.");
|
||||||
|
channel = ipCameraHandler.getThing().getChannel(CHANNEL_ANIMAL_ALARM);
|
||||||
|
if (channel != null) {
|
||||||
|
removeChannels.add(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getAbilityResponse[0].value.ability.abilityChn[0].supportAiPeople == null
|
||||||
|
|| getAbilityResponse[0].value.ability.abilityChn[0].supportAiPeople.permit == 0) {
|
||||||
|
ipCameraHandler.logger.debug("Camera has no AiPeople support.");
|
||||||
|
channel = ipCameraHandler.getThing().getChannel(CHANNEL_HUMAN_ALARM);
|
||||||
|
if (channel != null) {
|
||||||
|
removeChannels.add(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getAbilityResponse[0].value.ability.abilityChn[0].supportAiVehicle == null
|
||||||
|
|| getAbilityResponse[0].value.ability.abilityChn[0].supportAiVehicle.permit == 0) {
|
||||||
|
ipCameraHandler.logger.debug("Camera has no AiVehicle support.");
|
||||||
|
channel = ipCameraHandler.getThing().getChannel(CHANNEL_CAR_ALARM);
|
||||||
|
if (channel != null) {
|
||||||
|
removeChannels.add(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getAbilityResponse[0].value.ability.supportEmailEnable == null
|
||||||
|
|| getAbilityResponse[0].value.ability.supportEmailEnable.permit == 0) {
|
||||||
|
ipCameraHandler.logger.debug("Camera has no EmailEnable support.");
|
||||||
|
channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_EMAIL);
|
||||||
|
if (channel != null) {
|
||||||
|
removeChannels.add(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getAbilityResponse[0].value.ability.push == null
|
||||||
|
|| getAbilityResponse[0].value.ability.push.permit == 0) {
|
||||||
|
ipCameraHandler.logger.debug("Camera has no Push support.");
|
||||||
|
channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_PUSH);
|
||||||
|
if (channel != null) {
|
||||||
|
removeChannels.add(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getAbilityResponse[0].value.ability.supportAudioAlarm == null
|
||||||
|
|| getAbilityResponse[0].value.ability.supportAudioAlarm.permit == 0) {
|
||||||
|
ipCameraHandler.logger.debug("Camera has no AudioAlarm support.");
|
||||||
|
channel = ipCameraHandler.getThing().getChannel(CHANNEL_AUDIO_ALARM);
|
||||||
|
if (channel != null) {
|
||||||
|
removeChannels.add(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getAbilityResponse[0].value.ability.supportAudioAlarmEnable == null
|
||||||
|
|| getAbilityResponse[0].value.ability.supportAudioAlarmEnable.permit == 0) {
|
||||||
|
ipCameraHandler.logger.debug("Camera has no AudioAlarm support.");
|
||||||
|
channel = ipCameraHandler.getThing().getChannel(CHANNEL_THRESHOLD_AUDIO_ALARM);
|
||||||
|
if (channel != null) {
|
||||||
|
removeChannels.add(channel);
|
||||||
|
}
|
||||||
|
channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_AUDIO_ALARM);
|
||||||
|
if (channel != null) {
|
||||||
|
removeChannels.add(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getAbilityResponse[0].value.ability.abilityChn[0].supportAiFace == null
|
||||||
|
|| getAbilityResponse[0].value.ability.abilityChn[0].supportAiFace.permit == 0) {
|
||||||
|
ipCameraHandler.logger.debug("Camera has no AiFace support.");
|
||||||
|
channel = ipCameraHandler.getThing().getChannel(CHANNEL_FACE_DETECTED);
|
||||||
|
if (channel != null) {
|
||||||
|
removeChannels.add(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (JsonParseException e) {
|
||||||
|
ipCameraHandler.logger.warn("API command GetAbility may not be supported by the camera");
|
||||||
|
}
|
||||||
|
if (channel != null) {
|
||||||
|
ipCameraHandler.removeChannels(removeChannels);
|
||||||
}
|
}
|
||||||
ipCameraHandler.removeChannels(removeChannels);
|
|
||||||
break;
|
break;
|
||||||
case "/api.cgi?cmd=GetAiState":
|
case "/api.cgi?cmd=GetAiState":
|
||||||
ipCameraHandler.setChannelState(CHANNEL_LAST_EVENT_DATA, new StringType(content));
|
ipCameraHandler.setChannelState(CHANNEL_LAST_EVENT_DATA, new StringType(content));
|
||||||
GetAiStateResponse[] aiResponse = gson.fromJson(content, GetAiStateResponse[].class);
|
try {
|
||||||
if (aiResponse == null) {
|
GetAiStateResponse[] aiResponse = gson.fromJson(content, GetAiStateResponse[].class);
|
||||||
ipCameraHandler.logger.debug("The GetAiStateResponse could not be parsed");
|
if (aiResponse == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (aiResponse[0].value.dog_cat.alarm_state == 1) {
|
if (aiResponse[0].value == null) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_ANIMAL_ALARM, OnOffType.ON);
|
ipCameraHandler.logger.debug("The GetAiStateResponse could not be parsed: {}",
|
||||||
} else {
|
aiResponse[0].error.detail);
|
||||||
ipCameraHandler.setChannelState(CHANNEL_ANIMAL_ALARM, OnOffType.OFF);
|
return;
|
||||||
}
|
}
|
||||||
if (aiResponse[0].value.face.alarm_state == 1) {
|
if (aiResponse[0].value.dogCat.alarmState == 1) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_FACE_DETECTED, OnOffType.ON);
|
ipCameraHandler.setChannelState(CHANNEL_ANIMAL_ALARM, OnOffType.ON);
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_FACE_DETECTED, OnOffType.OFF);
|
ipCameraHandler.setChannelState(CHANNEL_ANIMAL_ALARM, OnOffType.OFF);
|
||||||
}
|
}
|
||||||
if (aiResponse[0].value.people.alarm_state == 1) {
|
if (aiResponse[0].value.face.alarmState == 1) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_HUMAN_ALARM, OnOffType.ON);
|
ipCameraHandler.setChannelState(CHANNEL_FACE_DETECTED, OnOffType.ON);
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_HUMAN_ALARM, OnOffType.OFF);
|
ipCameraHandler.setChannelState(CHANNEL_FACE_DETECTED, OnOffType.OFF);
|
||||||
}
|
}
|
||||||
if (aiResponse[0].value.vehicle.alarm_state == 1) {
|
if (aiResponse[0].value.people.alarmState == 1) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_CAR_ALARM, OnOffType.ON);
|
ipCameraHandler.setChannelState(CHANNEL_HUMAN_ALARM, OnOffType.ON);
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_CAR_ALARM, OnOffType.OFF);
|
ipCameraHandler.setChannelState(CHANNEL_HUMAN_ALARM, OnOffType.OFF);
|
||||||
|
}
|
||||||
|
if (aiResponse[0].value.vehicle.alarmState == 1) {
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_CAR_ALARM, OnOffType.ON);
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_CAR_ALARM, OnOffType.OFF);
|
||||||
|
}
|
||||||
|
} catch (JsonParseException e) {
|
||||||
|
ipCameraHandler.logger.debug("API GetAiState is not supported by the camera.");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "/api.cgi?cmd=GetAudioAlarm":
|
||||||
case "/api.cgi?cmd=GetAudioAlarmV20":
|
case "/api.cgi?cmd=GetAudioAlarmV20":
|
||||||
if (content.contains("\"enable\" : 1")) {
|
if (content.contains("\"enable\" : 1")) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON);
|
ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON);
|
||||||
@ -155,6 +248,13 @@ public class ReolinkHandler extends ChannelDuplexHandler {
|
|||||||
ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.ON);
|
ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.ON);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "/api.cgi?cmd=GetMdAlarm":
|
||||||
|
if (content.contains("00000")) {
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.OFF);
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "/api.cgi?cmd=GetMdState":
|
case "/api.cgi?cmd=GetMdState":
|
||||||
if (content.contains("\"state\" : 0")) {
|
if (content.contains("\"state\" : 0")) {
|
||||||
ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.OFF);
|
ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.OFF);
|
||||||
@ -162,6 +262,37 @@ public class ReolinkHandler extends ChannelDuplexHandler {
|
|||||||
ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.ON);
|
ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.ON);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "/api.cgi?cmd=GetEmail":
|
||||||
|
case "/api.cgi?cmd=GetEmailV20":
|
||||||
|
if (content.contains("\"enable\" : 0")) {
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.OFF);
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.ON);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "/api.cgi?cmd=GetPush":
|
||||||
|
case "/api.cgi?cmd=GetPushV20":
|
||||||
|
if (content.contains("\"enable\" : 0")) {
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.OFF);
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.ON);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "/api.cgi?cmd=GetWhiteLed":
|
||||||
|
if (content.contains("\"state\" : 0")) {
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_WHITE_LED, OnOffType.OFF);
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_WHITE_LED, OnOffType.ON);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "/cgi-bin/api.cgi?cmd=Snap":
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!cutDownURL.contains("cmd=Set")) {// ignore the responses from all Setxxxxx commands
|
||||||
|
ipCameraHandler.logger.warn(
|
||||||
|
"URL {} is not handled currently by the binding, please report this message",
|
||||||
|
cutDownURL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
ReferenceCountUtil.release(msg);
|
ReferenceCountUtil.release(msg);
|
||||||
@ -173,7 +304,9 @@ public class ReolinkHandler extends ChannelDuplexHandler {
|
|||||||
if (command instanceof RefreshType) {
|
if (command instanceof RefreshType) {
|
||||||
switch (channelUID.getId()) {
|
switch (channelUID.getId()) {
|
||||||
case CHANNEL_ENABLE_MOTION_ALARM:
|
case CHANNEL_ENABLE_MOTION_ALARM:
|
||||||
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetMdState" + ipCameraHandler.reolinkAuth);
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetMdAlarm" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\": \"GetMdAlarm\", \"action\": 1,\"param\": {\"channel\": "
|
||||||
|
+ ipCameraHandler.cameraConfig.getNvrChannel() + "}}]");
|
||||||
break;
|
break;
|
||||||
case CHANNEL_ENABLE_AUDIO_ALARM:
|
case CHANNEL_ENABLE_AUDIO_ALARM:
|
||||||
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetAudioAlarmV20" + ipCameraHandler.reolinkAuth,
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetAudioAlarmV20" + ipCameraHandler.reolinkAuth,
|
||||||
@ -183,6 +316,20 @@ public class ReolinkHandler extends ChannelDuplexHandler {
|
|||||||
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetIrLights" + ipCameraHandler.reolinkAuth,
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetIrLights" + ipCameraHandler.reolinkAuth,
|
||||||
"[{ \"cmd\":\"GetIrLights\"}]");
|
"[{ \"cmd\":\"GetIrLights\"}]");
|
||||||
break;
|
break;
|
||||||
|
case CHANNEL_AUTO_WHITE_LED:
|
||||||
|
case CHANNEL_WHITE_LED:
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetWhiteLed" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\": \"GetWhiteLed\",\"action\": 0,\"param\": {\"channel\": "
|
||||||
|
+ ipCameraHandler.cameraConfig.getNvrChannel() + "}}]");
|
||||||
|
break;
|
||||||
|
case CHANNEL_ENABLE_EMAIL:
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetEmailV20" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{ \"cmd\":\"GetEmailV20\"}]");
|
||||||
|
break;
|
||||||
|
case CHANNEL_ENABLE_PUSH:
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetPushV20" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{ \"cmd\":\"GetPush\"}]");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} // end of "REFRESH"
|
} // end of "REFRESH"
|
||||||
@ -209,43 +356,108 @@ public class ReolinkHandler extends ChannelDuplexHandler {
|
|||||||
+ ipCameraHandler.cameraConfig.getNvrChannel() + ",\"state\": \"Off\"}}}]");
|
+ ipCameraHandler.cameraConfig.getNvrChannel() + ",\"state\": \"Off\"}}}]");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CHANNEL_AUTO_WHITE_LED:
|
||||||
|
if (OnOffType.ON.equals(command)) {
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_WHITE_LED, UnDefType.UNDEF);
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetWhiteLed\",\"param\":{\"WhiteLed\":{\"channel\": "
|
||||||
|
+ ipCameraHandler.cameraConfig.getNvrChannel() + ", \"mode\": 1}}}]");
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetWhiteLed\",\"param\":{\"WhiteLed\":{\"channel\": "
|
||||||
|
+ ipCameraHandler.cameraConfig.getNvrChannel() + ", \"mode\": 0}}}]");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case CHANNEL_ENABLE_AUDIO_ALARM:
|
case CHANNEL_ENABLE_AUDIO_ALARM:
|
||||||
if (OnOffType.ON.equals(command)) {
|
if (OnOffType.ON.equals(command)) {
|
||||||
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarm" + ipCameraHandler.reolinkAuth,
|
if (ipCameraHandler.reolinkScheduleVersion == 1) {
|
||||||
"[{\"cmd\": \" SetAudioAlarm\",\"param\": {\"Audio\": {\"schedule\": {\"enable\": 1,\"table\": \"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\"}}}}]");
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarmV20" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetAudioAlarmV20\",\"param\":{\"Audio\" : {\"enable\" : 1}}}]");
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarm" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\": \" SetAudioAlarm\",\"param\": {\"Audio\": {\"schedule\": {\"enable\": 1,\"table\": \"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\"}}}}]");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarm" + ipCameraHandler.reolinkAuth,
|
if (ipCameraHandler.reolinkScheduleVersion == 1) {
|
||||||
"[{\"cmd\": \" SetAudioAlarm\",\"param\": {\"Audio\": {\"schedule\": {\"enable\": 0,\"table\": \"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\"}}}}]");
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarmV20" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetAudioAlarmV20\",\"param\":{\"Audio\" : {\"enable\" : 0}}}]");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarm" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\": \" SetAudioAlarm\",\"param\": {\"Audio\": {\"schedule\": {\"enable\": 0,\"table\": \"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\"}}}}]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CHANNEL_ENABLE_FTP:
|
case CHANNEL_ENABLE_FTP:
|
||||||
if (OnOffType.ON.equals(command)) {
|
if (OnOffType.ON.equals(command)) {
|
||||||
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtp" + ipCameraHandler.reolinkAuth,
|
if (ipCameraHandler.reolinkScheduleVersion == 1) {
|
||||||
"[{\"cmd\":\"SetFtp\",\"param\":{\"Rec\" : {\"channel\" : "
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtpV20" + ipCameraHandler.reolinkAuth,
|
||||||
+ ipCameraHandler.cameraConfig.getNvrChannel()
|
"[{\"cmd\":\"SetFtpV20\",\"param\":{\"Ftp\" : {\"enable\" : 1}}}]");
|
||||||
+ ",\"schedule\" : {\"enable\" : 1}}}}]");
|
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtp" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetFtp\",\"param\":{\"Ftp\" : {\"schedule\" : {\"enable\" : 1}}}}]");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtp" + ipCameraHandler.reolinkAuth,
|
if (ipCameraHandler.reolinkScheduleVersion == 1) {
|
||||||
"[{\"cmd\":\"SetFtp\",\"param\":{\"Rec\" : {\"channel\" : "
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtpV20" + ipCameraHandler.reolinkAuth,
|
||||||
+ ipCameraHandler.cameraConfig.getNvrChannel()
|
"[{\"cmd\":\"SetFtpV20\",\"param\":{\"Ftp\" : {\"enable\" : 0}}}]");
|
||||||
+ ",\"schedule\" : {\"enable\" : 0}}}}]");
|
} else {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtp" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetFtp\",\"param\":{\"Ftp\" : {\"schedule\" : {\"enable\" : 0}}}}]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHANNEL_ENABLE_EMAIL:
|
||||||
|
if (OnOffType.ON.equals(command)) {
|
||||||
|
if (ipCameraHandler.reolinkScheduleVersion == 1) {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetEmailV20" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetEmailV20\",\"param\":{\"Email\" : {\"enable\" : 1}}}]");
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetEmail" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetEmail\",\"param\":{\"Email\" : {\"schedule\" : {\"enable\" : 1}}}}]");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ipCameraHandler.reolinkScheduleVersion == 1) {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetEmailV20" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetEmailV20\",\"param\":{\"Email\" : {\"enable\" : 0}}}]");
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetEmail" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetEmail\",\"param\":{\"Email\" : {\"schedule\" : {\"enable\" : 0}}}}]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHANNEL_ENABLE_PUSH:
|
||||||
|
if (OnOffType.ON.equals(command)) {
|
||||||
|
if (ipCameraHandler.reolinkScheduleVersion == 1) {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetPushV20" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetPushV20\",\"param\":{\"Push\":{\"enable\":1}}}]");
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetPush" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetPush\",\"param\":{\"Push\" : {\"schedule\" : {\"enable\" : 1}}}}]");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ipCameraHandler.reolinkScheduleVersion == 1) {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetPushV20" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetPushV20\",\"param\":{\"Push\":{\"enable\":0}}}]");
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetPush" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetPush\",\"param\":{\"Push\" : {\"schedule\" : {\"enable\" : 0}}}}]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CHANNEL_ENABLE_LED:
|
case CHANNEL_ENABLE_LED:
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.OFF);
|
||||||
if (OnOffType.OFF.equals(command) || PercentType.ZERO.equals(command)) {
|
if (OnOffType.OFF.equals(command) || PercentType.ZERO.equals(command)) {
|
||||||
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetIrLights" + ipCameraHandler.reolinkAuth,
|
||||||
"[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 0,\"channel\": "
|
"[{\"cmd\": \"SetIrLights\",\"action\": 0,\"param\": {\"IrLights\": {\"channel\": "
|
||||||
+ ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 1}}}]");
|
+ ipCameraHandler.cameraConfig.getNvrChannel() + ",\"state\": \"Off\"}}}]");
|
||||||
} else if (OnOffType.ON.equals(command)) {
|
} else if (OnOffType.ON.equals(command) || command instanceof PercentType percentCommand) {
|
||||||
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetIrLights" + ipCameraHandler.reolinkAuth,
|
||||||
"[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 1,\"channel\": "
|
"[{\"cmd\": \"SetIrLights\",\"action\": 0,\"param\": {\"IrLights\": {\"channel\": "
|
||||||
+ ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 1}}}]");
|
+ ipCameraHandler.cameraConfig.getNvrChannel() + ",\"state\": \"On\"}}}]");
|
||||||
} else if (command instanceof PercentType percentCommand) {
|
} else {
|
||||||
int value = percentCommand.toBigDecimal().intValue();
|
ipCameraHandler.logger.warn("Unsupported command sent to enableLED channel");
|
||||||
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
|
|
||||||
"[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 1,\"channel\": "
|
|
||||||
+ ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 1,\"bright\": " + value
|
|
||||||
+ "}}}]");
|
|
||||||
}
|
}
|
||||||
case CHANNEL_ENABLE_MOTION_ALARM:
|
case CHANNEL_ENABLE_MOTION_ALARM:
|
||||||
if (OnOffType.ON.equals(command)) {
|
if (OnOffType.ON.equals(command)) {
|
||||||
@ -256,17 +468,46 @@ public class ReolinkHandler extends ChannelDuplexHandler {
|
|||||||
break;
|
break;
|
||||||
case CHANNEL_ENABLE_RECORDINGS:
|
case CHANNEL_ENABLE_RECORDINGS:
|
||||||
if (OnOffType.ON.equals(command)) {
|
if (OnOffType.ON.equals(command)) {
|
||||||
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRec" + ipCameraHandler.reolinkAuth,
|
if (ipCameraHandler.reolinkScheduleVersion == 1) {
|
||||||
"[{\"cmd\":\"SetRec\",\"param\":{\"Rec\" : {\"channel\" : "
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRecV20" + ipCameraHandler.reolinkAuth,
|
||||||
+ ipCameraHandler.cameraConfig.getNvrChannel()
|
"[{\"cmd\":\"SetRecV20\",\"param\":{\"Rec\":{\"enable\":1}}}]");
|
||||||
+ ",\"schedule\" : {\"enable\" : 1}}}}]");
|
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRec" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetRec\",\"param\":{\"Rec\" : {\"channel\" : "
|
||||||
|
+ ipCameraHandler.cameraConfig.getNvrChannel()
|
||||||
|
+ ",\"schedule\" : {\"enable\" : 1}}}}]");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRec" + ipCameraHandler.reolinkAuth,
|
if (ipCameraHandler.reolinkScheduleVersion == 1) {
|
||||||
"[{\"cmd\":\"SetRec\",\"param\":{\"Rec\" : {\"channel\" : "
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRecV20" + ipCameraHandler.reolinkAuth,
|
||||||
+ ipCameraHandler.cameraConfig.getNvrChannel()
|
"[{\"cmd\":\"SetRecV20\",\"param\":{\"Rec\":{\"enable\":0}}}]");
|
||||||
+ ",\"schedule\" : {\"enable\" : 0}}}}]");
|
|
||||||
|
} else {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRec" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\":\"SetRec\",\"param\":{\"Rec\" : {\"channel\" : "
|
||||||
|
+ ipCameraHandler.cameraConfig.getNvrChannel()
|
||||||
|
+ ",\"schedule\" : {\"enable\" : 0}}}}]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CHANNEL_WHITE_LED:
|
||||||
|
ipCameraHandler.setChannelState(CHANNEL_AUTO_WHITE_LED, OnOffType.OFF);
|
||||||
|
if (OnOffType.OFF.equals(command) || PercentType.ZERO.equals(command)) {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 0,\"channel\": "
|
||||||
|
+ ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 1}}}]");
|
||||||
|
} else if (OnOffType.ON.equals(command)) {
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 1,\"channel\": "
|
||||||
|
+ ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 0}}}]");
|
||||||
|
} else if (command instanceof PercentType percentCommand) {
|
||||||
|
int value = percentCommand.toBigDecimal().intValue();
|
||||||
|
ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
|
||||||
|
"[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 1,\"channel\": "
|
||||||
|
+ ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 1,\"bright\": " + value
|
||||||
|
+ "}}}]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,8 +14,10 @@ package org.openhab.binding.ipcamera.internal;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link ReolinkState} class holds the state and GSON parsed replies for a single Reolink Camera.
|
* The {@link ReolinkState} DTO holds the state and GSON parsed replies from a Reolink Camera.
|
||||||
*
|
*
|
||||||
* @author Matthew Skinner - Initial contribution
|
* @author Matthew Skinner - Initial contribution
|
||||||
*/
|
*/
|
||||||
@ -24,19 +26,59 @@ public class ReolinkState {
|
|||||||
public class GetAiStateResponse {
|
public class GetAiStateResponse {
|
||||||
public class Value {
|
public class Value {
|
||||||
public class Alarm {
|
public class Alarm {
|
||||||
public int alarm_state = 0;
|
@SerializedName(value = "alarmState", alternate = { "alarm_state" }) // alarm_state is used in json
|
||||||
public int support = 0;
|
public int alarmState = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int channel = 0;
|
@SerializedName(value = "dogCat", alternate = { "dog_cat" }) // dog_cat is used in json
|
||||||
public Alarm dog_cat = new Alarm();
|
public Alarm dogCat = new Alarm();
|
||||||
public Alarm face = new Alarm();
|
public Alarm face = new Alarm();
|
||||||
public Alarm people = new Alarm();
|
public Alarm people = new Alarm();
|
||||||
public Alarm vehicle = new Alarm();
|
public Alarm vehicle = new Alarm();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String cmd = "";
|
public class Error {
|
||||||
public int code = 0;
|
public String detail = "";
|
||||||
|
}
|
||||||
|
|
||||||
public Value value = new Value();
|
public Value value = new Value();
|
||||||
|
public Error error = new Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GetAbilityResponse {
|
||||||
|
public class Value {
|
||||||
|
public class Ability {
|
||||||
|
public class AbilityKey {
|
||||||
|
public int permit = 0;
|
||||||
|
public int ver = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AbilityChn {
|
||||||
|
public AbilityKey supportAiFace = new AbilityKey();
|
||||||
|
public AbilityKey supportAiPeople = new AbilityKey();
|
||||||
|
public AbilityKey supportAiVehicle = new AbilityKey();
|
||||||
|
public AbilityKey supportAiDogCat = new AbilityKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbilityChn[] abilityChn = new AbilityChn[1];
|
||||||
|
public AbilityKey push = new AbilityKey();
|
||||||
|
public AbilityKey scheduleVersion = new AbilityKey();
|
||||||
|
public AbilityKey supportAudioAlarm = new AbilityKey();
|
||||||
|
public AbilityKey supportAudioAlarmEnable = new AbilityKey();
|
||||||
|
public AbilityKey supportEmailEnable = new AbilityKey();
|
||||||
|
public AbilityKey supportFtpEnable = new AbilityKey();
|
||||||
|
public AbilityKey supportRecordEnable = new AbilityKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SerializedName(value = "ability", alternate = { "Ability" }) // uses uppercase A
|
||||||
|
public Ability ability = new Ability();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Error {
|
||||||
|
public String detail = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Value value = new Value();
|
||||||
|
public Error error = new Error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ import java.util.concurrent.Future;
|
|||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
@ -173,6 +174,7 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
// basicAuth MUST remain private as it holds the cameraConfig.getPassword()
|
// basicAuth MUST remain private as it holds the cameraConfig.getPassword()
|
||||||
private String basicAuth = "";
|
private String basicAuth = "";
|
||||||
public String reolinkAuth = "&token=null";
|
public String reolinkAuth = "&token=null";
|
||||||
|
public int reolinkScheduleVersion = 0;
|
||||||
public boolean useBasicAuth = false;
|
public boolean useBasicAuth = false;
|
||||||
public boolean useDigestAuth = false;
|
public boolean useDigestAuth = false;
|
||||||
public boolean newInstarApi = false;
|
public boolean newInstarApi = false;
|
||||||
@ -183,7 +185,7 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
public String rtspUri = "";
|
public String rtspUri = "";
|
||||||
public boolean audioAlarmUpdateSnapshot = false;
|
public boolean audioAlarmUpdateSnapshot = false;
|
||||||
private boolean motionAlarmUpdateSnapshot = false;
|
private boolean motionAlarmUpdateSnapshot = false;
|
||||||
private boolean isOnline = false; // Used so only 1 error is logged when a network issue occurs.
|
private AtomicBoolean isOnline = new AtomicBoolean(); // Used so only 1 error is logged when a network issue occurs.
|
||||||
private boolean firstAudioAlarm = false;
|
private boolean firstAudioAlarm = false;
|
||||||
private boolean firstMotionAlarm = false;
|
private boolean firstMotionAlarm = false;
|
||||||
public BigDecimal motionThreshold = BigDecimal.ZERO;
|
public BigDecimal motionThreshold = BigDecimal.ZERO;
|
||||||
@ -436,7 +438,7 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCorrectUrlFormat(String longUrl) {
|
public String getCorrectUrlFormat(String longUrl) {
|
||||||
String temp = longUrl;
|
String temp = longUrl;
|
||||||
URL url;
|
URL url;
|
||||||
|
|
||||||
@ -516,13 +518,12 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
Ffmpeg localSnapshot = ffmpegSnapshot;
|
Ffmpeg localSnapshot = ffmpegSnapshot;
|
||||||
if (localSnapshot != null && !localSnapshot.isAlive()) {
|
if (localSnapshot != null && !localSnapshot.isAlive()) {
|
||||||
cameraCommunicationError("FFmpeg Snapshots Stopped: Check that your camera can be reached.");
|
cameraCommunicationError("FFmpeg Snapshots Stopped: Check that your camera can be reached.");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
return; // ffmpeg snapshot stream is still alive
|
return; // ffmpeg snapshot stream is still alive
|
||||||
}
|
}
|
||||||
|
|
||||||
// if ONVIF cam also use connection state which is updated by regular messages to camera
|
// ONVIF cameras get regular event messages from the camera
|
||||||
if (thing.getThingTypeUID().getId().equals(ONVIF_THING) && snapshotUri.isEmpty() && onvifCamera.isConnected()) {
|
if (supportsOnvifEvents() && onvifCamera.isConnected()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,8 +537,8 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cameraCommunicationError(
|
cameraCommunicationError("Connection Timeout: Check your IP:" + cameraConfig.getIp() + " and PORT:"
|
||||||
"Connection Timeout: Check your IP and PORT are correct and the camera can be reached.");
|
+ cameraConfig.getPort() + " are correct and the camera can be reached.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always use this as sendHttpGET(GET/POST/PUT/DELETE, "/foo/bar",null)//
|
// Always use this as sendHttpGET(GET/POST/PUT/DELETE, "/foo/bar",null)//
|
||||||
@ -546,7 +547,7 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
public void sendHttpRequest(String httpMethod, String httpRequestURLFull, @Nullable String digestString) {
|
public void sendHttpRequest(String httpMethod, String httpRequestURLFull, @Nullable String digestString) {
|
||||||
int port = getPortFromShortenedUrl(httpRequestURLFull);
|
int port = getPortFromShortenedUrl(httpRequestURLFull);
|
||||||
String httpRequestURL = getTinyUrl(httpRequestURLFull);
|
String httpRequestURL = getTinyUrl(httpRequestURLFull);
|
||||||
|
logger.trace("Sending camera: {}: http://{}:{}{}", httpMethod, cameraConfig.getIp(), port, httpRequestURL);
|
||||||
if (mainBootstrap == null) {
|
if (mainBootstrap == null) {
|
||||||
mainBootstrap = new Bootstrap();
|
mainBootstrap = new Bootstrap();
|
||||||
mainBootstrap.group(mainEventLoopGroup);
|
mainBootstrap.group(mainEventLoopGroup);
|
||||||
@ -637,12 +638,9 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
if (future.isDone() && future.isSuccess()) {
|
if (future.isDone() && future.isSuccess()) {
|
||||||
Channel ch = future.channel();
|
Channel ch = future.channel();
|
||||||
openChannels.add(ch);
|
openChannels.add(ch);
|
||||||
if (!isOnline) {
|
if (cameraConnectionJob != null && !isOnline.get()) {
|
||||||
bringCameraOnline();
|
bringCameraOnline();
|
||||||
}
|
}
|
||||||
logger.trace("Sending camera: {}: http://{}:{}{}", httpMethod, cameraConfig.getIp(), port,
|
|
||||||
httpRequestURL);
|
|
||||||
|
|
||||||
openChannel(ch, httpRequestURL);
|
openChannel(ch, httpRequestURL);
|
||||||
CommonCameraHandler commonHandler = (CommonCameraHandler) ch.pipeline().get(COMMON_HANDLER);
|
CommonCameraHandler commonHandler = (CommonCameraHandler) ch.pipeline().get(COMMON_HANDLER);
|
||||||
commonHandler.setURL(httpRequestURLFull);
|
commonHandler.setURL(httpRequestURLFull);
|
||||||
@ -1350,7 +1348,7 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void bringCameraOnline() {
|
private void bringCameraOnline() {
|
||||||
isOnline = true;
|
isOnline.set(true);
|
||||||
updateStatus(ThingStatus.ONLINE);
|
updateStatus(ThingStatus.ONLINE);
|
||||||
groupTracker.listOfOnlineCameraHandlers.add(this);
|
groupTracker.listOfOnlineCameraHandlers.add(this);
|
||||||
groupTracker.listOfOnlineCameraUID.add(getThing().getUID().getId());
|
groupTracker.listOfOnlineCameraUID.add(getThing().getUID().getId());
|
||||||
@ -1405,6 +1403,12 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link pollingCameraConnection} This polls to see if the camera is reachable only until the camera
|
||||||
|
* successfully connects.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
void pollingCameraConnection() {
|
void pollingCameraConnection() {
|
||||||
keepMjpegRunning();
|
keepMjpegRunning();
|
||||||
if (thing.getThingTypeUID().getId().equals(GENERIC_THING)
|
if (thing.getThingTypeUID().getId().equals(GENERIC_THING)
|
||||||
@ -1421,12 +1425,6 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (cameraConfig.getOnvifPort() > 0 && !onvifCamera.isConnected()) {
|
if (cameraConfig.getOnvifPort() > 0 && !onvifCamera.isConnected()) {
|
||||||
if (onvifCamera.isConnectError()) {
|
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Camera is not reachable");
|
|
||||||
} else if (onvifCamera.isRefusedError()) {
|
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
|
||||||
"Camera refused connection on ONVIF ports.");
|
|
||||||
}
|
|
||||||
logger.debug("About to connect to the IP Camera using the ONVIF PORT at IP: {}:{}", cameraConfig.getIp(),
|
logger.debug("About to connect to the IP Camera using the ONVIF PORT at IP: {}:{}", cameraConfig.getIp(),
|
||||||
cameraConfig.getOnvifPort());
|
cameraConfig.getOnvifPort());
|
||||||
onvifCamera.connect(supportsOnvifEvents());
|
onvifCamera.connect(supportsOnvifEvents());
|
||||||
@ -1454,7 +1452,7 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
public void cameraCommunicationError(String reason) {
|
public void cameraCommunicationError(String reason) {
|
||||||
// will try to reconnect again as camera may be rebooting.
|
// will try to reconnect again as camera may be rebooting.
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, reason);
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, reason);
|
||||||
if (isOnline) { // if already offline dont try reconnecting in 6 seconds, we want 30sec wait.
|
if (isOnline.get()) { // if already offline dont try reconnecting in 6 seconds, we want 30sec wait.
|
||||||
resetAndRetryConnecting();
|
resetAndRetryConnecting();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1489,7 +1487,7 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getSnapshot() {
|
public byte[] getSnapshot() {
|
||||||
if (!isOnline) {
|
if (!isOnline.get()) {
|
||||||
// Single gray pixel JPG to keep streams open when the camera goes offline so they dont stop.
|
// Single gray pixel JPG to keep streams open when the camera goes offline so they dont stop.
|
||||||
return new byte[] { (byte) 0xff, (byte) 0xd8, (byte) 0xff, (byte) 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46,
|
return new byte[] { (byte) 0xff, (byte) 0xd8, (byte) 0xff, (byte) 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46,
|
||||||
0x00, 0x01, 0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, (byte) 0xff, (byte) 0xdb, 0x00, 0x43,
|
0x00, 0x01, 0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, (byte) 0xff, (byte) 0xdb, 0x00, 0x43,
|
||||||
@ -1596,13 +1594,8 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
+ cameraConfig.getUser() + "&password=" + cameraConfig.getPassword());
|
+ cameraConfig.getUser() + "&password=" + cameraConfig.getPassword());
|
||||||
sendHttpGET("/api.cgi?cmd=GetMdState&channel=" + cameraConfig.getNvrChannel() + "&user="
|
sendHttpGET("/api.cgi?cmd=GetMdState&channel=" + cameraConfig.getNvrChannel() + "&user="
|
||||||
+ cameraConfig.getUser() + "&password=" + cameraConfig.getPassword());
|
+ cameraConfig.getUser() + "&password=" + cameraConfig.getPassword());
|
||||||
} else {
|
} else if (!snapshotPolling) {
|
||||||
if (!snapshotPolling) {
|
checkCameraConnection();
|
||||||
checkCameraConnection();
|
|
||||||
}
|
|
||||||
if (!onvifCamera.isConnected()) {
|
|
||||||
onvifCamera.connect(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DAHUA_THING:
|
case DAHUA_THING:
|
||||||
@ -1736,6 +1729,9 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
TimeUnit.MINUTES);
|
TimeUnit.MINUTES);
|
||||||
} else {
|
} else {
|
||||||
reolinkAuth = "&user=" + cameraConfig.getUser() + "&password=" + cameraConfig.getPassword();
|
reolinkAuth = "&user=" + cameraConfig.getUser() + "&password=" + cameraConfig.getPassword();
|
||||||
|
// The reply to api.cgi?cmd=Login also sends this only with a token
|
||||||
|
sendHttpPOST("/api.cgi?cmd=GetAbility" + reolinkAuth,
|
||||||
|
"[{ \"cmd\":\"GetAbility\", \"param\":{ \"User\":{ \"userName\":\"admin\" }}}]");
|
||||||
}
|
}
|
||||||
if (snapshotUri.isEmpty()) {
|
if (snapshotUri.isEmpty()) {
|
||||||
if (cameraConfig.getNvrChannel() < 1) {
|
if (cameraConfig.getNvrChannel() < 1) {
|
||||||
@ -1766,9 +1762,6 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void tryConnecting() {
|
private void tryConnecting() {
|
||||||
int firstDelay = 4;
|
|
||||||
int normalDelay = 12; // doesn't make sense to have faster retry than CONNECT_TIMEOUT, which is 10 seconds, if
|
|
||||||
// camera is off
|
|
||||||
if (!thing.getThingTypeUID().getId().equals(GENERIC_THING)
|
if (!thing.getThingTypeUID().getId().equals(GENERIC_THING)
|
||||||
&& !thing.getThingTypeUID().getId().equals(DOORBIRD_THING) && cameraConfig.getOnvifPort() > 0) {
|
&& !thing.getThingTypeUID().getId().equals(DOORBIRD_THING) && cameraConfig.getOnvifPort() > 0) {
|
||||||
onvifCamera = new OnvifConnection(this, cameraConfig.getIp() + ":" + cameraConfig.getOnvifPort(),
|
onvifCamera = new OnvifConnection(this, cameraConfig.getIp() + ":" + cameraConfig.getOnvifPort(),
|
||||||
@ -1776,16 +1769,8 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
onvifCamera.setSelectedMediaProfile(cameraConfig.getOnvifMediaProfile());
|
onvifCamera.setSelectedMediaProfile(cameraConfig.getOnvifMediaProfile());
|
||||||
// Only use ONVIF events if it is not an API camera.
|
// Only use ONVIF events if it is not an API camera.
|
||||||
onvifCamera.connect(supportsOnvifEvents());
|
onvifCamera.connect(supportsOnvifEvents());
|
||||||
|
|
||||||
if (supportsOnvifEvents()) {
|
|
||||||
// it takes some time to try to retrieve the ONVIF snapshot and stream URLs and update internal members
|
|
||||||
// on first connect; if connection lost, doesn't make sense to poll to often
|
|
||||||
firstDelay = 12;
|
|
||||||
normalDelay = 30;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
cameraConnectionJob = threadPool.scheduleWithFixedDelay(this::pollingCameraConnection, firstDelay, normalDelay,
|
cameraConnectionJob = threadPool.scheduleWithFixedDelay(this::pollingCameraConnection, 4, 12, TimeUnit.SECONDS);
|
||||||
TimeUnit.SECONDS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean supportsOnvifEvents() {
|
private boolean supportsOnvifEvents() {
|
||||||
@ -1817,7 +1802,7 @@ public class IpCameraHandler extends BaseThingHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void offline() {
|
private void offline() {
|
||||||
isOnline = false;
|
isOnline.set(false);
|
||||||
snapshotPolling = false;
|
snapshotPolling = false;
|
||||||
Future<?> localFuture = pollCameraJob;
|
Future<?> localFuture = pollCameraJob;
|
||||||
if (localFuture != null) {
|
if (localFuture != null) {
|
||||||
|
@ -129,11 +129,9 @@ public class OnvifConnection {
|
|||||||
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";
|
private String subscriptionXAddr = "http://" + ipAddress + "/onvif/device_service";
|
||||||
private boolean connectError = false;
|
|
||||||
private boolean refusedError = false;
|
|
||||||
private boolean isConnected = false;
|
private boolean isConnected = false;
|
||||||
private int mediaProfileIndex = 0;
|
private int mediaProfileIndex = 0;
|
||||||
private String snapshotUri = "";
|
// private String snapshotUri = "";
|
||||||
private String rtspUri = "";
|
private String rtspUri = "";
|
||||||
private IpCameraHandler ipCameraHandler;
|
private IpCameraHandler ipCameraHandler;
|
||||||
private boolean usingEvents = false;
|
private boolean usingEvents = false;
|
||||||
@ -315,7 +313,6 @@ public class OnvifConnection {
|
|||||||
sendOnvifRequest(RequestType.PullMessages, subscriptionXAddr);
|
sendOnvifRequest(RequestType.PullMessages, subscriptionXAddr);
|
||||||
} else if (message.contains("GetSystemDateAndTimeResponse")) {// 1st to be sent.
|
} else if (message.contains("GetSystemDateAndTimeResponse")) {// 1st to be sent.
|
||||||
setIsConnected(true);
|
setIsConnected(true);
|
||||||
sendOnvifRequest(RequestType.GetCapabilities, deviceXAddr);
|
|
||||||
parseDateAndTime(message);
|
parseDateAndTime(message);
|
||||||
logger.debug("openHAB UTC dateTime is: {}", getUTCdateTime());
|
logger.debug("openHAB UTC dateTime is: {}", getUTCdateTime());
|
||||||
} else if (message.contains("GetCapabilitiesResponse")) {// 2nd to be sent.
|
} else if (message.contains("GetCapabilitiesResponse")) {// 2nd to be sent.
|
||||||
@ -362,11 +359,14 @@ public class OnvifConnection {
|
|||||||
} else if (message.contains("GetSnapshotUriResponse")) {
|
} else if (message.contains("GetSnapshotUriResponse")) {
|
||||||
String url = Helper.fetchXML(message, ":MediaUri", ":Uri");
|
String url = Helper.fetchXML(message, ":MediaUri", ":Uri");
|
||||||
if (!url.isBlank()) {
|
if (!url.isBlank()) {
|
||||||
snapshotUri = removeIPfromUrl(url);
|
logger.debug("GetSnapshotUri: {}", url);
|
||||||
logger.debug("GetSnapshotUri: {}", snapshotUri);
|
|
||||||
if (ipCameraHandler.snapshotUri.isEmpty()
|
if (ipCameraHandler.snapshotUri.isEmpty()
|
||||||
&& !"ffmpeg".equals(ipCameraHandler.cameraConfig.getSnapshotUrl())) {
|
&& !"ffmpeg".equals(ipCameraHandler.cameraConfig.getSnapshotUrl())) {
|
||||||
ipCameraHandler.snapshotUri = snapshotUri;
|
ipCameraHandler.snapshotUri = ipCameraHandler.getCorrectUrlFormat(url);
|
||||||
|
if (ipCameraHandler.getPortFromShortenedUrl(url) != ipCameraHandler.cameraConfig.getPort()) {
|
||||||
|
logger.warn("ONVIF is reporting the snapshot does not match the things configured port of:{}",
|
||||||
|
ipCameraHandler.cameraConfig.getPort());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (message.contains("GetStreamUriResponse")) {
|
} else if (message.contains("GetStreamUriResponse")) {
|
||||||
@ -382,12 +382,13 @@ public class OnvifConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link removeIPfromUrl} Will throw away all text before the cameras IP, also removes the IP and the PORT
|
* The {@link removeIPandPortFromUrl} Will throw away all text before the cameras IP, also removes the IP and the
|
||||||
|
* PORT
|
||||||
* leaving just the URL.
|
* leaving just the URL.
|
||||||
*
|
*
|
||||||
* @author Matthew Skinner - Initial contribution
|
* @author Matthew Skinner - Initial contribution
|
||||||
*/
|
*/
|
||||||
String removeIPfromUrl(String url) {
|
String removeIPandPortFromUrl(String url) {
|
||||||
int index = url.indexOf("//");
|
int index = url.indexOf("//");
|
||||||
if (index != -1) {// now remove the :port
|
if (index != -1) {// now remove the :port
|
||||||
index = url.indexOf("/", index + 2);
|
index = url.indexOf("/", index + 2);
|
||||||
@ -503,7 +504,8 @@ public class OnvifConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void sendOnvifRequest(RequestType requestType, String xAddr) {
|
public void sendOnvifRequest(RequestType requestType, String xAddr) {
|
||||||
logger.trace("Sending ONVIF request: {}", requestType);
|
logger.trace("Sending ONVIF request: {} to {}", requestType, xAddr);
|
||||||
|
int port = extractPortFromUrl(xAddr);
|
||||||
String security = "";
|
String security = "";
|
||||||
String extraEnvelope = "";
|
String extraEnvelope = "";
|
||||||
String headerTo = "";
|
String headerTo = "";
|
||||||
@ -531,12 +533,13 @@ public class OnvifConnection {
|
|||||||
headers = "";
|
headers = "";
|
||||||
}
|
}
|
||||||
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, new HttpMethod("POST"),
|
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, new HttpMethod("POST"),
|
||||||
removeIPfromUrl(xAddr));
|
removeIPandPortFromUrl(xAddr));
|
||||||
String actionString = Helper.fetchXML(getXmlCache, requestType.toString(), "xmlns=\"");
|
String actionString = Helper.fetchXML(getXmlCache, requestType.toString(), "xmlns=\"");
|
||||||
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", ipAddress + ":" + onvifPort);
|
// Tapo brand have different ports for the event xAddr to the other xAddr, can't use 1 port for all ONVIF calls.
|
||||||
|
request.headers().set("Host", ipAddress + ":" + port);
|
||||||
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 + ">"
|
||||||
@ -571,28 +574,30 @@ public class OnvifConnection {
|
|||||||
bootstrap = localBootstap;
|
bootstrap = localBootstap;
|
||||||
}
|
}
|
||||||
if (!mainEventLoopGroup.isShuttingDown()) {
|
if (!mainEventLoopGroup.isShuttingDown()) {
|
||||||
localBootstap.connect(new InetSocketAddress(ipAddress, onvifPort)).addListener(new ChannelFutureListener() {
|
// Tapo brand have different ports for the event xAddr to the other xAddr, can't use 1 port for all calls.
|
||||||
|
localBootstap.connect(new InetSocketAddress(ipAddress, port)).addListener(new ChannelFutureListener() {
|
||||||
@Override
|
@Override
|
||||||
public void operationComplete(@Nullable ChannelFuture future) {
|
public void operationComplete(@Nullable ChannelFuture future) {
|
||||||
if (future == null) {
|
if (future == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (future.isSuccess()) {
|
if (future.isSuccess()) {
|
||||||
connectError = false;
|
|
||||||
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.trace("connect failed - cause {}", cause.getMessage());
|
logger.debug("connect failed - cause {}", cause.getMessage());
|
||||||
if (cause instanceof ConnectTimeoutException) {
|
if (cause instanceof ConnectTimeoutException) {
|
||||||
logger.debug("Camera is not reachable on IP {}", ipAddress);
|
usingEvents = false;// Prevent Unsubscribe from being sent
|
||||||
connectError = true;
|
ipCameraHandler.cameraCommunicationError(
|
||||||
|
"Camera timed out when trying to connect to the ONVIF port:" + port);
|
||||||
} else if ((cause instanceof ConnectException) && msg != null
|
} else if ((cause instanceof ConnectException) && msg != null
|
||||||
&& msg.contains("Connection refused")) {
|
&& msg.contains("Connection refused")) {
|
||||||
logger.debug("Camera ONVIF port {} is refused.", onvifPort);
|
usingEvents = false;// Prevent Unsubscribe from being sent
|
||||||
refusedError = true;
|
ipCameraHandler.cameraCommunicationError(
|
||||||
|
"Camera refused to connect when using ONVIF to port:" + port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isConnected) {
|
if (isConnected) {
|
||||||
@ -944,14 +949,6 @@ public class OnvifConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConnectError() {
|
|
||||||
return connectError;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRefusedError() {
|
|
||||||
return refusedError;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
connecting.lock();
|
connecting.lock();
|
||||||
try {
|
try {
|
||||||
@ -965,8 +962,6 @@ public class OnvifConnection {
|
|||||||
connecting.lock();
|
connecting.lock();
|
||||||
try {
|
try {
|
||||||
this.isConnected = isConnected;
|
this.isConnected = isConnected;
|
||||||
this.connectError = false;
|
|
||||||
this.refusedError = false;
|
|
||||||
} finally {
|
} finally {
|
||||||
connecting.unlock();
|
connecting.unlock();
|
||||||
}
|
}
|
||||||
|
@ -629,6 +629,8 @@ channel-type.ipcamera.audioAlarm.label = Audio Alarm
|
|||||||
channel-type.ipcamera.audioAlarm.description = Audio has triggered an Alarm.
|
channel-type.ipcamera.audioAlarm.description = Audio has triggered an Alarm.
|
||||||
channel-type.ipcamera.autoLED.label = Auto LED
|
channel-type.ipcamera.autoLED.label = Auto LED
|
||||||
channel-type.ipcamera.autoLED.description = Turn the automatic mode for the LED ON and OFF.
|
channel-type.ipcamera.autoLED.description = Turn the automatic mode for the LED ON and OFF.
|
||||||
|
channel-type.ipcamera.autoWhiteLED.label = Auto White LED
|
||||||
|
channel-type.ipcamera.autoWhiteLED.description = Turn the automatic mode for the visible white LED ON or OFF.
|
||||||
channel-type.ipcamera.carAlarm.label = Car Alarm
|
channel-type.ipcamera.carAlarm.label = Car Alarm
|
||||||
channel-type.ipcamera.carAlarm.description = A car has triggered the Vehicle Detection.
|
channel-type.ipcamera.carAlarm.description = A car has triggered the Vehicle Detection.
|
||||||
channel-type.ipcamera.cellMotionAlarm.label = Cell Motion Alarm
|
channel-type.ipcamera.cellMotionAlarm.label = Cell Motion Alarm
|
||||||
@ -637,6 +639,8 @@ channel-type.ipcamera.doorBell.label = Door Bell
|
|||||||
channel-type.ipcamera.doorBell.description = The button has been pushed.
|
channel-type.ipcamera.doorBell.description = The button has been pushed.
|
||||||
channel-type.ipcamera.enableAudioAlarm.label = Enable Audio Alarm
|
channel-type.ipcamera.enableAudioAlarm.label = Enable Audio Alarm
|
||||||
channel-type.ipcamera.enableAudioAlarm.description = By using this feature you can stop the camera from sending e-mails when you are having a party.
|
channel-type.ipcamera.enableAudioAlarm.description = By using this feature you can stop the camera from sending e-mails when you are having a party.
|
||||||
|
channel-type.ipcamera.enableEmail.label = Enable Email
|
||||||
|
channel-type.ipcamera.enableEmail.description = Turn the email features of the camera on or off
|
||||||
channel-type.ipcamera.enableExternalAlarmInput.label = Enable Alarm Input 1
|
channel-type.ipcamera.enableExternalAlarmInput.label = Enable Alarm Input 1
|
||||||
channel-type.ipcamera.enableExternalAlarmInput.description = Turn the External Alarm Input feature on and off.
|
channel-type.ipcamera.enableExternalAlarmInput.description = Turn the External Alarm Input feature on and off.
|
||||||
channel-type.ipcamera.enableFTP.label = Enable FTP
|
channel-type.ipcamera.enableFTP.label = Enable FTP
|
||||||
@ -653,6 +657,8 @@ channel-type.ipcamera.enablePirAlarm.label = Enable PIR Alarm
|
|||||||
channel-type.ipcamera.enablePirAlarm.description = Enable/Disable the PIR Alarm.
|
channel-type.ipcamera.enablePirAlarm.description = Enable/Disable the PIR Alarm.
|
||||||
channel-type.ipcamera.enablePrivacyMode.label = Enable Privacy Mode
|
channel-type.ipcamera.enablePrivacyMode.label = Enable Privacy Mode
|
||||||
channel-type.ipcamera.enablePrivacyMode.description = Turn the Privacy Mode on and off.
|
channel-type.ipcamera.enablePrivacyMode.description = Turn the Privacy Mode on and off.
|
||||||
|
channel-type.ipcamera.enablePush.label = Enable Push
|
||||||
|
channel-type.ipcamera.enablePush.description = Turn the push notification features of the camera on or off
|
||||||
channel-type.ipcamera.enableRecordings.label = Enable Recordings
|
channel-type.ipcamera.enableRecordings.label = Enable Recordings
|
||||||
channel-type.ipcamera.enableRecordings.description = Enable/Disable the cameras internal recordings
|
channel-type.ipcamera.enableRecordings.description = Enable/Disable the cameras internal recordings
|
||||||
channel-type.ipcamera.externalAlarmInput.label = Alarm Input 1
|
channel-type.ipcamera.externalAlarmInput.label = Alarm Input 1
|
||||||
@ -764,5 +770,7 @@ channel-type.ipcamera.tooDarkAlarm.label = Too Dark Alarm
|
|||||||
channel-type.ipcamera.tooDarkAlarm.description = Image is too dark.
|
channel-type.ipcamera.tooDarkAlarm.description = Image is too dark.
|
||||||
channel-type.ipcamera.triggerExternalAlarmInput.label = Alarm In 1 TRIGGER high ON/low OFF
|
channel-type.ipcamera.triggerExternalAlarmInput.label = Alarm In 1 TRIGGER high ON/low OFF
|
||||||
channel-type.ipcamera.triggerExternalAlarmInput.description = Change the External Alarm Input to trigger on high or low states.
|
channel-type.ipcamera.triggerExternalAlarmInput.description = Change the External Alarm Input to trigger on high or low states.
|
||||||
|
channel-type.ipcamera.whiteLED.label = White LED
|
||||||
|
channel-type.ipcamera.whiteLED.description = Turn the visible white LED ON and OFF and if supported 0-100% dimming.
|
||||||
channel-type.ipcamera.zoom.label = Zoom
|
channel-type.ipcamera.zoom.label = Zoom
|
||||||
channel-type.ipcamera.zoom.description = Zoom the camera to a new value.
|
channel-type.ipcamera.zoom.description = Zoom the camera to a new value.
|
||||||
|
@ -905,6 +905,8 @@
|
|||||||
<channel id="itemTaken" typeId="itemTaken"/>
|
<channel id="itemTaken" typeId="itemTaken"/>
|
||||||
<channel id="autoLED" typeId="autoLED"/>
|
<channel id="autoLED" typeId="autoLED"/>
|
||||||
<channel id="enableLED" typeId="enableLED"/>
|
<channel id="enableLED" typeId="enableLED"/>
|
||||||
|
<channel id="whiteLED" typeId="whiteLED"/>
|
||||||
|
<channel id="autoWhiteLED" typeId="autoWhiteLED"/>
|
||||||
<channel id="textOverlay" typeId="textOverlay"/>
|
<channel id="textOverlay" typeId="textOverlay"/>
|
||||||
<channel id="pan" typeId="pan"/>
|
<channel id="pan" typeId="pan"/>
|
||||||
<channel id="tilt" typeId="tilt"/>
|
<channel id="tilt" typeId="tilt"/>
|
||||||
@ -921,6 +923,11 @@
|
|||||||
<channel id="sceneChangeAlarm" typeId="sceneChangeAlarm"/>
|
<channel id="sceneChangeAlarm" typeId="sceneChangeAlarm"/>
|
||||||
<channel id="tooBlurryAlarm" typeId="tooBlurryAlarm"/>
|
<channel id="tooBlurryAlarm" typeId="tooBlurryAlarm"/>
|
||||||
</channels>
|
</channels>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<property name="thingTypeVersion">1</property>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<config-description>
|
<config-description>
|
||||||
|
|
||||||
<parameter-group name="Settings">
|
<parameter-group name="Settings">
|
||||||
@ -2297,13 +2304,22 @@
|
|||||||
<channel id="animalAlarm" typeId="animalAlarm"/>
|
<channel id="animalAlarm" typeId="animalAlarm"/>
|
||||||
<channel id="faceDetected" typeId="faceDetected"/>
|
<channel id="faceDetected" typeId="faceDetected"/>
|
||||||
<channel id="autoLED" typeId="autoLED"/>
|
<channel id="autoLED" typeId="autoLED"/>
|
||||||
|
<channel id="autoWhiteLED" typeId="autoWhiteLED"/>
|
||||||
<channel id="enableLED" typeId="enableLED"/>
|
<channel id="enableLED" typeId="enableLED"/>
|
||||||
|
<channel id="whiteLED" typeId="whiteLED"/>
|
||||||
<channel id="textOverlay" typeId="textOverlay"/>
|
<channel id="textOverlay" typeId="textOverlay"/>
|
||||||
<channel id="activateAlarmOutput" typeId="activateAlarmOutput"/>
|
<channel id="activateAlarmOutput" typeId="activateAlarmOutput"/>
|
||||||
<channel id="doorBell" typeId="doorBell"/>
|
<channel id="doorBell" typeId="doorBell"/>
|
||||||
<channel id="enableRecordings" typeId="enableRecordings"/>
|
<channel id="enableRecordings" typeId="enableRecordings"/>
|
||||||
<channel id="enableFTP" typeId="enableFTP"/>
|
<channel id="enableFTP" typeId="enableFTP"/>
|
||||||
|
<channel id="enableEmail" typeId="enableEmail"/>
|
||||||
|
<channel id="enablePush" typeId="enablePush"/>
|
||||||
</channels>
|
</channels>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<property name="thingTypeVersion">1</property>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<config-description>
|
<config-description>
|
||||||
|
|
||||||
<parameter-group name="Settings">
|
<parameter-group name="Settings">
|
||||||
@ -2948,6 +2964,13 @@
|
|||||||
<category>Light</category>
|
<category>Light</category>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="whiteLED" advanced="true">
|
||||||
|
<item-type>Dimmer</item-type>
|
||||||
|
<label>White LED</label>
|
||||||
|
<description>Turn the visible white LED ON and OFF and if supported 0-100% dimming.</description>
|
||||||
|
<category>Light</category>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
<channel-type id="enablePrivacyMode" advanced="true">
|
<channel-type id="enablePrivacyMode" advanced="true">
|
||||||
<item-type>Switch</item-type>
|
<item-type>Switch</item-type>
|
||||||
<label>Enable Privacy Mode</label>
|
<label>Enable Privacy Mode</label>
|
||||||
@ -2966,12 +2989,30 @@
|
|||||||
<description>Turn the FTP features of the camera on and off</description>
|
<description>Turn the FTP features of the camera on and off</description>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="enableEmail" advanced="true">
|
||||||
|
<item-type>Switch</item-type>
|
||||||
|
<label>Enable Email</label>
|
||||||
|
<description>Turn the email features of the camera on or off</description>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="enablePush" advanced="true">
|
||||||
|
<item-type>Switch</item-type>
|
||||||
|
<label>Enable Push</label>
|
||||||
|
<description>Turn the push notification features of the camera on or off</description>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
<channel-type id="autoLED" advanced="true">
|
<channel-type id="autoLED" advanced="true">
|
||||||
<item-type>Switch</item-type>
|
<item-type>Switch</item-type>
|
||||||
<label>Auto LED</label>
|
<label>Auto LED</label>
|
||||||
<description>Turn the automatic mode for the LED ON and OFF.</description>
|
<description>Turn the automatic mode for the LED ON and OFF.</description>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="autoWhiteLED" advanced="true">
|
||||||
|
<item-type>Switch</item-type>
|
||||||
|
<label>Auto White LED</label>
|
||||||
|
<description>Turn the automatic mode for the visible white LED ON or OFF.</description>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
<channel-type id="externalLight" advanced="true">
|
<channel-type id="externalLight" advanced="true">
|
||||||
<item-type>Switch</item-type>
|
<item-type>Switch</item-type>
|
||||||
<label>External Light</label>
|
<label>External Light</label>
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||||
|
<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
|
||||||
|
xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
|
||||||
|
|
||||||
|
<thing-type uid="ipcamera:reolink">
|
||||||
|
<instruction-set targetVersion="1">
|
||||||
|
<add-channel id="whiteLED">
|
||||||
|
<type>ipcamera:whiteLED</type>
|
||||||
|
</add-channel>
|
||||||
|
<add-channel id="autoWhiteLED">
|
||||||
|
<type>ipcamera:autoWhiteLED</type>
|
||||||
|
</add-channel>
|
||||||
|
<add-channel id="enableEmail">
|
||||||
|
<type>ipcamera:enableEmail</type>
|
||||||
|
</add-channel>
|
||||||
|
<add-channel id="enablePush">
|
||||||
|
<type>ipcamera:enablePush</type>
|
||||||
|
</add-channel>
|
||||||
|
</instruction-set>
|
||||||
|
</thing-type>
|
||||||
|
|
||||||
|
<thing-type uid="ipcamera:dahua">
|
||||||
|
<instruction-set targetVersion="1">
|
||||||
|
<add-channel id="whiteLED">
|
||||||
|
<type>ipcamera:whiteLED</type>
|
||||||
|
</add-channel>
|
||||||
|
<add-channel id="autoWhiteLED">
|
||||||
|
<type>ipcamera:autoWhiteLED</type>
|
||||||
|
</add-channel>
|
||||||
|
</instruction-set>
|
||||||
|
</thing-type>
|
||||||
|
|
||||||
|
</update:update-descriptions>
|
Loading…
Reference in New Issue
Block a user