]> git.basschouten.com Git - openhab-addons.git/blob
0aaee77ec096a683895ed26a9b7241ab8d451b3b
[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.math.BigDecimal;
18 import java.util.ArrayList;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.ipcamera.internal.handler.IpCameraHandler;
23 import org.openhab.core.library.types.OnOffType;
24 import org.openhab.core.library.types.PercentType;
25 import org.openhab.core.library.types.StringType;
26 import org.openhab.core.thing.ChannelUID;
27 import org.openhab.core.types.Command;
28 import org.openhab.core.types.RefreshType;
29
30 import io.netty.channel.ChannelDuplexHandler;
31 import io.netty.channel.ChannelHandlerContext;
32 import io.netty.util.ReferenceCountUtil;
33
34 /**
35  * The {@link InstarHandler} is responsible for handling commands, which are
36  * sent to one of the channels.
37  *
38  * @author Matthew Skinner - Initial contribution
39  */
40
41 @NonNullByDefault
42 public class InstarHandler extends ChannelDuplexHandler {
43     private IpCameraHandler ipCameraHandler;
44     private String requestUrl = "Empty";
45
46     public InstarHandler(IpCameraHandler thingHandler) {
47         ipCameraHandler = thingHandler;
48     }
49
50     public void setURL(String url) {
51         requestUrl = url;
52     }
53
54     // This handles the incoming http replies back from the camera.
55     @Override
56     public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object msg) throws Exception {
57         if (msg == null || ctx == null) {
58             return;
59         }
60         try {
61             String value1 = "";
62             String content = msg.toString();
63             ipCameraHandler.logger.trace("HTTP Result back from camera is \t:{}:", content);
64             switch (requestUrl) {
65                 case "/param.cgi?cmd=getinfrared":
66                     if (content.contains("var infraredstat=\"auto") || content.contains("infraredstat=\"2\"")) {
67                         ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.ON);
68                     } else {
69                         ipCameraHandler.setChannelState(CHANNEL_AUTO_LED, OnOffType.OFF);
70                     }
71                     break;
72                 case "/param.cgi?cmd=getoverlayattr&-region=1":// Text Overlays
73                     if (content.contains("var show_1=\"0\"") || content.contains("show=\"0\"")) {
74                         ipCameraHandler.setChannelState(CHANNEL_TEXT_OVERLAY, StringType.EMPTY);
75                     } else {
76                         value1 = Helper.searchString(content, "var name_1=\"");
77                         if (!value1.isEmpty()) {
78                             ipCameraHandler.setChannelState(CHANNEL_TEXT_OVERLAY, StringType.valueOf(value1));
79                         } else {
80                             value1 = Helper.searchString(content, "name=\"");
81                             if (!value1.isEmpty()) {
82                                 ipCameraHandler.setChannelState(CHANNEL_TEXT_OVERLAY, StringType.valueOf(value1));
83                             }
84                         }
85                     }
86                     break;
87                 case "/cgi-bin/hi3510/param.cgi?cmd=getmdattr":// Motion Alarm old
88                     if (content.contains("var m1_enable=\"1\"")) {
89                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON);
90                     } else {
91                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.OFF);
92                     }
93                     break;
94                 case "/param.cgi?cmd=getalarmattr":// Motion Alarm new
95                     if (content.contains("armed=\"1\"")) {
96                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.ON);
97                     } else {
98                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_MOTION_ALARM, OnOffType.OFF);
99                     }
100                     break;
101                 case "/param.cgi?cmd=getaudioalarmattr":// Audio Alarm
102                     if (content.contains("enable=\"1\"")) {
103                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.ON);
104                         value1 = Helper.searchString(content, "aa_value=\"");
105                         if (!value1.isEmpty()) {// old cameras have threshold in percentage
106                             ipCameraHandler.setChannelState(CHANNEL_THRESHOLD_AUDIO_ALARM, PercentType.valueOf(value1));
107                         } else {
108                             value1 = Helper.searchString(content, "threshold=\"");
109                             if (!value1.isEmpty()) {// newer cameras have values up to 10
110                                 ipCameraHandler.setChannelState(CHANNEL_THRESHOLD_AUDIO_ALARM,
111                                         PercentType.valueOf(value1 + "0"));
112                             }
113                         }
114                     } else {
115                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_AUDIO_ALARM, OnOffType.OFF);
116                         ipCameraHandler.setChannelState(CHANNEL_THRESHOLD_AUDIO_ALARM, OnOffType.OFF);
117                     }
118                     break;
119                 case "/param.cgi?cmd=getpirattr":// PIR Alarm
120                     if (content.contains("enable=\"1\"")) {
121                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_PIR_ALARM, OnOffType.ON);
122                     } else {
123                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_PIR_ALARM, OnOffType.OFF);
124                     }
125                     // Reset the Alarm, need to find better place to put this.
126                     ipCameraHandler.noMotionDetected(CHANNEL_PIR_ALARM);
127                     break;
128                 case "/param.cgi?cmd=getioattr":// External Alarm Input
129                     if (content.contains("enable=\"1\"")) {
130                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT, OnOffType.ON);
131                     } else {
132                         ipCameraHandler.setChannelState(CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT, OnOffType.OFF);
133                     }
134                     break;
135                 default:
136                     if (requestUrl.startsWith("/param.cgi?cmd=setasaction&-server=1&enable=1")
137                             && content.contains("response=\"200\";")) {// new
138                         ipCameraHandler.newInstarApi = true;
139                         ipCameraHandler.logger.debug("Alarm server successfully setup for a 2k+ Instar camera");
140                         if (ipCameraHandler.cameraConfig.getFfmpegInput().isEmpty()) {
141                             ipCameraHandler.rtspUri = "rtsp://" + ipCameraHandler.cameraConfig.getIp()
142                                     + "/livestream/12";
143                         }
144                         if (ipCameraHandler.cameraConfig.getMjpegUrl().isEmpty()) {
145                             ipCameraHandler.mjpegUri = "/livestream/12?action=play&media=mjpeg";
146                         }
147                         if (ipCameraHandler.cameraConfig.getSnapshotUrl().isEmpty()) {
148                             ipCameraHandler.snapshotUri = "/snap.cgi?chn=12";
149                         }
150                     } else if (requestUrl.startsWith("/param.cgi?cmd=setmdalarm&-aname=server2&-switch=on&-interval=1")
151                             && content.startsWith("[Succeed]set ok")) {
152                         ipCameraHandler.newInstarApi = false;
153                         ipCameraHandler.logger.debug("Alarm server successfully setup for a 1080p Instar camera");
154                     } else {
155                         ipCameraHandler.logger.debug("Unknown reply from URI:{}", requestUrl);
156                     }
157             }
158         } finally {
159             ReferenceCountUtil.release(msg);
160         }
161     }
162
163     // This handles the commands that come from the openHAB event bus.
164     public void handleCommand(ChannelUID channelUID, Command command) {
165         if (command instanceof RefreshType) {
166             switch (channelUID.getId()) {
167                 case CHANNEL_THRESHOLD_AUDIO_ALARM:
168                 case CHANNEL_ENABLE_AUDIO_ALARM:
169                     ipCameraHandler.sendHttpGET("/param.cgi?cmd=getaudioalarmattr");
170                     break;
171                 case CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT:
172                     ipCameraHandler.sendHttpGET("/param.cgi?cmd=getioattr");
173                     break;
174                 case CHANNEL_ENABLE_MOTION_ALARM:
175                     if (ipCameraHandler.newInstarApi) {
176                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=getalarmattr");
177                     } else {
178                         ipCameraHandler.sendHttpGET("/cgi-bin/hi3510/param.cgi?cmd=getmdattr");
179                     }
180                     break;
181                 case CHANNEL_ENABLE_PIR_ALARM:
182                     ipCameraHandler.sendHttpGET("/param.cgi?cmd=getpirattr");
183                     break;
184                 case CHANNEL_AUTO_LED:
185                     ipCameraHandler.sendHttpGET("/param.cgi?cmd=getinfrared");
186                     break;
187                 case CHANNEL_TEXT_OVERLAY:
188                     ipCameraHandler.sendHttpGET("/param.cgi?cmd=getoverlayattr&-region=1");
189                     break;
190             }
191             return;
192         } // end of "REFRESH"
193         if (ipCameraHandler.newInstarApi) {
194             switch (channelUID.getId()) {
195                 case CHANNEL_THRESHOLD_AUDIO_ALARM:
196                     if (OnOffType.OFF.equals(command) || PercentType.ZERO.equals(command)) {
197                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setaudioalarmattr&enable=0");
198                     } else if (OnOffType.ON.equals(command)) {
199                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setaudioalarmattr&enable=1");
200                     } else if (command instanceof PercentType) {
201                         int value = ((PercentType) command).toBigDecimal().divide(BigDecimal.TEN).intValue();
202                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setaudioalarmattr&enable=1&threshold=" + value);
203                     }
204                     return;
205                 case CHANNEL_ENABLE_AUDIO_ALARM:
206                     if (OnOffType.ON.equals(command)) {
207                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setaudioalarmattr&enable=1");
208                     } else {
209                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setaudioalarmattr&enable=0");
210                     }
211                     return;
212                 case CHANNEL_ENABLE_MOTION_ALARM:
213                     if (OnOffType.ON.equals(command)) {
214                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setalarmattr&armed=1");
215                     } else {
216                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setalarmattr&armed=0");
217                     }
218                     return;
219                 case CHANNEL_TEXT_OVERLAY:
220                     String text = Helper.encodeSpecialChars(command.toString());
221                     if (text.isEmpty()) {
222                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setoverlayattr&-region=1&-show=0");
223                     } else {
224                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setoverlayattr&-region=1&-show=1&-name=" + text);
225                     }
226                     return;
227                 case CHANNEL_AUTO_LED:
228                     if (OnOffType.ON.equals(command)) {
229                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setinfrared&-infraredstat=2");
230                     } else {
231                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setinfrared&-infraredstat=0");
232                     }
233                     return;
234                 case CHANNEL_ENABLE_PIR_ALARM:
235                     if (OnOffType.ON.equals(command)) {
236                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setpirattr&enable=1");
237                     } else {
238                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setpirattr&enable=0");
239                     }
240                     return;
241                 case CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT:
242                     if (OnOffType.ON.equals(command)) {
243                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setioattr&enable=1");
244                     } else {
245                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setioattr&enable=0");
246                     }
247                     return;
248             }
249         } else {
250             switch (channelUID.getId()) {
251                 case CHANNEL_THRESHOLD_AUDIO_ALARM:
252                     if (OnOffType.OFF.equals(command) || PercentType.ZERO.equals(command)) {
253                         ipCameraHandler.sendHttpGET("/cgi-bin/hi3510/param.cgi?cmd=setaudioalarmattr&-aa_enable=0");
254                     } else if (OnOffType.ON.equals(command)) {
255                         ipCameraHandler.sendHttpGET("/cgi-bin/hi3510/param.cgi?cmd=setaudioalarmattr&-aa_enable=1");
256                     } else if (command instanceof PercentType) {
257                         int value = ((PercentType) command).toBigDecimal().divide(BigDecimal.TEN).intValue();
258                         ipCameraHandler.sendHttpGET(
259                                 "/cgi-bin/hi3510/param.cgi?cmd=setaudioalarmattr&-aa_enable=1&-aa_value=" + value * 10);
260                     }
261                     return;
262                 case CHANNEL_ENABLE_AUDIO_ALARM:
263                     if (OnOffType.ON.equals(command)) {
264                         ipCameraHandler.sendHttpGET("/cgi-bin/hi3510/param.cgi?cmd=setaudioalarmattr&-aa_enable=1");
265                     } else {
266                         ipCameraHandler.sendHttpGET("/cgi-bin/hi3510/param.cgi?cmd=setaudioalarmattr&-aa_enable=0");
267                     }
268                     return;
269                 case CHANNEL_ENABLE_MOTION_ALARM:
270                     if (OnOffType.ON.equals(command)) {
271                         ipCameraHandler.sendHttpGET(
272                                 "/cgi-bin/hi3510/param.cgi?cmd=setmdattr&-enable=1&-name=1&cmd=setmdattr&-enable=1&-name=2&cmd=setmdattr&-enable=1&-name=3&cmd=setmdattr&-enable=1&-name=4");
273                     } else {
274                         ipCameraHandler.sendHttpGET(
275                                 "/cgi-bin/hi3510/param.cgi?cmd=setmdattr&-enable=0&-name=1&cmd=setmdattr&-enable=0&-name=2&cmd=setmdattr&-enable=0&-name=3&cmd=setmdattr&-enable=0&-name=4");
276                     }
277                     return;
278                 case CHANNEL_TEXT_OVERLAY:
279                     String text = Helper.encodeSpecialChars(command.toString());
280                     if (text.isEmpty()) {
281                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setoverlayattr&-region=1&-show=0");
282                     } else {
283                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setoverlayattr&-region=1&-show=1&-name=" + text);
284                     }
285                     return;
286                 case CHANNEL_AUTO_LED:
287                     if (OnOffType.ON.equals(command)) {
288                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setinfrared&-infraredstat=auto");
289                     } else {
290                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setinfrared&-infraredstat=close");
291                     }
292                     return;
293                 case CHANNEL_ENABLE_PIR_ALARM:
294                     if (OnOffType.ON.equals(command)) {
295                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setpirattr&-pir_enable=1");
296                     } else {
297                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setpirattr&-pir_enable=0");
298                     }
299                     return;
300                 case CHANNEL_ENABLE_EXTERNAL_ALARM_INPUT:
301                     if (OnOffType.ON.equals(command)) {
302                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setioattr&-io_enable=1");
303                     } else {
304                         ipCameraHandler.sendHttpGET("/param.cgi?cmd=setioattr&-io_enable=0");
305                     }
306                     return;
307             }
308         }
309     }
310
311     public void alarmTriggered(String alarm) {
312         // older cameras placed the & for the first query, whilst newer cameras do not.
313         // examples are /instar?&active=6 vs /instar?active=6&object=0
314         ipCameraHandler.setChannelState(CHANNEL_LAST_EVENT_DATA, new StringType(alarm));
315         String alarmCode = alarm.replaceAll(".+active=", "");
316         alarmCode = alarmCode.replaceAll("&.+", "");
317         String objectCode = alarm.replaceAll(".+object=", "");
318         switch (alarmCode) {
319             case "1":// The motion area boxes 1-4
320             case "2":
321             case "3":
322             case "4":
323                 ipCameraHandler.motionDetected(CHANNEL_MOTION_ALARM);
324                 break;
325             case "5":// PIR
326                 ipCameraHandler.motionDetected(CHANNEL_PIR_ALARM);
327                 break;
328             case "6":// Audio Alarm
329                 ipCameraHandler.audioDetected();
330                 break;
331             case "7":// Motion area 1 + PIR
332             case "8":// Motion area 2 + PIR
333             case "9":// Motion area 3 + PIR
334             case "10":// Motion area 4 + PIR
335                 ipCameraHandler.motionDetected(CHANNEL_MOTION_ALARM);
336                 ipCameraHandler.motionDetected(CHANNEL_PIR_ALARM);
337                 break;
338             default:
339                 ipCameraHandler.logger.debug("Unknown alarm code:{}", alarmCode);
340         }
341         if (!objectCode.isEmpty()) {
342             switch (objectCode) {
343                 // person=1, car=2, animal=4 so 1+2+4=7 means one of each.
344                 case "0":// no object
345                     break;
346                 case "1":
347                     ipCameraHandler.motionDetected(CHANNEL_HUMAN_ALARM);
348                     break;
349                 case "2":
350                     ipCameraHandler.motionDetected(CHANNEL_CAR_ALARM);
351                     break;
352                 case "3":
353                     ipCameraHandler.motionDetected(CHANNEL_HUMAN_ALARM);
354                     ipCameraHandler.motionDetected(CHANNEL_CAR_ALARM);
355                     break;
356                 case "4":
357                     ipCameraHandler.motionDetected(CHANNEL_ANIMAL_ALARM);
358                     break;
359                 case "5":
360                     ipCameraHandler.motionDetected(CHANNEL_HUMAN_ALARM);
361                     ipCameraHandler.motionDetected(CHANNEL_ANIMAL_ALARM);
362                     break;
363                 case "6":
364                     ipCameraHandler.motionDetected(CHANNEL_CAR_ALARM);
365                     ipCameraHandler.motionDetected(CHANNEL_ANIMAL_ALARM);
366                     break;
367                 case "7":
368                     ipCameraHandler.motionDetected(CHANNEL_HUMAN_ALARM);
369                     ipCameraHandler.motionDetected(CHANNEL_CAR_ALARM);
370                     ipCameraHandler.motionDetected(CHANNEL_ANIMAL_ALARM);
371                     break;
372                 default:
373                     if (objectCode.startsWith("/instar?")) {
374                         return;// has no object due to older Instar camera model
375                     }
376                     ipCameraHandler.logger.debug("Unknown object detection code:{}", objectCode);
377             }
378         }
379     }
380
381     // If a camera does not need to poll a request as often as snapshots, it can be
382     // added here. Binding steps through the list.
383     public ArrayList<String> getLowPriorityRequests() {
384         ArrayList<String> lowPriorityRequests = new ArrayList<String>(7);
385         lowPriorityRequests.add("/param.cgi?cmd=getaudioalarmattr");
386         lowPriorityRequests.add("/cgi-bin/hi3510/param.cgi?cmd=getmdattr");
387         if (ipCameraHandler.newInstarApi) {// old API cameras get a error 404 response to this
388             lowPriorityRequests.add("/param.cgi?cmd=getalarmattr");
389         }
390         lowPriorityRequests.add("/param.cgi?cmd=getinfrared");
391         lowPriorityRequests.add("/param.cgi?cmd=getoverlayattr&-region=1");
392         lowPriorityRequests.add("/param.cgi?cmd=getpirattr");
393         lowPriorityRequests.add("/param.cgi?cmd=getioattr"); // ext alarm input on/off
394         return lowPriorityRequests;
395     }
396 }