]> git.basschouten.com Git - openhab-addons.git/blob
2cde80aae1bd0c8d4bdf4b4e2c7f822025e1613b
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.ipcamera.internal;
14
15 import static org.openhab.binding.ipcamera.internal.IpCameraBindingConstants.*;
16
17 import java.util.ArrayList;
18 import java.util.List;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.ipcamera.internal.ReolinkState.GetAbilityResponse;
23 import org.openhab.binding.ipcamera.internal.ReolinkState.GetAiStateResponse;
24 import org.openhab.binding.ipcamera.internal.handler.IpCameraHandler;
25 import org.openhab.core.library.types.OnOffType;
26 import org.openhab.core.library.types.PercentType;
27 import org.openhab.core.library.types.StringType;
28 import org.openhab.core.thing.ChannelUID;
29 import org.openhab.core.types.Command;
30 import org.openhab.core.types.RefreshType;
31 import org.openhab.core.types.UnDefType;
32
33 import com.google.gson.Gson;
34 import com.google.gson.JsonParseException;
35
36 import io.netty.channel.ChannelDuplexHandler;
37 import io.netty.channel.ChannelHandlerContext;
38 import io.netty.util.ReferenceCountUtil;
39
40 /**
41  * The {@link ReolinkHandler} is responsible for handling commands, which are
42  * sent to one of the channels.
43  *
44  * @author Matthew Skinner - Initial contribution
45  */
46
47 @NonNullByDefault
48 public class ReolinkHandler extends ChannelDuplexHandler {
49     protected final Gson gson = new Gson();
50     private IpCameraHandler ipCameraHandler;
51     private String requestUrl = "Empty";
52
53     public ReolinkHandler(IpCameraHandler thingHandler) {
54         ipCameraHandler = thingHandler;
55     }
56
57     public void setURL(String url) {
58         requestUrl = url;
59     }
60
61     // This handles the incoming http replies back from the camera.
62     @Override
63     public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object msg) throws Exception {
64         if (msg == null || ctx == null) {
65             return;
66         }
67         try {
68             String content = msg.toString();
69             ipCameraHandler.logger.trace("HTTP Result from {} contains \t:{}:", requestUrl, content);
70             int afterCommand = requestUrl.indexOf("&");
71             String cutDownURL;
72             if (afterCommand < 0) {
73                 cutDownURL = requestUrl;
74             } else {
75                 cutDownURL = requestUrl.substring(0, afterCommand);
76             }
77             switch (cutDownURL) {// Use a cutdown URL as we can not use variables in a switch()
78                 case "/api.cgi?cmd=Login":
79                     ipCameraHandler.reolinkAuth = "&token=" + Helper.searchString(content, "\"name\" : \"");
80                     if (ipCameraHandler.reolinkAuth.length() > 7) {
81                         ipCameraHandler.logger.debug("Your Reolink camera gave a login:{}",
82                                 ipCameraHandler.reolinkAuth);
83                         ipCameraHandler.snapshotUri = "/cgi-bin/api.cgi?cmd=Snap&channel="
84                                 + ipCameraHandler.cameraConfig.getNvrChannel() + "&rs=openHAB"
85                                 + ipCameraHandler.reolinkAuth;
86                         // admin user in case username in config is a restricted user account. This may cause channels
87                         // to be removed due to restricted user, causing missing channels to be falsely reported as a
88                         // bug.
89                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetAbility" + ipCameraHandler.reolinkAuth,
90                                 "[{ \"cmd\":\"GetAbility\", \"param\":{ \"User\":{ \"userName\":\"admin\" }}}]");
91                     } else {
92                         ipCameraHandler.logger.info("Your Reolink camera gave a bad login response:{}", content);
93                     }
94                     break;
95                 case "/api.cgi?cmd=GetAbility": // Used to check what channels the camera supports
96                     List<org.openhab.core.thing.Channel> removeChannels = new ArrayList<>();
97                     org.openhab.core.thing.Channel channel = null;
98                     try {
99                         GetAbilityResponse[] getAbilityResponse = gson.fromJson(content, GetAbilityResponse[].class);
100                         if (getAbilityResponse == null) {
101                             return;
102                         }
103                         if (getAbilityResponse[0].value == null || getAbilityResponse[0].value.ability == null) {
104                             ipCameraHandler.logger.warn("The GetAbilityResponse could not be parsed: {}",
105                                     getAbilityResponse[0].error.detail);
106                             return;
107                         }
108                         ipCameraHandler.reolinkScheduleVersion = getAbilityResponse[0].value.ability.scheduleVersion.ver;
109                         if (getAbilityResponse[0].value.ability.supportFtpEnable == null
110                                 || getAbilityResponse[0].value.ability.supportFtpEnable.permit == 0) {
111                             ipCameraHandler.logger.debug("Camera has no Enable FTP support.");
112                             channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_FTP);
113                             if (channel != null) {
114                                 removeChannels.add(channel);
115                             }
116                         }
117                         if (getAbilityResponse[0].value.ability.supportRecordEnable == null
118                                 || getAbilityResponse[0].value.ability.supportRecordEnable.permit == 0) {
119                             ipCameraHandler.logger.debug("Camera has no enable recording support.");
120                             channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_RECORDINGS);
121                             if (channel != null) {
122                                 removeChannels.add(channel);
123                             }
124                         }
125                         if (getAbilityResponse[0].value.ability.abilityChn[0].supportAiDogCat == null
126                                 || getAbilityResponse[0].value.ability.abilityChn[0].supportAiDogCat.permit == 0) {
127                             ipCameraHandler.logger.debug("Camera has no AiDogCat support.");
128                             channel = ipCameraHandler.getThing().getChannel(CHANNEL_ANIMAL_ALARM);
129                             if (channel != null) {
130                                 removeChannels.add(channel);
131                             }
132                         }
133                         if (getAbilityResponse[0].value.ability.abilityChn[0].supportAiPeople == null
134                                 || getAbilityResponse[0].value.ability.abilityChn[0].supportAiPeople.permit == 0) {
135                             ipCameraHandler.logger.debug("Camera has no AiPeople support.");
136                             channel = ipCameraHandler.getThing().getChannel(CHANNEL_HUMAN_ALARM);
137                             if (channel != null) {
138                                 removeChannels.add(channel);
139                             }
140                         }
141                         if (getAbilityResponse[0].value.ability.abilityChn[0].supportAiVehicle == null
142                                 || getAbilityResponse[0].value.ability.abilityChn[0].supportAiVehicle.permit == 0) {
143                             ipCameraHandler.logger.debug("Camera has no AiVehicle support.");
144                             channel = ipCameraHandler.getThing().getChannel(CHANNEL_CAR_ALARM);
145                             if (channel != null) {
146                                 removeChannels.add(channel);
147                             }
148                         }
149                         if (getAbilityResponse[0].value.ability.supportEmailEnable == null
150                                 || getAbilityResponse[0].value.ability.supportEmailEnable.permit == 0) {
151                             ipCameraHandler.logger.debug("Camera has no EmailEnable support.");
152                             channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_EMAIL);
153                             if (channel != null) {
154                                 removeChannels.add(channel);
155                             }
156                         }
157                         if (getAbilityResponse[0].value.ability.push == null
158                                 || getAbilityResponse[0].value.ability.push.permit == 0) {
159                             ipCameraHandler.logger.debug("Camera has no Push support.");
160                             channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_PUSH);
161                             if (channel != null) {
162                                 removeChannels.add(channel);
163                             }
164                         }
165                         if (getAbilityResponse[0].value.ability.supportAudioAlarm == null
166                                 || getAbilityResponse[0].value.ability.supportAudioAlarm.permit == 0) {
167                             ipCameraHandler.logger.debug("Camera has no AudioAlarm support.");
168                             channel = ipCameraHandler.getThing().getChannel(CHANNEL_AUDIO_ALARM);
169                             if (channel != null) {
170                                 removeChannels.add(channel);
171                             }
172                         }
173                         if (getAbilityResponse[0].value.ability.supportAudioAlarmEnable == null
174                                 || getAbilityResponse[0].value.ability.supportAudioAlarmEnable.permit == 0) {
175                             ipCameraHandler.logger.debug("Camera has no AudioAlarm support.");
176                             channel = ipCameraHandler.getThing().getChannel(CHANNEL_THRESHOLD_AUDIO_ALARM);
177                             if (channel != null) {
178                                 removeChannels.add(channel);
179                             }
180                             channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_AUDIO_ALARM);
181                             if (channel != null) {
182                                 removeChannels.add(channel);
183                             }
184                         }
185                         if (getAbilityResponse[0].value.ability.abilityChn[0].supportAiFace == null
186                                 || getAbilityResponse[0].value.ability.abilityChn[0].supportAiFace.permit == 0) {
187                             ipCameraHandler.logger.debug("Camera has no AiFace support.");
188                             channel = ipCameraHandler.getThing().getChannel(CHANNEL_FACE_DETECTED);
189                             if (channel != null) {
190                                 removeChannels.add(channel);
191                             }
192                         }
193                     } catch (JsonParseException e) {
194                         ipCameraHandler.logger.warn("API command GetAbility may not be supported by the camera");
195                     }
196                     if (channel != null) {
197                         ipCameraHandler.removeChannels(removeChannels);
198                     }
199                     break;
200                 case "/api.cgi?cmd=GetAiState":
201                     ipCameraHandler.setChannelState(CHANNEL_LAST_EVENT_DATA, new StringType(content));
202                     try {
203                         GetAiStateResponse[] aiResponse = gson.fromJson(content, GetAiStateResponse[].class);
204                         if (aiResponse == null) {
205                             return;
206                         }
207                         if (aiResponse[0].value == null) {
208                             ipCameraHandler.logger.debug("The GetAiStateResponse could not be parsed: {}",
209                                     aiResponse[0].error.detail);
210                             return;
211                         }
212                         if (aiResponse[0].value.dogCat.alarmState == 1) {
213                             ipCameraHandler.setChannelState(CHANNEL_ANIMAL_ALARM, OnOffType.ON);
214                         } else {
215                             ipCameraHandler.setChannelState(CHANNEL_ANIMAL_ALARM, OnOffType.OFF);
216                         }
217                         if (aiResponse[0].value.face.alarmState == 1) {
218                             ipCameraHandler.setChannelState(CHANNEL_FACE_DETECTED, OnOffType.ON);
219                         } else {
220                             ipCameraHandler.setChannelState(CHANNEL_FACE_DETECTED, OnOffType.OFF);
221                         }
222                         if (aiResponse[0].value.people.alarmState == 1) {
223                             ipCameraHandler.setChannelState(CHANNEL_HUMAN_ALARM, OnOffType.ON);
224                         } else {
225                             ipCameraHandler.setChannelState(CHANNEL_HUMAN_ALARM, OnOffType.OFF);
226                         }
227                         if (aiResponse[0].value.vehicle.alarmState == 1) {
228                             ipCameraHandler.setChannelState(CHANNEL_CAR_ALARM, OnOffType.ON);
229                         } else {
230                             ipCameraHandler.setChannelState(CHANNEL_CAR_ALARM, OnOffType.OFF);
231                         }
232                     } catch (JsonParseException e) {
233                         ipCameraHandler.logger.debug("API GetAiState is not supported by the camera.");
234                     }
235                     break;
236                 case "/api.cgi?cmd=GetAudioAlarm":
237                 case "/api.cgi?cmd=GetAudioAlarmV20":
238                     if (content.contains("\"enable\" : 1")) {
239                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON);
240                     } else {
241                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.OFF);
242                     }
243                     break;
244                 case "/api.cgi?cmd=GetIrLights":
245                     if (content.contains("\"state\" : 0")) {
246                         ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.OFF);
247                     } else {
248                         ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.ON);
249                     }
250                     break;
251                 case "/api.cgi?cmd=GetMdAlarm":
252                     if (content.contains("00000")) {
253                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.OFF);
254                     } else {
255                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON);
256                     }
257                     break;
258                 case "/api.cgi?cmd=GetMdState":
259                     if (content.contains("\"state\" : 0")) {
260                         ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.OFF);
261                     } else {
262                         ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.ON);
263                     }
264                     break;
265                 case "/api.cgi?cmd=GetEmail":
266                 case "/api.cgi?cmd=GetEmailV20":
267                     if (content.contains("\"enable\" : 0")) {
268                         ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.OFF);
269                     } else {
270                         ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.ON);
271                     }
272                     break;
273                 case "/api.cgi?cmd=GetPush":
274                 case "/api.cgi?cmd=GetPushV20":
275                     if (content.contains("\"enable\" : 0")) {
276                         ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.OFF);
277                     } else {
278                         ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.ON);
279                     }
280                     break;
281                 case "/api.cgi?cmd=GetWhiteLed":
282                     if (content.contains("\"state\" : 0")) {
283                         ipCameraHandler.setChannelState(CHANNEL_WHITE_LED, OnOffType.OFF);
284                     } else {
285                         ipCameraHandler.setChannelState(CHANNEL_WHITE_LED, OnOffType.ON);
286                     }
287                     break;
288                 case "/cgi-bin/api.cgi?cmd=Snap":
289                     break;
290                 default:
291                     if (!cutDownURL.contains("cmd=Set")) {// ignore the responses from all Setxxxxx commands
292                         ipCameraHandler.logger.warn(
293                                 "URL {} is not handled currently by the binding, please report this message",
294                                 cutDownURL);
295                     }
296             }
297         } finally {
298             ReferenceCountUtil.release(msg);
299         }
300     }
301
302     // This handles the commands that come from the openHAB event bus.
303     public void handleCommand(ChannelUID channelUID, Command command) {
304         if (command instanceof RefreshType) {
305             switch (channelUID.getId()) {
306                 case CHANNEL_ENABLE_MOTION_ALARM:
307                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetMdAlarm" + ipCameraHandler.reolinkAuth,
308                             "[{\"cmd\": \"GetMdAlarm\", \"action\": 1,\"param\": {\"channel\": "
309                                     + ipCameraHandler.cameraConfig.getNvrChannel() + "}}]");
310                     break;
311                 case CHANNEL_ENABLE_AUDIO_ALARM:
312                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetAudioAlarmV20" + ipCameraHandler.reolinkAuth,
313                             "[{ \"cmd\":\"GetAudioAlarmV20\", \"action\":1, \"param\":{ \"channel\": 0}}]");
314                     break;
315                 case CHANNEL_AUTO_LED:
316                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetIrLights" + ipCameraHandler.reolinkAuth,
317                             "[{ \"cmd\":\"GetIrLights\"}]");
318                     break;
319                 case CHANNEL_AUTO_WHITE_LED:
320                 case CHANNEL_WHITE_LED:
321                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetWhiteLed" + ipCameraHandler.reolinkAuth,
322                             "[{\"cmd\": \"GetWhiteLed\",\"action\": 0,\"param\": {\"channel\": "
323                                     + ipCameraHandler.cameraConfig.getNvrChannel() + "}}]");
324                     break;
325                 case CHANNEL_ENABLE_EMAIL:
326                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetEmailV20" + ipCameraHandler.reolinkAuth,
327                             "[{ \"cmd\":\"GetEmailV20\"}]");
328                     break;
329                 case CHANNEL_ENABLE_PUSH:
330                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetPushV20" + ipCameraHandler.reolinkAuth,
331                             "[{ \"cmd\":\"GetPush\"}]");
332                     break;
333             }
334             return;
335         } // end of "REFRESH"
336         switch (channelUID.getId()) {
337             case CHANNEL_ACTIVATE_ALARM_OUTPUT: // cameras built in siren
338                 if (OnOffType.ON.equals(command)) {
339                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=AudioAlarmPlay" + ipCameraHandler.reolinkAuth,
340                             "[{\"cmd\": \"AudioAlarmPlay\", \"param\": {\"alarm_mode\": \"manul\", \"manual_switch\": 1, \"channel\": "
341                                     + ipCameraHandler.cameraConfig.getNvrChannel() + " }}]");
342                 } else {
343                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=AudioAlarmPlay" + ipCameraHandler.reolinkAuth,
344                             "[{\"cmd\": \"AudioAlarmPlay\", \"param\": {\"alarm_mode\": \"manul\", \"manual_switch\": 0, \"channel\": "
345                                     + ipCameraHandler.cameraConfig.getNvrChannel() + " }}]");
346                 }
347                 break;
348             case CHANNEL_AUTO_LED:
349                 if (OnOffType.ON.equals(command)) {
350                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetIrLights" + ipCameraHandler.reolinkAuth,
351                             "[{\"cmd\": \"SetIrLights\",\"action\": 0,\"param\": {\"IrLights\": {\"channel\": "
352                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"state\": \"Auto\"}}}]");
353                 } else {
354                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetIrLights" + ipCameraHandler.reolinkAuth,
355                             "[{\"cmd\": \"SetIrLights\",\"action\": 0,\"param\": {\"IrLights\": {\"channel\": "
356                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"state\": \"Off\"}}}]");
357                 }
358                 break;
359             case CHANNEL_AUTO_WHITE_LED:
360                 if (OnOffType.ON.equals(command)) {
361                     ipCameraHandler.setChannelState(CHANNEL_WHITE_LED, UnDefType.UNDEF);
362                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
363                             "[{\"cmd\":\"SetWhiteLed\",\"param\":{\"WhiteLed\":{\"channel\": "
364                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ", \"mode\": 1}}}]");
365                 } else {
366                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
367                             "[{\"cmd\":\"SetWhiteLed\",\"param\":{\"WhiteLed\":{\"channel\": "
368                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ", \"mode\": 0}}}]");
369                 }
370                 break;
371             case CHANNEL_ENABLE_AUDIO_ALARM:
372                 if (OnOffType.ON.equals(command)) {
373                     if (ipCameraHandler.reolinkScheduleVersion == 1) {
374                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarmV20" + ipCameraHandler.reolinkAuth,
375                                 "[{\"cmd\":\"SetAudioAlarmV20\",\"param\":{\"Audio\" : {\"enable\" : 1}}}]");
376                     } else {
377                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarm" + ipCameraHandler.reolinkAuth,
378                                 "[{\"cmd\": \" SetAudioAlarm\",\"param\": {\"Audio\": {\"schedule\": {\"enable\": 1,\"table\": \"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\"}}}}]");
379                     }
380                 } else {
381                     if (ipCameraHandler.reolinkScheduleVersion == 1) {
382                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarmV20" + ipCameraHandler.reolinkAuth,
383                                 "[{\"cmd\":\"SetAudioAlarmV20\",\"param\":{\"Audio\" : {\"enable\" : 0}}}]");
384
385                     } else {
386                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarm" + ipCameraHandler.reolinkAuth,
387                                 "[{\"cmd\": \" SetAudioAlarm\",\"param\": {\"Audio\": {\"schedule\": {\"enable\": 0,\"table\": \"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\"}}}}]");
388                     }
389                 }
390                 break;
391             case CHANNEL_ENABLE_FTP:
392                 if (OnOffType.ON.equals(command)) {
393                     if (ipCameraHandler.reolinkScheduleVersion == 1) {
394                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtpV20" + ipCameraHandler.reolinkAuth,
395                                 "[{\"cmd\":\"SetFtpV20\",\"param\":{\"Ftp\" : {\"enable\" : 1}}}]");
396
397                     } else {
398                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtp" + ipCameraHandler.reolinkAuth,
399                                 "[{\"cmd\":\"SetFtp\",\"param\":{\"Ftp\" : {\"schedule\" : {\"enable\" : 1}}}}]");
400                     }
401                 } else {
402                     if (ipCameraHandler.reolinkScheduleVersion == 1) {
403                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtpV20" + ipCameraHandler.reolinkAuth,
404                                 "[{\"cmd\":\"SetFtpV20\",\"param\":{\"Ftp\" : {\"enable\" : 0}}}]");
405                     } else {
406                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtp" + ipCameraHandler.reolinkAuth,
407                                 "[{\"cmd\":\"SetFtp\",\"param\":{\"Ftp\" : {\"schedule\" : {\"enable\" : 0}}}}]");
408                     }
409                 }
410                 break;
411             case CHANNEL_ENABLE_EMAIL:
412                 if (OnOffType.ON.equals(command)) {
413                     if (ipCameraHandler.reolinkScheduleVersion == 1) {
414                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetEmailV20" + ipCameraHandler.reolinkAuth,
415                                 "[{\"cmd\":\"SetEmailV20\",\"param\":{\"Email\" : {\"enable\" : 1}}}]");
416                     } else {
417                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetEmail" + ipCameraHandler.reolinkAuth,
418                                 "[{\"cmd\":\"SetEmail\",\"param\":{\"Email\" : {\"schedule\" : {\"enable\" : 1}}}}]");
419                     }
420                 } else {
421                     if (ipCameraHandler.reolinkScheduleVersion == 1) {
422                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetEmailV20" + ipCameraHandler.reolinkAuth,
423                                 "[{\"cmd\":\"SetEmailV20\",\"param\":{\"Email\" : {\"enable\" : 0}}}]");
424                     } else {
425                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetEmail" + ipCameraHandler.reolinkAuth,
426                                 "[{\"cmd\":\"SetEmail\",\"param\":{\"Email\" : {\"schedule\" : {\"enable\" : 0}}}}]");
427                     }
428                 }
429                 break;
430             case CHANNEL_ENABLE_PUSH:
431                 if (OnOffType.ON.equals(command)) {
432                     if (ipCameraHandler.reolinkScheduleVersion == 1) {
433                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetPushV20" + ipCameraHandler.reolinkAuth,
434                                 "[{\"cmd\":\"SetPushV20\",\"param\":{\"Push\":{\"enable\":1}}}]");
435                     } else {
436                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetPush" + ipCameraHandler.reolinkAuth,
437                                 "[{\"cmd\":\"SetPush\",\"param\":{\"Push\" : {\"schedule\" : {\"enable\" : 1}}}}]");
438                     }
439                 } else {
440                     if (ipCameraHandler.reolinkScheduleVersion == 1) {
441                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetPushV20" + ipCameraHandler.reolinkAuth,
442                                 "[{\"cmd\":\"SetPushV20\",\"param\":{\"Push\":{\"enable\":0}}}]");
443                     } else {
444                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetPush" + ipCameraHandler.reolinkAuth,
445                                 "[{\"cmd\":\"SetPush\",\"param\":{\"Push\" : {\"schedule\" : {\"enable\" : 0}}}}]");
446                     }
447                 }
448                 break;
449             case CHANNEL_ENABLE_LED:
450                 ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.OFF);
451                 if (OnOffType.OFF.equals(command) || PercentType.ZERO.equals(command)) {
452                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetIrLights" + ipCameraHandler.reolinkAuth,
453                             "[{\"cmd\": \"SetIrLights\",\"action\": 0,\"param\": {\"IrLights\": {\"channel\": "
454                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"state\": \"Off\"}}}]");
455                 } else if (OnOffType.ON.equals(command) || command instanceof PercentType percentCommand) {
456                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetIrLights" + ipCameraHandler.reolinkAuth,
457                             "[{\"cmd\": \"SetIrLights\",\"action\": 0,\"param\": {\"IrLights\": {\"channel\": "
458                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"state\": \"On\"}}}]");
459                 } else {
460                     ipCameraHandler.logger.warn("Unsupported command sent to enableLED channel");
461                 }
462             case CHANNEL_ENABLE_MOTION_ALARM:
463                 if (OnOffType.ON.equals(command)) {
464                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetMdAlarm" + ipCameraHandler.reolinkAuth);
465                 } else {
466                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetMdAlarm" + ipCameraHandler.reolinkAuth);
467                 }
468                 break;
469             case CHANNEL_ENABLE_RECORDINGS:
470                 if (OnOffType.ON.equals(command)) {
471                     if (ipCameraHandler.reolinkScheduleVersion == 1) {
472                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRecV20" + ipCameraHandler.reolinkAuth,
473                                 "[{\"cmd\":\"SetRecV20\",\"param\":{\"Rec\":{\"enable\":1}}}]");
474
475                     } else {
476                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRec" + ipCameraHandler.reolinkAuth,
477                                 "[{\"cmd\":\"SetRec\",\"param\":{\"Rec\" : {\"channel\" : "
478                                         + ipCameraHandler.cameraConfig.getNvrChannel()
479                                         + ",\"schedule\" : {\"enable\" : 1}}}}]");
480                     }
481                 } else {
482                     if (ipCameraHandler.reolinkScheduleVersion == 1) {
483                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRecV20" + ipCameraHandler.reolinkAuth,
484                                 "[{\"cmd\":\"SetRecV20\",\"param\":{\"Rec\":{\"enable\":0}}}]");
485
486                     } else {
487                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRec" + ipCameraHandler.reolinkAuth,
488                                 "[{\"cmd\":\"SetRec\",\"param\":{\"Rec\" : {\"channel\" : "
489                                         + ipCameraHandler.cameraConfig.getNvrChannel()
490                                         + ",\"schedule\" : {\"enable\" : 0}}}}]");
491                     }
492                 }
493                 break;
494             case CHANNEL_WHITE_LED:
495                 ipCameraHandler.setChannelState(CHANNEL_AUTO_WHITE_LED, OnOffType.OFF);
496                 if (OnOffType.OFF.equals(command) || PercentType.ZERO.equals(command)) {
497                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
498                             "[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 0,\"channel\": "
499                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 0}}}]");
500                 } else if (OnOffType.ON.equals(command)) {
501                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
502                             "[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 1,\"channel\": "
503                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 2}}}]");
504                 } else if (command instanceof PercentType percentCommand) {
505                     int value = percentCommand.toBigDecimal().intValue();
506                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
507                             "[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 1,\"channel\": "
508                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 2,\"bright\": " + value
509                                     + "}}}]");
510                 }
511         }
512     }
513
514     // If a camera does not need to poll a request as often as snapshots, it can be
515     // added here. Binding steps through the list.
516     public List<String> getLowPriorityRequests() {
517         return List.of();
518     }
519 }