added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.leapmotion-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-leapmotion" description="LeapMotion Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.leapmotion/${project.version}</bundle>
|
||||
<configfile finalname="${openhab.userdata}/tmp/lib/libLeap.dylib" override="false">mvn:${project.groupId}/openhab-addons-external/${project.version}/lib/libLeap</configfile>
|
||||
<configfile finalname="${openhab.userdata}/tmp/lib/libLeapJava.dylib" override="false">mvn:${project.groupId}/openhab-addons-external/${project.version}/lib/libLeapJava</configfile>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.leapmotion.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link LeapMotionBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LeapMotionBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "leapmotion";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_CONTROLLER = new ThingTypeUID(BINDING_ID, "controller");
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String CHANNEL_GESTURE = "gesture";
|
||||
public static final ChannelTypeUID CHANNEL_GESTURE_UID = new ChannelTypeUID(BINDING_ID, CHANNEL_GESTURE);
|
||||
|
||||
// List of all gestures
|
||||
public static final String GESTURE_TAP = "tap";
|
||||
public static final String GESTURE_CLOCKWISE = "clockwise";
|
||||
public static final String GESTURE_ANTICLOCKWISE = "anticlockwise";
|
||||
public static final String GESTURE_FINGERS = "fingers";
|
||||
public static final String GESTURE_NOHAND = "nohand";
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.leapmotion.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.thing.profiles.ProfileCallback;
|
||||
import org.openhab.core.thing.profiles.ProfileTypeUID;
|
||||
import org.openhab.core.thing.profiles.TriggerProfile;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link LeapMotionColorProfile} class implements the behavior when being linked to a Color item.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LeapMotionColorProfile implements TriggerProfile {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LeapMotionColorProfile.class);
|
||||
|
||||
private ProfileCallback callback;
|
||||
private HSBType lastState = HSBType.BLACK;
|
||||
|
||||
public LeapMotionColorProfile(ProfileCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileTypeUID getProfileTypeUID() {
|
||||
return LeapMotionProfileFactory.UID_COLOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateUpdateFromItem(State state) {
|
||||
if (state instanceof HSBType) {
|
||||
lastState = (HSBType) state;
|
||||
} else {
|
||||
PercentType currentBrightness = state.as(PercentType.class);
|
||||
if (currentBrightness != null) {
|
||||
lastState = new HSBType(lastState.getHue(), lastState.getSaturation(), currentBrightness);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTriggerFromHandler(String event) {
|
||||
if (event.equals(LeapMotionBindingConstants.GESTURE_TAP)) {
|
||||
callback.sendCommand(lastState.getBrightness().equals(PercentType.ZERO) ? OnOffType.ON : OnOffType.OFF);
|
||||
} else if (event.equals(LeapMotionBindingConstants.GESTURE_CLOCKWISE)) {
|
||||
HSBType color = changeColor(lastState, true);
|
||||
callback.sendCommand(color);
|
||||
lastState = color;
|
||||
} else if (event.equals(LeapMotionBindingConstants.GESTURE_ANTICLOCKWISE)) {
|
||||
HSBType color = changeColor(lastState, false);
|
||||
callback.sendCommand(color);
|
||||
lastState = color;
|
||||
} else if (event.startsWith(LeapMotionBindingConstants.GESTURE_FINGERS)) {
|
||||
// the brightness is determined by the height of the palm over the sensor, where higher means brighter
|
||||
int fingers = Integer
|
||||
.valueOf(Character.toString(event.charAt(LeapMotionBindingConstants.GESTURE_FINGERS.length())));
|
||||
if (fingers == 5) {
|
||||
try {
|
||||
int height = Integer
|
||||
.valueOf(event.substring(LeapMotionBindingConstants.GESTURE_FINGERS.length() + 2));
|
||||
height = Math.min(100 * height / LeapMotionDimmerProfile.MAX_HEIGHT, 100); // don't use values over
|
||||
// 100
|
||||
PercentType brightness = new PercentType(height);
|
||||
callback.sendCommand(brightness);
|
||||
lastState = new HSBType(lastState.getHue(), lastState.getSaturation(), brightness);
|
||||
} catch (NumberFormatException e) {
|
||||
logger.error("Found illegal format of finger event: {}", event, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private HSBType changeColor(HSBType color, boolean clockwise) {
|
||||
int hue = clockwise ? (color.getHue().toBigDecimal().intValue() - 20 + 360) % 360
|
||||
: (color.getHue().toBigDecimal().intValue() + 20 + 360) % 360;
|
||||
logger.debug("New hue value: {}", hue);
|
||||
HSBType newState = new HSBType(new DecimalType(hue), color.getSaturation(), color.getBrightness());
|
||||
return newState;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.leapmotion.internal;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.thing.profiles.ProfileCallback;
|
||||
import org.openhab.core.thing.profiles.ProfileContext;
|
||||
import org.openhab.core.thing.profiles.ProfileTypeUID;
|
||||
import org.openhab.core.thing.profiles.TriggerProfile;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link LeapMotionDimmerProfile} class implements the behavior when being linked to a Dimmer item.
|
||||
* It supports two modes: Either the dim level is determined by the number of shown fingers or by the height of the hand
|
||||
* over the controller.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LeapMotionDimmerProfile implements TriggerProfile {
|
||||
|
||||
static final int MAX_HEIGHT = 400; // in mm over controller
|
||||
private static final String MODE = "mode";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LeapMotionDimmerProfile.class);
|
||||
|
||||
private ProfileCallback callback;
|
||||
private BigDecimal lastState = BigDecimal.ZERO;
|
||||
private boolean fingerMode = false;
|
||||
|
||||
public LeapMotionDimmerProfile(ProfileCallback callback, ProfileContext profileContext) {
|
||||
this.callback = callback;
|
||||
fingerMode = "fingers".equals(profileContext.getConfiguration().get(MODE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileTypeUID getProfileTypeUID() {
|
||||
return LeapMotionProfileFactory.UID_DIMMER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateUpdateFromItem(State state) {
|
||||
PercentType currentState = state.as(PercentType.class);
|
||||
if (currentState != null) {
|
||||
lastState = currentState.toBigDecimal();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTriggerFromHandler(String event) {
|
||||
if (event.equals(LeapMotionBindingConstants.GESTURE_TAP)) {
|
||||
callback.sendCommand(lastState.equals(BigDecimal.ZERO) ? OnOffType.ON : OnOffType.OFF);
|
||||
} else if (event.startsWith(LeapMotionBindingConstants.GESTURE_FINGERS)) {
|
||||
int fingers = Integer
|
||||
.valueOf(Character.toString(event.charAt(LeapMotionBindingConstants.GESTURE_FINGERS.length())));
|
||||
if (fingerMode) {
|
||||
// the brightness is determined by the number of shown fingers, 20% for each.
|
||||
callback.sendCommand(new PercentType(fingers * 20));
|
||||
} else if (fingers == 5) {
|
||||
// the brightness is determined by the height of the palm over the sensor, where higher means brighter
|
||||
try {
|
||||
int height = Integer
|
||||
.valueOf(event.substring(LeapMotionBindingConstants.GESTURE_FINGERS.length() + 2));
|
||||
height = Math.min(100 * height / MAX_HEIGHT, 100); // don't use values over 100
|
||||
callback.sendCommand(new PercentType(height));
|
||||
} catch (NumberFormatException e) {
|
||||
logger.error("Found illegal format of finger event: {}", event, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.leapmotion.internal;
|
||||
|
||||
import static org.openhab.binding.leapmotion.internal.LeapMotionBindingConstants.THING_TYPE_CONTROLLER;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.leapmotion.internal.handler.LeapMotionHandler;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* The {@link LeapMotionHandlerFactory} is responsible for creating things and thing handlers.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*/
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.leapmotion")
|
||||
@NonNullByDefault
|
||||
public class LeapMotionHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_CONTROLLER);
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (thingTypeUID.equals(THING_TYPE_CONTROLLER)) {
|
||||
return new LeapMotionHandler(thing);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.leapmotion.internal;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.CoreItemFactory;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.profiles.Profile;
|
||||
import org.openhab.core.thing.profiles.ProfileAdvisor;
|
||||
import org.openhab.core.thing.profiles.ProfileCallback;
|
||||
import org.openhab.core.thing.profiles.ProfileContext;
|
||||
import org.openhab.core.thing.profiles.ProfileFactory;
|
||||
import org.openhab.core.thing.profiles.ProfileType;
|
||||
import org.openhab.core.thing.profiles.ProfileTypeBuilder;
|
||||
import org.openhab.core.thing.profiles.ProfileTypeProvider;
|
||||
import org.openhab.core.thing.profiles.ProfileTypeUID;
|
||||
import org.openhab.core.thing.profiles.TriggerProfileType;
|
||||
import org.openhab.core.thing.type.ChannelType;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* This class defines and provides all profiles and their types of this binding.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component
|
||||
public class LeapMotionProfileFactory implements ProfileFactory, ProfileAdvisor, ProfileTypeProvider {
|
||||
|
||||
static final ProfileTypeUID UID_SWITCH = new ProfileTypeUID(LeapMotionBindingConstants.BINDING_ID, "switch");
|
||||
static final ProfileTypeUID UID_DIMMER = new ProfileTypeUID(LeapMotionBindingConstants.BINDING_ID, "dimmer");
|
||||
static final ProfileTypeUID UID_COLOR = new ProfileTypeUID(LeapMotionBindingConstants.BINDING_ID, "color");
|
||||
|
||||
private static final TriggerProfileType SWITCH_TYPE = ProfileTypeBuilder.newTrigger(UID_SWITCH, "Toggle Switch")
|
||||
.withSupportedItemTypes(CoreItemFactory.SWITCH, CoreItemFactory.DIMMER, CoreItemFactory.COLOR)
|
||||
.withSupportedChannelTypeUIDs(LeapMotionBindingConstants.CHANNEL_GESTURE_UID).build();
|
||||
|
||||
private static final TriggerProfileType DIMMER_TYPE = ProfileTypeBuilder.newTrigger(UID_DIMMER, "Dimmer Control")
|
||||
.withSupportedItemTypes(CoreItemFactory.DIMMER, CoreItemFactory.COLOR)
|
||||
.withSupportedChannelTypeUIDs(LeapMotionBindingConstants.CHANNEL_GESTURE_UID).build();
|
||||
|
||||
private static final TriggerProfileType COLOR_TYPE = ProfileTypeBuilder.newTrigger(UID_COLOR, "Color Control")
|
||||
.withSupportedItemTypes(CoreItemFactory.COLOR)
|
||||
.withSupportedChannelTypeUIDs(LeapMotionBindingConstants.CHANNEL_GESTURE_UID).build();
|
||||
|
||||
@Override
|
||||
public Collection<ProfileTypeUID> getSupportedProfileTypeUIDs() {
|
||||
return Stream.of(UID_SWITCH, UID_DIMMER, UID_COLOR).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ProfileType> getProfileTypes(@Nullable Locale locale) {
|
||||
return Stream.of(SWITCH_TYPE, DIMMER_TYPE, COLOR_TYPE).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ProfileTypeUID getSuggestedProfileTypeUID(Channel channel, @Nullable String itemType) {
|
||||
return getSuggestedProfileTypeUID(channel.getChannelTypeUID(), itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ProfileTypeUID getSuggestedProfileTypeUID(ChannelType channelType, @Nullable String itemType) {
|
||||
return getSuggestedProfileTypeUID(channelType.getUID(), itemType);
|
||||
}
|
||||
|
||||
private @Nullable ProfileTypeUID getSuggestedProfileTypeUID(@Nullable ChannelTypeUID channelTypeUID,
|
||||
@Nullable String itemType) {
|
||||
if (LeapMotionBindingConstants.CHANNEL_GESTURE_UID.equals(channelTypeUID) && itemType != null) {
|
||||
switch (itemType) {
|
||||
case CoreItemFactory.SWITCH:
|
||||
return UID_SWITCH;
|
||||
case CoreItemFactory.DIMMER:
|
||||
return UID_DIMMER;
|
||||
case CoreItemFactory.COLOR:
|
||||
return UID_COLOR;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Profile createProfile(ProfileTypeUID profileTypeUID, ProfileCallback callback,
|
||||
ProfileContext profileContext) {
|
||||
if (UID_SWITCH.equals(profileTypeUID)) {
|
||||
return new LeapMotionSwitchProfile(callback);
|
||||
} else if (UID_DIMMER.equals(profileTypeUID)) {
|
||||
return new LeapMotionDimmerProfile(callback, profileContext);
|
||||
} else if (UID_COLOR.equals(profileTypeUID)) {
|
||||
return new LeapMotionColorProfile(callback);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.leapmotion.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.profiles.ProfileCallback;
|
||||
import org.openhab.core.thing.profiles.ProfileTypeUID;
|
||||
import org.openhab.core.thing.profiles.TriggerProfile;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link LeapMotionSwitchProfile} class implements the behavior when being linked to a Switch item.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LeapMotionSwitchProfile implements TriggerProfile {
|
||||
|
||||
private ProfileCallback callback;
|
||||
private boolean lastState = false;
|
||||
|
||||
public LeapMotionSwitchProfile(ProfileCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileTypeUID getProfileTypeUID() {
|
||||
return LeapMotionProfileFactory.UID_SWITCH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateUpdateFromItem(State state) {
|
||||
lastState = OnOffType.ON.equals(state.as(OnOffType.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTriggerFromHandler(String event) {
|
||||
if (event.equals(LeapMotionBindingConstants.GESTURE_TAP)) {
|
||||
callback.sendCommand(lastState ? OnOffType.OFF : OnOffType.ON);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.leapmotion.internal.discovery;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.leapmotion.internal.LeapMotionBindingConstants;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
import com.leapmotion.leap.Controller;
|
||||
import com.leapmotion.leap.Listener;
|
||||
|
||||
/**
|
||||
* This is a discovery service, which finds locally attached LeapMotion controllers and adds them to the Inbox
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.leapmotion")
|
||||
public class LeapMotionDiscoveryService extends AbstractDiscoveryService {
|
||||
|
||||
private @NonNullByDefault({}) Controller leapController;
|
||||
private @NonNullByDefault({}) Listener listener;
|
||||
|
||||
public LeapMotionDiscoveryService() throws IllegalArgumentException {
|
||||
super(Collections.singleton(LeapMotionBindingConstants.THING_TYPE_CONTROLLER), 10, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate(@Nullable Map<String, @Nullable Object> configProperties) {
|
||||
leapController = new Controller();
|
||||
listener = new Listener() {
|
||||
@Override
|
||||
public void onConnect(@Nullable Controller c) {
|
||||
createDiscoveryResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect(@Nullable Controller c) {
|
||||
removeDiscoveryResult();
|
||||
}
|
||||
};
|
||||
super.activate(configProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
leapController.removeListener(listener);
|
||||
listener = null;
|
||||
leapController.delete();
|
||||
leapController = null;
|
||||
super.deactivate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
if (leapController.isConnected()) {
|
||||
createDiscoveryResult();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startBackgroundDiscovery() {
|
||||
super.startBackgroundDiscovery();
|
||||
leapController.addListener(listener);
|
||||
}
|
||||
|
||||
private void createDiscoveryResult() {
|
||||
DiscoveryResult result = DiscoveryResultBuilder
|
||||
.create(new ThingUID(LeapMotionBindingConstants.THING_TYPE_CONTROLLER, "local"))
|
||||
.withLabel("Leap Motion Controller").build();
|
||||
thingDiscovered(result);
|
||||
}
|
||||
|
||||
private void removeDiscoveryResult() {
|
||||
removeOlderResults(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.leapmotion.internal.handler;
|
||||
|
||||
import static org.openhab.binding.leapmotion.internal.LeapMotionBindingConstants.*;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.leapmotion.leap.CircleGesture;
|
||||
import com.leapmotion.leap.Controller;
|
||||
import com.leapmotion.leap.FingerList;
|
||||
import com.leapmotion.leap.Frame;
|
||||
import com.leapmotion.leap.Gesture;
|
||||
import com.leapmotion.leap.GestureList;
|
||||
import com.leapmotion.leap.Hand;
|
||||
import com.leapmotion.leap.Listener;
|
||||
|
||||
/**
|
||||
* The {@link LeapMotionHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
* @author Thomas Eichstädt-Engelen - Initial version of listener logic
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LeapMotionHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LeapMotionHandler.class);
|
||||
|
||||
private @NonNullByDefault({}) LeapMotionListener listener;
|
||||
private @NonNullByDefault({}) Controller leapController;
|
||||
|
||||
public LeapMotionHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
this.listener = new LeapMotionListener();
|
||||
|
||||
leapController = new Controller();
|
||||
leapController.setPolicyFlags(Controller.PolicyFlag.POLICY_BACKGROUND_FRAMES);
|
||||
leapController.addListener(this.listener);
|
||||
if (leapController.isConnected()) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
leapController.removeListener(this.listener);
|
||||
listener = null;
|
||||
leapController.delete();
|
||||
leapController = null;
|
||||
}
|
||||
|
||||
private class LeapMotionListener extends Listener {
|
||||
|
||||
private static final int RATE_LIMIT_IN_MS = 200;
|
||||
private long lastEvent = 0;
|
||||
private boolean noHand;
|
||||
|
||||
public LeapMotionListener() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnect(@Nullable Controller controller) {
|
||||
if (controller != null) {
|
||||
controller.enableGesture(Gesture.Type.TYPE_KEY_TAP);
|
||||
controller.enableGesture(Gesture.Type.TYPE_CIRCLE);
|
||||
}
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect(@Nullable Controller controller) {
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrame(@Nullable Controller controller) {
|
||||
if (controller == null) {
|
||||
return;
|
||||
}
|
||||
Frame frame = controller.frame();
|
||||
|
||||
GestureList gestures = frame.gestures();
|
||||
for (int i = 0; i < gestures.count(); i++) {
|
||||
Gesture gesture = gestures.get(i);
|
||||
switch (gesture.type()) {
|
||||
case TYPE_KEY_TAP:
|
||||
logger.debug("Key tap");
|
||||
triggerChannel(CHANNEL_GESTURE, GESTURE_TAP);
|
||||
break;
|
||||
case TYPE_CIRCLE:
|
||||
CircleGesture circle = new CircleGesture(gesture);
|
||||
// Calculate clock direction using the angle between circle normal and pointable
|
||||
boolean clockwiseness;
|
||||
if (circle.pointable().direction().angleTo(circle.normal()) <= Math.PI / 4) {
|
||||
// Clockwise if angle is less than 90 degrees
|
||||
clockwiseness = true;
|
||||
} else {
|
||||
clockwiseness = false;
|
||||
}
|
||||
|
||||
// Calculate angle swept since last frame
|
||||
if (circle.state() == com.leapmotion.leap.Gesture.State.STATE_UPDATE) {
|
||||
if (System.nanoTime() > lastEvent + TimeUnit.MILLISECONDS.toNanos(RATE_LIMIT_IN_MS)) {
|
||||
logger.debug("Circle (clockwise={})", clockwiseness);
|
||||
if (clockwiseness) {
|
||||
triggerChannel(CHANNEL_GESTURE, GESTURE_CLOCKWISE);
|
||||
} else {
|
||||
triggerChannel(CHANNEL_GESTURE, GESTURE_ANTICLOCKWISE);
|
||||
}
|
||||
lastEvent = System.nanoTime();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.debug("Unknown gesture type.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!frame.hands().isEmpty()) {
|
||||
noHand = false;
|
||||
// Get the first hand
|
||||
Hand hand = frame.hands().get(0);
|
||||
// Check if the hand has any fingers
|
||||
FingerList fingers = hand.fingers();
|
||||
if (System.nanoTime() > lastEvent + TimeUnit.MILLISECONDS.toNanos(RATE_LIMIT_IN_MS)) {
|
||||
int height = (int) hand.palmPosition().getY();
|
||||
logger.debug("Fingers shown {} @ {}", fingers.count(), height);
|
||||
triggerChannel(CHANNEL_GESTURE, GESTURE_FINGERS + fingers.count() + "_" + height);
|
||||
lastEvent = System.nanoTime();
|
||||
}
|
||||
} else {
|
||||
if (!noHand) {
|
||||
noHand = true;
|
||||
logger.debug("No hand");
|
||||
triggerChannel(CHANNEL_GESTURE, GESTURE_NOHAND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="leapmotion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>Leap Motion Binding</name>
|
||||
<description>This is the binding for Leap Motion controllers.</description>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0
|
||||
https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
|
||||
<config-description uri="profile:leapmotion:dimmer">
|
||||
<parameter name="mode" type="text" required="false">
|
||||
<label>Mode</label>
|
||||
<description>The mode for interpreting gestures. Either it dims depending on the number of shown fingers or it uses
|
||||
the height of the hand over the controller.</description>
|
||||
<options>
|
||||
<option value="fingers">Number of Fingers</option>
|
||||
<option value="height">Height of Hand</option>
|
||||
</options>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</config-description:config-descriptions>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="leapmotion"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<thing-type id="controller">
|
||||
<label>Leap Motion Controller</label>
|
||||
<description>A Leap Motion Gesture Sensor</description>
|
||||
|
||||
<channels>
|
||||
<channel id="gesture" typeId="gesture"/>
|
||||
</channels>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="gesture">
|
||||
<kind>trigger</kind>
|
||||
<label>Gestures</label>
|
||||
<description>Provides recognized gestures from the controller</description>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user