Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[nanoleaf] Refactored code to use core features and more #10101

Merged
merged 6 commits into from
Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 37 additions & 61 deletions bundles/org.openhab.binding.nanoleaf/README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
@NonNullByDefault
public class NanoleafBindingConstants {

private static final String BINDING_ID = "nanoleaf";
public static final String BINDING_ID = "nanoleaf";

// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_CONTROLLER = new ThingTypeUID(BINDING_ID, "controller");
Expand All @@ -44,7 +44,6 @@ public class NanoleafBindingConstants {
public static final String CONFIG_PANEL_ID = "id";

// List of controller channels
public static final String CHANNEL_POWER = "power";
public static final String CHANNEL_COLOR = "color";
public static final String CHANNEL_COLOR_TEMPERATURE = "colorTemperature";
public static final String CHANNEL_COLOR_TEMPERATURE_ABS = "colorTemperatureAbs";
Expand All @@ -53,12 +52,10 @@ public class NanoleafBindingConstants {
public static final String CHANNEL_RHYTHM_STATE = "rhythmState";
public static final String CHANNEL_RHYTHM_ACTIVE = "rhythmActive";
public static final String CHANNEL_RHYTHM_MODE = "rhythmMode";
public static final String CHANNEL_PANEL_LAYOUT = "panelLayout";

// List of light panel channels
public static final String CHANNEL_PANEL_COLOR = "panelColor";
public static final String CHANNEL_PANEL_SINGLE_TAP = "singleTap";
public static final String CHANNEL_PANEL_DOUBLE_TAP = "doubleTap";
public static final String CHANNEL_PANEL_COLOR = "color";
public static final String CHANNEL_PANEL_TAP = "tap";

// Nanoleaf OpenAPI URLs
public static final String API_V1_BASE_URL = "/api/v1";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,22 @@
import static org.openhab.binding.nanoleaf.internal.NanoleafBindingConstants.*;

import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.nanoleaf.internal.discovery.NanoleafPanelsDiscoveryService;
import org.openhab.binding.nanoleaf.internal.handler.NanoleafControllerHandler;
import org.openhab.binding.nanoleaf.internal.handler.NanoleafPanelHandler;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
Expand All @@ -49,6 +42,7 @@
* and panel (thing) handlers.
*
* @author Martin Raepple - Initial contribution
* @author Kai Kreuzer - made discovery a handler service
*/
@NonNullByDefault
@Component(configurationPid = "binding.nanoleaf", service = ThingHandlerFactory.class)
Expand All @@ -58,7 +52,6 @@ public class NanoleafHandlerFactory extends BaseThingHandlerFactory {
.unmodifiableSet(Stream.of(THING_TYPE_LIGHT_PANEL, THING_TYPE_CONTROLLER).collect(Collectors.toSet()));

private final Logger logger = LoggerFactory.getLogger(NanoleafHandlerFactory.class);
private final Map<ThingUID, ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
private final HttpClient httpClient;

@Activate
Expand All @@ -77,7 +70,6 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {

if (THING_TYPE_CONTROLLER.equals(thingTypeUID)) {
NanoleafControllerHandler handler = new NanoleafControllerHandler((Bridge) thing, httpClient);
registerDiscoveryService(handler);
logger.debug("Nanoleaf controller handler created.");
return handler;
} else if (THING_TYPE_LIGHT_PANEL.equals(thingTypeUID)) {
Expand All @@ -87,30 +79,4 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
}
return null;
}

@Override
protected void removeHandler(ThingHandler thingHandler) {
if (thingHandler instanceof NanoleafControllerHandler) {
unregisterDiscoveryService(thingHandler.getThing());
logger.debug("Nanoleaf controller handler removed.");
}
}

private synchronized void registerDiscoveryService(NanoleafControllerHandler bridgeHandler) {
NanoleafPanelsDiscoveryService discoveryService = new NanoleafPanelsDiscoveryService(bridgeHandler);
discoveryServiceRegs.put(bridgeHandler.getThing().getUID(),
bundleContext.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>()));
logger.debug("Discovery service for panels registered.");
}

@SuppressWarnings("null")
private synchronized void unregisterDiscoveryService(Thing thing) {
@Nullable
ServiceRegistration<?> serviceReg = discoveryServiceRegs.remove(thing.getUID());
// would require null check but "if (response!=null)" throws warning on comoile time :´-(
if (serviceReg != null) {
serviceReg.unregister();
}
logger.debug("Discovery service for panels removed.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -57,7 +58,7 @@ public static Request requestBuilder(HttpClient httpClient, NanoleafControllerCo
LOGGER.trace("RequestBuilder: Sending Request {}:{} {} ", requestURI.getHost(), requestURI.getPort(),
requestURI.getPath());

return httpClient.newRequest(requestURI).method(method);
return httpClient.newRequest(requestURI).method(method).timeout(10, TimeUnit.SECONDS);
}

public static URI getUri(NanoleafControllerConfig controllerConfig, String apiOperation, @Nullable String query)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* Copyright (c) 2010-2021 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.nanoleaf.internal.command;

import java.util.Arrays;
import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.nanoleaf.internal.NanoleafBindingConstants;
import org.openhab.binding.nanoleaf.internal.handler.NanoleafControllerHandler;
import org.openhab.core.io.console.Console;
import org.openhab.core.io.console.extensions.AbstractConsoleCommandExtension;
import org.openhab.core.io.console.extensions.ConsoleCommandExtension;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingRegistry;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

/**
* Console commands for interacting with Nanoleaf integration
*
* @author Kai Kreuzer - Initial contribution
*/
@NonNullByDefault
@Component(service = ConsoleCommandExtension.class)
public class NanoleafCommandExtension extends AbstractConsoleCommandExtension {

private static final String CMD_LAYOUT = "layout";
private final ThingRegistry thingRegistry;

@Activate
public NanoleafCommandExtension(@Reference ThingRegistry thingRegistry) {
super("nanoleaf", "Interact with the Nanoleaf integration.");
this.thingRegistry = thingRegistry;
}

@Override
public void execute(String[] args, Console console) {
if (args.length > 0) {
String subCommand = args[0];
switch (subCommand) {
case CMD_LAYOUT:
if (args.length == 1) {
thingRegistry.getAll().forEach(thing -> {
if (thing.getUID().getBindingId().equals(NanoleafBindingConstants.BINDING_ID)) {
ThingHandler handler = thing.getHandler();
if (handler instanceof NanoleafControllerHandler) {
NanoleafControllerHandler nanoleafControllerHandler = (NanoleafControllerHandler) handler;
String layout = nanoleafControllerHandler.getLayout();
console.println("Layout of Nanoleaf controller '" + thing.getUID().getAsString()
+ "' with label '" + thing.getLabel() + "':" + System.lineSeparator());
console.println(layout);
console.println(System.lineSeparator());
}
}
});
} else if (args.length == 2) {
String uid = args[1];
Thing thing = thingRegistry.get(new ThingUID(uid));
if (thing != null) {
ThingHandler handler = thing.getHandler();
if (handler instanceof NanoleafControllerHandler) {
NanoleafControllerHandler nanoleafControllerHandler = (NanoleafControllerHandler) handler;
String layout = nanoleafControllerHandler.getLayout();
console.println(layout);
} else {
console.println("Thing with UID '" + uid.toString()
+ "' is not an initialized Nanoleaf controller.");
}
} else {
console.println("Thing with UID '" + uid.toString() + "' does not exist.");
}
} else {
printUsage(console);
}
break;

default:
console.println("Unknown command '" + subCommand + "'");
printUsage(console);
break;
}
}
}

@Override
public List<String> getUsages() {
return Arrays.asList(buildCommandUsage(CMD_LAYOUT + " <thingUID>", "Prints the panel layout on the console."));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Copyright (c) 2010-2021 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.nanoleaf.internal.commanddescription;

import java.util.List;
import java.util.stream.Collectors;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.nanoleaf.internal.NanoleafBindingConstants;
import org.openhab.binding.nanoleaf.internal.NanoleafControllerListener;
import org.openhab.binding.nanoleaf.internal.handler.NanoleafControllerHandler;
import org.openhab.binding.nanoleaf.internal.model.ControllerInfo;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseDynamicCommandDescriptionProvider;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.thing.type.DynamicCommandDescriptionProvider;
import org.openhab.core.types.CommandOption;
import org.osgi.service.component.annotations.Component;

/**
* This class provides the available effects as dynamic options as they are read from the Nanoleaf controller.
*
* @author Kai Kreuzer - Initial contribution
*
*/
@NonNullByDefault
@Component(service = { DynamicCommandDescriptionProvider.class })
public class NanoleafCommandDescriptionProvider extends BaseDynamicCommandDescriptionProvider
implements NanoleafControllerListener, ThingHandlerService {

private @Nullable ChannelUID effectChannelUID;

private @Nullable NanoleafControllerHandler bridgeHandler;

@Override
public void setThingHandler(ThingHandler handler) {
this.bridgeHandler = (NanoleafControllerHandler) handler;
bridgeHandler.registerControllerListener(this);
effectChannelUID = new ChannelUID(handler.getThing().getUID(), NanoleafBindingConstants.CHANNEL_EFFECT);
}

@Override
public @Nullable ThingHandler getThingHandler() {
return bridgeHandler;
}

@Override
public void deactivate() {
if (bridgeHandler != null) {
bridgeHandler.unregisterControllerListener(this);
}
super.deactivate();
}

@Override
public void onControllerInfoFetched(@NonNull ThingUID bridge, @NonNull ControllerInfo controllerInfo) {
List<@NonNull String> effects = controllerInfo.getEffects().getEffectsList();
ChannelUID uid = effectChannelUID;
if (effects != null && uid != null && uid.getThingUID().equals(bridge)) {
List<@NonNull CommandOption> commandOptions = effects.stream() //
.map(effect -> new CommandOption(effect, effect)) //
.collect(Collectors.toList());
setCommandOptions(uid, commandOptions);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ public String getServiceType() {

logger.trace("Discovered nanoleaf host: {} port: {} firmWare: {} modelId: {} qualifiedName: {}", host, port,
firmwareVersion, modelId, qualifiedName);
logger.debug("Adding Nanoleaf controller {} with FW version {} found at {} {} to inbox", qualifiedName,
logger.debug("Adding Nanoleaf controller {} with FW version {} found at {}:{} to inbox", qualifiedName,
firmwareVersion, host, port);
if (!OpenAPIUtils.checkRequiredFirmware(service.getPropertyString("md"), firmwareVersion)) {
logger.warn("Nanoleaf controller firmware is too old. Must be {} or higher",
logger.debug("Nanoleaf controller firmware is too old. Must be {} or higher",
MODEL_ID_LIGHTPANELS.equals(modelId) ? API_MIN_FW_VER_LIGHTPANELS : API_MIN_FW_VER_CANVAS);
}

Expand Down
Loading