]> git.basschouten.com Git - openhab-addons.git/blob
ed6308b8d66e10b440ef189801ca47c7c146615b
[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.leapmotion.internal.handler;
14
15 import static org.openhab.binding.leapmotion.internal.LeapMotionBindingConstants.*;
16
17 import java.util.concurrent.TimeUnit;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.core.thing.ChannelUID;
22 import org.openhab.core.thing.Thing;
23 import org.openhab.core.thing.ThingStatus;
24 import org.openhab.core.thing.binding.BaseThingHandler;
25 import org.openhab.core.types.Command;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 import com.leapmotion.leap.CircleGesture;
30 import com.leapmotion.leap.Controller;
31 import com.leapmotion.leap.FingerList;
32 import com.leapmotion.leap.Frame;
33 import com.leapmotion.leap.Gesture;
34 import com.leapmotion.leap.GestureList;
35 import com.leapmotion.leap.Hand;
36 import com.leapmotion.leap.Listener;
37
38 /**
39  * The {@link LeapMotionHandler} is responsible for handling commands, which are
40  * sent to one of the channels.
41  *
42  * @author Kai Kreuzer - Initial contribution
43  * @author Thomas Eichstädt-Engelen - Initial version of listener logic
44  *
45  */
46 @NonNullByDefault
47 public class LeapMotionHandler extends BaseThingHandler {
48
49     private final Logger logger = LoggerFactory.getLogger(LeapMotionHandler.class);
50
51     private @NonNullByDefault({}) LeapMotionListener listener;
52     private @NonNullByDefault({}) Controller leapController;
53
54     public LeapMotionHandler(Thing thing) {
55         super(thing);
56     }
57
58     @Override
59     public void handleCommand(ChannelUID channelUID, Command command) {
60     }
61
62     @Override
63     public void initialize() {
64         this.listener = new LeapMotionListener();
65
66         leapController = new Controller();
67         leapController.setPolicyFlags(Controller.PolicyFlag.POLICY_BACKGROUND_FRAMES);
68         leapController.addListener(this.listener);
69         if (leapController.isConnected()) {
70             updateStatus(ThingStatus.ONLINE);
71         } else {
72             updateStatus(ThingStatus.OFFLINE);
73         }
74     }
75
76     @Override
77     public void dispose() {
78         leapController.removeListener(this.listener);
79         listener = null;
80         leapController.delete();
81         leapController = null;
82     }
83
84     private class LeapMotionListener extends Listener {
85
86         private static final int RATE_LIMIT_IN_MS = 200;
87         private long lastEvent = 0;
88         private boolean noHand;
89
90         public LeapMotionListener() {
91         }
92
93         @Override
94         public void onConnect(@Nullable Controller controller) {
95             if (controller != null) {
96                 controller.enableGesture(Gesture.Type.TYPE_KEY_TAP);
97                 controller.enableGesture(Gesture.Type.TYPE_CIRCLE);
98             }
99             updateStatus(ThingStatus.ONLINE);
100         }
101
102         @Override
103         public void onDisconnect(@Nullable Controller controller) {
104             updateStatus(ThingStatus.OFFLINE);
105         }
106
107         @Override
108         public void onFrame(@Nullable Controller controller) {
109             if (controller == null) {
110                 return;
111             }
112             Frame frame = controller.frame();
113
114             GestureList gestures = frame.gestures();
115             for (int i = 0; i < gestures.count(); i++) {
116                 Gesture gesture = gestures.get(i);
117                 switch (gesture.type()) {
118                     case TYPE_KEY_TAP:
119                         logger.debug("Key tap");
120                         triggerChannel(CHANNEL_GESTURE, GESTURE_TAP);
121                         break;
122                     case TYPE_CIRCLE:
123                         CircleGesture circle = new CircleGesture(gesture);
124                         // Calculate clock direction using the angle between circle normal and pointable
125                         boolean clockwiseness;
126                         if (circle.pointable().direction().angleTo(circle.normal()) <= Math.PI / 4) {
127                             // Clockwise if angle is less than 90 degrees
128                             clockwiseness = true;
129                         } else {
130                             clockwiseness = false;
131                         }
132
133                         // Calculate angle swept since last frame
134                         if (circle.state() == com.leapmotion.leap.Gesture.State.STATE_UPDATE) {
135                             if (System.nanoTime() > lastEvent + TimeUnit.MILLISECONDS.toNanos(RATE_LIMIT_IN_MS)) {
136                                 logger.debug("Circle (clockwise={})", clockwiseness);
137                                 if (clockwiseness) {
138                                     triggerChannel(CHANNEL_GESTURE, GESTURE_CLOCKWISE);
139                                 } else {
140                                     triggerChannel(CHANNEL_GESTURE, GESTURE_ANTICLOCKWISE);
141                                 }
142                                 lastEvent = System.nanoTime();
143                             }
144                         }
145                         break;
146                     default:
147                         logger.debug("Unknown gesture type.");
148                         break;
149                 }
150             }
151
152             if (!frame.hands().isEmpty()) {
153                 noHand = false;
154                 // Get the first hand
155                 Hand hand = frame.hands().get(0);
156                 // Check if the hand has any fingers
157                 FingerList fingers = hand.fingers();
158                 if (System.nanoTime() > lastEvent + TimeUnit.MILLISECONDS.toNanos(RATE_LIMIT_IN_MS)) {
159                     int height = (int) hand.palmPosition().getY();
160                     logger.debug("Fingers shown {} @ {}", fingers.count(), height);
161                     triggerChannel(CHANNEL_GESTURE, GESTURE_FINGERS + fingers.count() + "_" + height);
162                     lastEvent = System.nanoTime();
163                 }
164             } else {
165                 if (!noHand) {
166                     noHand = true;
167                     logger.debug("No hand");
168                     triggerChannel(CHANNEL_GESTURE, GESTURE_NOHAND);
169                 }
170             }
171         }
172     }
173 }