]> git.basschouten.com Git - openhab-addons.git/blob
2f582481f69174322840636c61df6f3e66294903
[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.alarm_state == 1) {
124                         ipCameraHandler.setChannelState(CHANNEL_ANIMAL_ALARM, OnOffType.ON);
125                     } else {
126                         ipCameraHandler.setChannelState(CHANNEL_ANIMAL_ALARM, OnOffType.OFF);
127                     }
128                     if (aiResponse[0].value.face.alarm_state == 1) {
129                         ipCameraHandler.setChannelState(CHANNEL_FACE_DETECTED, OnOffType.ON);
130                     } else {
131                         ipCameraHandler.setChannelState(CHANNEL_FACE_DETECTED, OnOffType.OFF);
132                     }
133                     if (aiResponse[0].value.people.alarm_state == 1) {
134                         ipCameraHandler.setChannelState(CHANNEL_HUMAN_ALARM, OnOffType.ON);
135                     } else {
136                         ipCameraHandler.setChannelState(CHANNEL_HUMAN_ALARM, OnOffType.OFF);
137                     }
138                     if (aiResponse[0].value.vehicle.alarm_state == 1) {
139                         ipCameraHandler.setChannelState(CHANNEL_CAR_ALARM, OnOffType.ON);
140                     } else {
141                         ipCameraHandler.setChannelState(CHANNEL_CAR_ALARM, OnOffType.OFF);
142                     }
143                     break;
144                 case "/api.cgi?cmd=GetAudioAlarmV20":
145                     if (content.contains("\"enable\" : 1")) {
146                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON);
147                     } else {
148                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.OFF);
149                     }
150                     break;
151                 case "/api.cgi?cmd=GetIrLights":
152                     if (content.contains("\"state\" : 0")) {
153                         ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.OFF);
154                     } else {
155                         ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.ON);
156                     }
157                     break;
158                 case "/api.cgi?cmd=GetMdState":
159                     if (content.contains("\"state\" : 0")) {
160                         ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.OFF);
161                     } else {
162                         ipCameraHandler.setChannelState(CHANNEL_MOTION_ALARM, OnOffType.ON);
163                     }
164                     break;
165             }
166         } finally {
167             ReferenceCountUtil.release(msg);
168         }
169     }
170
171     // This handles the commands that come from the openHAB event bus.
172     public void handleCommand(ChannelUID channelUID, Command command) {
173         if (command instanceof RefreshType) {
174             switch (channelUID.getId()) {
175                 case CHANNEL_ENABLE_MOTION_ALARM:
176                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetMdState" + ipCameraHandler.reolinkAuth);
177                     break;
178                 case CHANNEL_ENABLE_AUDIO_ALARM:
179                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetAudioAlarmV20" + ipCameraHandler.reolinkAuth,
180                             "[{ \"cmd\":\"GetAudioAlarmV20\", \"action\":1, \"param\":{ \"channel\": 0}}]");
181                     break;
182                 case CHANNEL_AUTO_LED:
183                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=GetIrLights" + ipCameraHandler.reolinkAuth,
184                             "[{ \"cmd\":\"GetIrLights\"}]");
185                     break;
186             }
187             return;
188         } // end of "REFRESH"
189         switch (channelUID.getId()) {
190             case CHANNEL_ACTIVATE_ALARM_OUTPUT: // cameras built in siren
191                 if (OnOffType.ON.equals(command)) {
192                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=AudioAlarmPlay" + ipCameraHandler.reolinkAuth,
193                             "[{\"cmd\": \"AudioAlarmPlay\", \"param\": {\"alarm_mode\": \"manul\", \"manual_switch\": 1, \"channel\": "
194                                     + ipCameraHandler.cameraConfig.getNvrChannel() + " }}]");
195                 } else {
196                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=AudioAlarmPlay" + ipCameraHandler.reolinkAuth,
197                             "[{\"cmd\": \"AudioAlarmPlay\", \"param\": {\"alarm_mode\": \"manul\", \"manual_switch\": 0, \"channel\": "
198                                     + ipCameraHandler.cameraConfig.getNvrChannel() + " }}]");
199                 }
200                 break;
201             case CHANNEL_AUTO_LED:
202                 if (OnOffType.ON.equals(command)) {
203                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetIrLights" + ipCameraHandler.reolinkAuth,
204                             "[{\"cmd\": \"SetIrLights\",\"action\": 0,\"param\": {\"IrLights\": {\"channel\": "
205                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"state\": \"Auto\"}}}]");
206                 } else {
207                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetIrLights" + ipCameraHandler.reolinkAuth,
208                             "[{\"cmd\": \"SetIrLights\",\"action\": 0,\"param\": {\"IrLights\": {\"channel\": "
209                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"state\": \"Off\"}}}]");
210                 }
211                 break;
212             case CHANNEL_ENABLE_AUDIO_ALARM:
213                 if (OnOffType.ON.equals(command)) {
214                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarm" + ipCameraHandler.reolinkAuth,
215                             "[{\"cmd\": \" SetAudioAlarm\",\"param\": {\"Audio\": {\"schedule\": {\"enable\": 1,\"table\": \"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\"}}}}]");
216                 } else {
217                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetAudioAlarm" + ipCameraHandler.reolinkAuth,
218                             "[{\"cmd\": \" SetAudioAlarm\",\"param\": {\"Audio\": {\"schedule\": {\"enable\": 0,\"table\": \"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\"}}}}]");
219                 }
220                 break;
221             case CHANNEL_ENABLE_FTP:
222                 if (OnOffType.ON.equals(command)) {
223                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtp" + ipCameraHandler.reolinkAuth,
224                             "[{\"cmd\":\"SetFtp\",\"param\":{\"Rec\" : {\"channel\" : "
225                                     + ipCameraHandler.cameraConfig.getNvrChannel()
226                                     + ",\"schedule\" : {\"enable\" : 1}}}}]");
227                 } else {
228                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetFtp" + ipCameraHandler.reolinkAuth,
229                             "[{\"cmd\":\"SetFtp\",\"param\":{\"Rec\" : {\"channel\" : "
230                                     + ipCameraHandler.cameraConfig.getNvrChannel()
231                                     + ",\"schedule\" : {\"enable\" : 0}}}}]");
232                 }
233                 break;
234             case CHANNEL_ENABLE_LED:
235                 if (OnOffType.OFF.equals(command) || PercentType.ZERO.equals(command)) {
236                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
237                             "[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 0,\"channel\": "
238                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 1}}}]");
239                 } else if (OnOffType.ON.equals(command)) {
240                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
241                             "[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 1,\"channel\": "
242                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 1}}}]");
243                 } else if (command instanceof PercentType percentCommand) {
244                     int value = percentCommand.toBigDecimal().intValue();
245                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetWhiteLed" + ipCameraHandler.reolinkAuth,
246                             "[{\"cmd\": \"SetWhiteLed\",\"param\": {\"WhiteLed\": {\"state\": 1,\"channel\": "
247                                     + ipCameraHandler.cameraConfig.getNvrChannel() + ",\"mode\": 1,\"bright\": " + value
248                                     + "}}}]");
249                 }
250             case CHANNEL_ENABLE_MOTION_ALARM:
251                 if (OnOffType.ON.equals(command)) {
252                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetMdAlarm" + ipCameraHandler.reolinkAuth);
253                 } else {
254                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetMdAlarm" + ipCameraHandler.reolinkAuth);
255                 }
256                 break;
257             case CHANNEL_ENABLE_RECORDINGS:
258                 if (OnOffType.ON.equals(command)) {
259                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRec" + ipCameraHandler.reolinkAuth,
260                             "[{\"cmd\":\"SetRec\",\"param\":{\"Rec\" : {\"channel\" : "
261                                     + ipCameraHandler.cameraConfig.getNvrChannel()
262                                     + ",\"schedule\" : {\"enable\" : 1}}}}]");
263                 } else {
264                     ipCameraHandler.sendHttpPOST("/api.cgi?cmd=SetRec" + ipCameraHandler.reolinkAuth,
265                             "[{\"cmd\":\"SetRec\",\"param\":{\"Rec\" : {\"channel\" : "
266                                     + ipCameraHandler.cameraConfig.getNvrChannel()
267                                     + ",\"schedule\" : {\"enable\" : 0}}}}]");
268                 }
269                 break;
270         }
271     }
272
273     // If a camera does not need to poll a request as often as snapshots, it can be
274     // added here. Binding steps through the list.
275     public List<String> getLowPriorityRequests() {
276         return List.of();
277     }
278 }