]> git.basschouten.com Git - openhab-addons.git/blob
3dffcf72572d9110e50f22258f7d1e8d56125b98
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.GetAiStateResponse;
23 import org.openhab.binding.ipcamera.internal.handler.IpCameraHandler;
24 import org.openhab.core.library.types.OnOffType;
25 import org.openhab.core.library.types.PercentType;
26 import org.openhab.core.library.types.StringType;
27 import org.openhab.core.thing.ChannelUID;
28 import org.openhab.core.types.Command;
29 import org.openhab.core.types.RefreshType;
30
31 import com.google.gson.Gson;
32
33 import io.netty.channel.ChannelDuplexHandler;
34 import io.netty.channel.ChannelHandlerContext;
35 import io.netty.util.ReferenceCountUtil;
36
37 /**
38  * The {@link ReolinkHandler} is responsible for handling commands, which are
39  * sent to one of the channels.
40  *
41  * @author Matthew Skinner - Initial contribution
42  */
43
44 @NonNullByDefault
45 public class ReolinkHandler extends ChannelDuplexHandler {
46     protected final Gson gson = new Gson();
47     private IpCameraHandler ipCameraHandler;
48     private String requestUrl = "Empty";
49
50     public ReolinkHandler(IpCameraHandler thingHandler) {
51         ipCameraHandler = thingHandler;
52     }
53
54     public void setURL(String url) {
55         requestUrl = url;
56     }
57
58     // This handles the incoming http replies back from the camera.
59     @Override
60     public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object msg) throws Exception {
61         if (msg == null || ctx == null) {
62             return;
63         }
64         try {
65             String content = msg.toString();
66             ipCameraHandler.logger.trace("HTTP Result from {} contains \t:{}:", requestUrl, content);
67             int afterCommand = requestUrl.indexOf("&");
68             String cutDownURL;
69             if (afterCommand < 0) {
70                 cutDownURL = requestUrl;
71             } else {
72                 cutDownURL = requestUrl.substring(0, afterCommand);
73             }
74             switch (cutDownURL) {// Use a cutdown URL as we can not use variables in a switch()
75                 case "/api.cgi?cmd=Login":
76                     ipCameraHandler.reolinkAuth = "&token=" + Helper.searchString(content, "\"name\" : \"");
77                     if (ipCameraHandler.reolinkAuth.length() > 7) {
78                         ipCameraHandler.logger.debug("Your Reolink camera gave a login:{}",
79                                 ipCameraHandler.reolinkAuth);
80                         ipCameraHandler.snapshotUri = "/cgi-bin/api.cgi?cmd=Snap&channel="
81                                 + ipCameraHandler.cameraConfig.getNvrChannel() + "&rs=openHAB"
82                                 + ipCameraHandler.reolinkAuth;
83                         ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetAbility" + ipCameraHandler.reolinkAuth,
84                                 "[{ \"cmd\":\"GetAbility\", \"param\":{ \"User\":{ \"userName\":\""
85                                         + ipCameraHandler.cameraConfig.getUser() + "\" }}}]");
86                     } else {
87                         ipCameraHandler.logger.info("Your Reolink camera gave a bad login response:{}", content);
88                     }
89                     break;
90                 case "/api.cgi?cmd=GetAbility": // Used to check what channels the camera supports
91                     List<org.openhab.core.thing.Channel> removeChannels = new ArrayList<>();
92                     org.openhab.core.thing.Channel channel;
93                     if (content.contains("\"supportFtpEnable\": { \"permit\": 0")) {
94                         ipCameraHandler.logger.debug("Camera has no Enable FTP support.");
95                         channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_FTP);
96                         if (channel != null) {
97                             removeChannels.add(channel);
98                         }
99                     }
100                     if (content.contains("\"supportRecordEnable\": { \"permit\": 0")) {
101                         ipCameraHandler.logger.debug("Camera has no enable recording support.");
102                         channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_RECORDINGS);
103                         if (channel != null) {
104                             removeChannels.add(channel);
105                         }
106                     }
107                     if (content.contains("\"floodLight\": { \"permit\": 0")) {
108                         ipCameraHandler.logger.debug("Camera has no Flood light support.");
109                         channel = ipCameraHandler.getThing().getChannel(CHANNEL_ENABLE_LED);
110                         if (channel != null) {
111                             removeChannels.add(channel);
112                         }
113                     }
114                     ipCameraHandler.removeChannels(removeChannels);
115                     break;
116                 case "/api.cgi?cmd=GetAiState":
117                     ipCameraHandler.setChannelState(CHANNEL_LAST_EVENT_DATA, new StringType(content));
118                     GetAiStateResponse[] aiResponse = gson.fromJson(content, GetAiStateResponse[].class);
119                     if (aiResponse == null) {
120                         ipCameraHandler.logger.debug("The GetAiStateResponse could not be parsed");
121                         return;
122                     }
123                     if (aiResponse[0].value.dog_cat != null) {
124                         if (aiResponse[0].value.dog_cat.alarm_state == 1) {
125                             ipCameraHandler.setChannelState(CHANNEL_ANIMAL_ALARM, OnOffType.ON);
126                         } else {
127                             ipCameraHandler.setChannelState(CHANNEL_ANIMAL_ALARM, OnOffType.OFF);
128                         }
129                     }
130                     if (aiResponse[0].value.face.alarm_state == 1) {
131                         ipCameraHandler.setChannelState(CHANNEL_FACE_DETECTED, OnOffType.ON);
132                     } else {
133                         ipCameraHandler.setChannelState(CHANNEL_FACE_DETECTED, OnOffType.OFF);
134                     }
135                     if (aiResponse[0].value.people.alarm_state == 1) {
136                         ipCameraHandler.setChannelState(CHANNEL_HUMAN_ALARM, OnOffType.ON);
137                     } else {
138                         ipCameraHandler.setChannelState(CHANNEL_HUMAN_ALARM, OnOffType.OFF);
139                     }
140                     if (aiResponse[0].value.vehicle.alarm_state == 1) {
141                         ipCameraHandler.setChannelState(CHANNEL_CAR_ALARM, OnOffType.ON);
142                     } else {
143                         ipCameraHandler.setChannelState(CHANNEL_CAR_ALARM, OnOffType.OFF);
144                     }
145                     break;
146                 case "/api.cgi?cmd=GetAudioAlarmV20":
147                     if (content.contains("\"enable\" : 1")) {
148                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON);
149                     } else {
150                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.OFF);
151                     }
152                     break;
153                 case "/api.cgi?cmd=GetIrLights":
154                     if (content.contains("\"state\" : 0")) {
155                         ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.OFF);
156                     } else {
157                         ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.ON);
158                     }
159                     break;
160                 case "/api.cgi?cmd=GetMdState":
161                     if (content.contains("\"state\" : 0")) {
162                         ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.OFF);
163                     } else {
164                         ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.ON);
165                     }
166                     break;
167             }
168         } finally {
169             ReferenceCountUtil.release(msg);
170         }
171     }
172
173     // This handles the commands that come from the openHAB event bus.
174     public void handleCommand(ChannelUID channelUID, Command command) {
175         if (command instanceof RefreshType) {
176             switch (channelUID.getId()) {
177                 case CHANNEL_ENABLE_MOTION_ALARM:
178                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetMdState" + ipCameraHandler.reolinkAuth);
179                     break;
180                 case CHANNEL_ENABLE_AUDIO_ALARM:
181                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetAudioAlarmV20" + ipCameraHandler.reolinkAuth,
182                             "[{ \"cmd\":\"GetAudioAlarmV20\", \"action\":1, \"param\":{ \"channel\": 0}}]");
183                     break;
184                 case CHANNEL_AUTO_LED:
185                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetIrLights" + ipCameraHandler.reolinkAuth,
186                             "[{ \"cmd\":\"GetIrLights\"}]");
187                     break;
188             }
189             return;
190         } // end of "REFRESH"
191         switch (channelUID.getId()) {
192             case CHANNEL_ACTIVATE_ALARM_OUTPUT: // cameras built in siren
193                 if (OnOffType.ON.equals(command)) {
194                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=AudioAlarmPlay" + ipCameraHandler.reolinkAuth,
195                             "[{\"cmd\": \"AudioAlarmPlay\", \"param\": {\"alarm_mode\": \"manul\", \"manual_switch\": 1, \"channel\": "
196                                     + ipCameraHandler.cameraConfig.getNvrChannel() + " }}]");
197                 } else {
198                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=AudioAlarmPlay" + ipCameraHandler.reolinkAuth,
199                             "[{\"cmd\": \"AudioAlarmPlay\", \"param\": {\"alarm_mode\": \"manul\", \"manual_switch\": 0, \"channel\": "
200                                     + ipCameraHandler.cameraConfig.getNvrChannel() + " }}]");
201                 }
202                 break;
203             case CHANNEL_AUTO_LED:
204                 if (OnOffType.ON.equals(command)) {
205                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetIrLights" + ipCameraHandler.reolinkAuth,
206                             "[{\"cmd\": \"SetIrLights\",\"action\": 0,\"param\": {\"IrLights\": {\"channel\": "
207                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"state\": \"Auto\"}}}]");
208                 } else {
209                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetIrLights" + ipCameraHandler.reolinkAuth,
210                             "[{\"cmd\": \"SetIrLights\",\"action\": 0,\"param\": {\"IrLights\": {\"channel\": "
211                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"state\": \"Off\"}}}]");
212                 }
213                 break;
214             case CHANNEL_ENABLE_AUDIO_ALARM:
215                 if (OnOffType.ON.equals(command)) {
216                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarm" + ipCameraHandler.reolinkAuth,
217                             "[{\"cmd\": \" SetAudioAlarm\",\"param\": {\"Audio\": {\"schedule\": {\"enable\": 1,\"table\": \"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\"}}}}]");
218                 } else {
219                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarm" + ipCameraHandler.reolinkAuth,
220                             "[{\"cmd\": \" SetAudioAlarm\",\"param\": {\"Audio\": {\"schedule\": {\"enable\": 0,\"table\": \"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\"}}}}]");
221                 }
222                 break;
223             case CHANNEL_ENABLE_FTP:
224                 if (OnOffType.ON.equals(command)) {
225                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtp" + ipCameraHandler.reolinkAuth,
226                             "[{\"cmd\":\"SetFtp\",\"param\":{\"Rec\" : {\"channel\" : "
227                                     + ipCameraHandler.cameraConfig.getNvrChannel()
228                                     + ",\"schedule\" : {\"enable\" : 1}}}}]");
229                 } else {
230                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtp" + ipCameraHandler.reolinkAuth,
231                             "[{\"cmd\":\"SetFtp\",\"param\":{\"Rec\" : {\"channel\" : "
232                                     + ipCameraHandler.cameraConfig.getNvrChannel()
233                                     + ",\"schedule\" : {\"enable\" : 0}}}}]");
234                 }
235                 break;
236             case CHANNEL_ENABLE_LED:
237                 if (OnOffType.OFF.equals(command) || PercentType.ZERO.equals(command)) {
238                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
239                             "[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 0,\"channel\": "
240                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 1}}}]");
241                 } else if (OnOffType.ON.equals(command)) {
242                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
243                             "[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 1,\"channel\": "
244                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 1}}}]");
245                 } else if (command instanceof PercentType percentCommand) {
246                     int value = percentCommand.toBigDecimal().intValue();
247                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
248                             "[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 1,\"channel\": "
249                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 1,\"bright\": " + value
250                                     + "}}}]");
251                 }
252             case CHANNEL_ENABLE_MOTION_ALARM:
253                 if (OnOffType.ON.equals(command)) {
254                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetMdAlarm" + ipCameraHandler.reolinkAuth);
255                 } else {
256                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetMdAlarm" + ipCameraHandler.reolinkAuth);
257                 }
258                 break;
259             case CHANNEL_ENABLE_RECORDINGS:
260                 if (OnOffType.ON.equals(command)) {
261                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRec" + ipCameraHandler.reolinkAuth,
262                             "[{\"cmd\":\"SetRec\",\"param\":{\"Rec\" : {\"channel\" : "
263                                     + ipCameraHandler.cameraConfig.getNvrChannel()
264                                     + ",\"schedule\" : {\"enable\" : 1}}}}]");
265                 } else {
266                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRec" + ipCameraHandler.reolinkAuth,
267                             "[{\"cmd\":\"SetRec\",\"param\":{\"Rec\" : {\"channel\" : "
268                                     + ipCameraHandler.cameraConfig.getNvrChannel()
269                                     + ",\"schedule\" : {\"enable\" : 0}}}}]");
270                 }
271                 break;
272         }
273     }
274
275     // If a camera does not need to poll a request as often as snapshots, it can be
276     // added here. Binding steps through the list.
277     public List<String> getLowPriorityRequests() {
278         return List.of();
279     }
280 }