[nanoleaf] CODEOWNERs, add Shapes Support, beta-firmware support (#10029)
Signed-off-by: Stefan Höhn <stefan@andreaundstefanhoehn.de>
This commit is contained in:
parent
f9a982e548
commit
570f86d043
@ -170,7 +170,7 @@
|
|||||||
/bundles/org.openhab.binding.mqtt.homeassistant/ @davidgraeff
|
/bundles/org.openhab.binding.mqtt.homeassistant/ @davidgraeff
|
||||||
/bundles/org.openhab.binding.mqtt.homie/ @davidgraeff
|
/bundles/org.openhab.binding.mqtt.homie/ @davidgraeff
|
||||||
/bundles/org.openhab.binding.mystrom/ @pail23
|
/bundles/org.openhab.binding.mystrom/ @pail23
|
||||||
/bundles/org.openhab.binding.nanoleaf/ @raepple
|
/bundles/org.openhab.binding.nanoleaf/ @raepple @stefan-hoehn
|
||||||
/bundles/org.openhab.binding.neato/ @jjlauterbach
|
/bundles/org.openhab.binding.neato/ @jjlauterbach
|
||||||
/bundles/org.openhab.binding.neeo/ @tmrobert8
|
/bundles/org.openhab.binding.neeo/ @tmrobert8
|
||||||
/bundles/org.openhab.binding.neohub/ @andrewfg
|
/bundles/org.openhab.binding.neohub/ @andrewfg
|
||||||
|
|||||||
@ -11,8 +11,10 @@ The binding uses the [Nanoleaf OpenAPI](https://forum.nanoleaf.me/docs/openapi),
|
|||||||
|
|
||||||
## Supported Things
|
## Supported Things
|
||||||
|
|
||||||
|
Nanoleaf provides a bunch of devices of which some are connected to Wifi whereas other use the new Thread Technology. This binding only supports devices that are connected to Wifi.
|
||||||
|
|
||||||
Currently Nanoleaf's "Light Panels" and "Canvas" devices are supported.
|
Currently Nanoleaf's "Light Panels" and "Canvas" devices are supported.
|
||||||
Note that only the canvas type does support the touch functionality.
|
Note that only specific types do support the touch functionality, so the binding needs to check these types.
|
||||||
|
|
||||||
The binding supports two thing types: controller and lightpanel.
|
The binding supports two thing types: controller and lightpanel.
|
||||||
|
|
||||||
@ -23,6 +25,17 @@ The lightpanel (singular) thing controls one of the individual panels/canvas tha
|
|||||||
Each individual panel has therefore its own id assigned to it.
|
Each individual panel has therefore its own id assigned to it.
|
||||||
You can set the **color** for each panel or turn it on (white) or off (black) and in the case of a nanoleaf canvas you can even detect single and double **touch events** related to an individual panel which opens a whole new world of controlling any other device within your openHAB environment.
|
You can set the **color** for each panel or turn it on (white) or off (black) and in the case of a nanoleaf canvas you can even detect single and double **touch events** related to an individual panel which opens a whole new world of controlling any other device within your openHAB environment.
|
||||||
|
|
||||||
|
|
||||||
|
| Nanoleaf Name | Type | Description | supported | touch support |
|
||||||
|
| ---------------------- | ---- | ---------------------------------------------------------- | --------- | ------------- |
|
||||||
|
| Light Panels | NL22 | Triangles 1st Generation | X | (-) |
|
||||||
|
| Shapes Triangle | NL42 | Triangles 2nd Generation (rounded edges) | X | X |
|
||||||
|
| Shapes Hexagon | NL42 | Triangles 2nd Generation (rounded edges) | (X) | (X) |
|
||||||
|
| Shapes Mini Triangles | ?? | Mini Triangles | ? | ? |
|
||||||
|
| Canvas | NL29 | Squares | X | X |
|
||||||
|
|
||||||
|
x = Supported (x) = Supported but only tested by community (-) = unknown (no device available to test)
|
||||||
|
|
||||||
Note: In case of major changes of a binding (like adding more features to a thing) it becomes necessary to delete your things due to the things not being compatible anymore.
|
Note: In case of major changes of a binding (like adding more features to a thing) it becomes necessary to delete your things due to the things not being compatible anymore.
|
||||||
Don't worry too much though as they will be easily redetected and nothing really is lost.
|
Don't worry too much though as they will be easily redetected and nothing really is lost.
|
||||||
Just make sure that you delete them and rediscover as described below.
|
Just make sure that you delete them and rediscover as described below.
|
||||||
|
|||||||
@ -12,6 +12,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.nanoleaf.internal;
|
package org.openhab.binding.nanoleaf.internal;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
|
|
||||||
@ -71,9 +74,12 @@ public class NanoleafBindingConstants {
|
|||||||
public static final String API_MIN_FW_VER_LIGHTPANELS = "1.5.0";
|
public static final String API_MIN_FW_VER_LIGHTPANELS = "1.5.0";
|
||||||
public static final String API_MIN_FW_VER_CANVAS = "1.1.0";
|
public static final String API_MIN_FW_VER_CANVAS = "1.1.0";
|
||||||
public static final String MODEL_ID_LIGHTPANELS = "NL22";
|
public static final String MODEL_ID_LIGHTPANELS = "NL22";
|
||||||
public static final String MODEL_ID_CANVAS = "NL29";
|
|
||||||
|
public static final List<String> MODELS_WITH_TOUCHSUPPORT = Arrays.asList("NL29", "NL42");
|
||||||
public static final String DEVICE_TYPE_LIGHTPANELS = "lightPanels";
|
public static final String DEVICE_TYPE_LIGHTPANELS = "lightPanels";
|
||||||
public static final String DEVICE_TYPE_CANVAS = "canvas";
|
public static final String DEVICE_TYPE_TOUCHSUPPORT = "canvas"; // we need to keep this enum for backward
|
||||||
|
// compatibility even though not only canvas type
|
||||||
|
// support touch
|
||||||
|
|
||||||
// mDNS discovery service type
|
// mDNS discovery service type
|
||||||
// see http://forum.nanoleaf.me/docs/openapi#_gf9l5guxt8r0
|
// see http://forum.nanoleaf.me/docs/openapi#_gf9l5guxt8r0
|
||||||
|
|||||||
@ -49,6 +49,7 @@ public class OpenAPIUtils {
|
|||||||
|
|
||||||
// Regular expression for firmware version
|
// Regular expression for firmware version
|
||||||
private static final Pattern FIRMWARE_VERSION_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)");
|
private static final Pattern FIRMWARE_VERSION_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)");
|
||||||
|
private static final Pattern FIRMWARE_VERSION_PATTERN_BETA = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)-(\\d+)");
|
||||||
|
|
||||||
public static Request requestBuilder(HttpClient httpClient, NanoleafControllerConfig controllerConfig,
|
public static Request requestBuilder(HttpClient httpClient, NanoleafControllerConfig controllerConfig,
|
||||||
String apiOperation, HttpMethod method) throws NanoleafException {
|
String apiOperation, HttpMethod method) throws NanoleafException {
|
||||||
@ -162,11 +163,21 @@ public class OpenAPIUtils {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int[] getFirmwareVersionNumbers(String firmwareVersion) throws IllegalArgumentException {
|
public static int[] getFirmwareVersionNumbers(String firmwareVersion) throws IllegalArgumentException {
|
||||||
|
LOGGER.debug("firmwareVersion: {}", firmwareVersion);
|
||||||
Matcher m = FIRMWARE_VERSION_PATTERN.matcher(firmwareVersion);
|
Matcher m = FIRMWARE_VERSION_PATTERN.matcher(firmwareVersion);
|
||||||
if (!m.matches()) {
|
|
||||||
throw new IllegalArgumentException("Malformed controller firmware version");
|
if (m.matches()) {
|
||||||
|
return new int[] { Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)),
|
||||||
|
Integer.parseInt(m.group(3)) };
|
||||||
|
} else {
|
||||||
|
m = FIRMWARE_VERSION_PATTERN_BETA.matcher(firmwareVersion);
|
||||||
|
if (m.matches()) {
|
||||||
|
return new int[] { Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)),
|
||||||
|
Integer.parseInt(m.group(3)), Integer.parseInt(m.group(4)) };
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Malformed controller firmware version " + firmwareVersion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new int[] { Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)), Integer.parseInt(m.group(3)) };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,7 +75,7 @@ public class NanoleafMDNSDiscoveryParticipant implements MDNSDiscoveryParticipan
|
|||||||
properties.put(Thing.PROPERTY_MODEL_ID, modelId);
|
properties.put(Thing.PROPERTY_MODEL_ID, modelId);
|
||||||
properties.put(Thing.PROPERTY_VENDOR, "Nanoleaf");
|
properties.put(Thing.PROPERTY_VENDOR, "Nanoleaf");
|
||||||
String qualifiedName = service.getQualifiedName();
|
String qualifiedName = service.getQualifiedName();
|
||||||
logger.debug("AVR found: {}", qualifiedName);
|
logger.debug("Device found: {}", qualifiedName);
|
||||||
|
|
||||||
logger.trace("Discovered nanoleaf host: {} port: {} firmWare: {} modelId: {} qualifiedName: {}", host, port,
|
logger.trace("Discovered nanoleaf host: {} port: {} firmWare: {} modelId: {} qualifiedName: {}", host, port,
|
||||||
firmwareVersion, modelId, qualifiedName);
|
firmwareVersion, modelId, qualifiedName);
|
||||||
|
|||||||
@ -17,10 +17,7 @@ import static org.openhab.binding.nanoleaf.internal.NanoleafBindingConstants.*;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Scanner;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
@ -132,8 +129,8 @@ public class NanoleafControllerHandler extends BaseBridgeHandler {
|
|||||||
|
|
||||||
Map<String, String> properties = getThing().getProperties();
|
Map<String, String> properties = getThing().getProperties();
|
||||||
String propertyModelId = properties.get(Thing.PROPERTY_MODEL_ID);
|
String propertyModelId = properties.get(Thing.PROPERTY_MODEL_ID);
|
||||||
if (MODEL_ID_CANVAS.equals(propertyModelId)) {
|
if (hasTouchSupport(propertyModelId)) {
|
||||||
config.deviceType = DEVICE_TYPE_CANVAS;
|
config.deviceType = DEVICE_TYPE_TOUCHSUPPORT;
|
||||||
} else {
|
} else {
|
||||||
config.deviceType = DEVICE_TYPE_LIGHTPANELS;
|
config.deviceType = DEVICE_TYPE_LIGHTPANELS;
|
||||||
}
|
}
|
||||||
@ -334,9 +331,9 @@ public class NanoleafControllerHandler extends BaseBridgeHandler {
|
|||||||
|
|
||||||
private synchronized void startTouchJob() {
|
private synchronized void startTouchJob() {
|
||||||
NanoleafControllerConfig config = getConfigAs(NanoleafControllerConfig.class);
|
NanoleafControllerConfig config = getConfigAs(NanoleafControllerConfig.class);
|
||||||
if (!config.deviceType.equals(DEVICE_TYPE_CANVAS)) {
|
if (!config.deviceType.equals(DEVICE_TYPE_TOUCHSUPPORT)) {
|
||||||
logger.debug("NOT starting TouchJob for Panel {} because it has wrong device type '{}' vs required '{}'",
|
logger.debug("NOT starting TouchJob for Panel {} because it has wrong device type '{}' vs required '{}'",
|
||||||
this.getThing().getUID(), config.deviceType, DEVICE_TYPE_CANVAS);
|
this.getThing().getUID(), config.deviceType, DEVICE_TYPE_TOUCHSUPPORT);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Starting TouchJob for Panel {}", this.getThing().getUID());
|
logger.debug("Starting TouchJob for Panel {}", this.getThing().getUID());
|
||||||
@ -353,6 +350,10 @@ public class NanoleafControllerHandler extends BaseBridgeHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasTouchSupport(@Nullable String deviceType) {
|
||||||
|
return (MODELS_WITH_TOUCHSUPPORT.contains(deviceType));
|
||||||
|
}
|
||||||
|
|
||||||
private synchronized void stopTouchJob() {
|
private synchronized void stopTouchJob() {
|
||||||
if (touchJob != null && !touchJob.isCancelled()) {
|
if (touchJob != null && !touchJob.isCancelled()) {
|
||||||
logger.debug("Stop touch job");
|
logger.debug("Stop touch job");
|
||||||
@ -636,9 +637,9 @@ public class NanoleafControllerHandler extends BaseBridgeHandler {
|
|||||||
|
|
||||||
Configuration config = editConfiguration();
|
Configuration config = editConfiguration();
|
||||||
|
|
||||||
if (MODEL_ID_CANVAS.equals(controllerInfo.getModel())) {
|
if (hasTouchSupport(controllerInfo.getModel())) {
|
||||||
config.put(NanoleafControllerConfig.DEVICE_TYPE, DEVICE_TYPE_CANVAS);
|
config.put(NanoleafControllerConfig.DEVICE_TYPE, DEVICE_TYPE_TOUCHSUPPORT);
|
||||||
logger.debug("Set to device type {}", DEVICE_TYPE_CANVAS);
|
logger.debug("Set to device type {}", DEVICE_TYPE_TOUCHSUPPORT);
|
||||||
} else {
|
} else {
|
||||||
config.put(NanoleafControllerConfig.DEVICE_TYPE, DEVICE_TYPE_LIGHTPANELS);
|
config.put(NanoleafControllerConfig.DEVICE_TYPE, DEVICE_TYPE_LIGHTPANELS);
|
||||||
logger.debug("Set to device type {}", DEVICE_TYPE_LIGHTPANELS);
|
logger.debug("Set to device type {}", DEVICE_TYPE_LIGHTPANELS);
|
||||||
|
|||||||
@ -318,7 +318,7 @@ public class NanoleafPanelHandler extends BaseThingHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (NanoleafNotFoundException nfe) {
|
} catch (NanoleafNotFoundException nfe) {
|
||||||
logger.warn("Panel data could not be retrieved as no data was returned (static type missing?) : {}",
|
logger.debug("Panel data could not be retrieved as no data was returned (static type missing?) : {}",
|
||||||
nfe.getMessage());
|
nfe.getMessage());
|
||||||
} catch (NanoleafBadRequestException nfe) {
|
} catch (NanoleafBadRequestException nfe) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
binding.nanoleaf.name = Nanoleaf Binding
|
binding.nanoleaf.name = Nanoleaf Binding
|
||||||
binding.nanoleaf.description = Integrates the Nanoleaf Light Panels (v150320)
|
binding.nanoleaf.description = Integrates the Nanoleaf Light Panels (v010221)
|
||||||
|
|
||||||
# thing types
|
# thing types
|
||||||
thing-type.nanoleaf.controller.name = Nanoleaf Controller
|
thing-type.nanoleaf.controller.name = Nanoleaf Controller
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
binding.nanoleaf.name = Nanoleaf Binding
|
binding.nanoleaf.name = Nanoleaf Binding
|
||||||
binding.nanoleaf.description = Binding für die Integration des Nanoleaf Light Panels (v150320)
|
binding.nanoleaf.description = Binding für die Integration des Nanoleaf Light Panels (Ein mit dem Controller verbundenes Paneel)
|
||||||
|
|
||||||
# thing types
|
# thing types
|
||||||
thing-type.nanoleaf.controller.name = Nanoleaf Controller
|
thing-type.nanoleaf.controller.name = Nanoleaf Controller
|
||||||
|
|||||||
@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test Firmware check
|
||||||
|
*
|
||||||
|
* @author Stefan Höhn - Initial contribution
|
||||||
|
*/
|
||||||
|
|
||||||
|
@NonNullByDefault
|
||||||
|
public class OpenAPUUtilsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStateOn() {
|
||||||
|
int[] versions = OpenAPIUtils.getFirmwareVersionNumbers("5.1.2");
|
||||||
|
assertThat(versions[0], is(5));
|
||||||
|
assertThat(versions[1], is(1));
|
||||||
|
assertThat(versions[2], is(2));
|
||||||
|
int[] versions2 = OpenAPIUtils.getFirmwareVersionNumbers("5.1.2-4");
|
||||||
|
assertThat(versions2[0], is(5));
|
||||||
|
assertThat(versions2[1], is(1));
|
||||||
|
assertThat(versions2[2], is(2));
|
||||||
|
assertThat(versions2[3], is(4));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user