]> git.basschouten.com Git - openhab-addons.git/commitdiff
[Nanoleaf] Support lines (#13881)
authorJørgen Austvik <jaustvik@acm.org>
Thu, 8 Dec 2022 21:39:45 +0000 (22:39 +0100)
committerGitHub <noreply@github.com>
Thu, 8 Dec 2022 21:39:45 +0000 (22:39 +0100)
Lines is a Nanoleaf shape we haven't been able to test earlier.

Now we have tested them, and added support for painting them as well.

They do unfortunately not support touch gestures.

Signed-off-by: Jørgen Austvik <jaustvik@acm.org>
bundles/org.openhab.binding.nanoleaf/README.md
bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/layout/ShapeType.java
bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/layout/shape/NoDraw.java [new file with mode: 0644]
bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/layout/shape/PanelFactory.java
bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/layout/shape/SingleLine.java [new file with mode: 0644]
bundles/org.openhab.binding.nanoleaf/src/test/java/org/openhab/binding/nanoleaf/internal/layout/NanoleafLayoutTest.java
bundles/org.openhab.binding.nanoleaf/src/test/resources/lines.json [new file with mode: 0644]

index c6226731fedd952dd5dcebc02b2b882deb0c9483..df5d8f52a9d8c25bd2d219d4c8f38edf96b4a9e1 100644 (file)
@@ -33,8 +33,8 @@ You can set the **color** for each panel and in the case of a Nanoleaf Canvas or
 | Shapes Mini Triangles  | NL48 | Mini Triangles                                             |     X     |       X       |
 | Elements Hexagon       | NL52 | Elements Hexagons                                          |     X     |       X       |
 | Smart Bulb             | NL45 | Smart Bulb                                                 |     -     |               |
-| Lightstrip             | NL55 | Lightstrip                                                 |     -     |               |
-| Lines                  | NL59 | Lines                                                      |     -     |               |
+| Lightstrip             | NL55 | Lightstrip                                                 |     -     |       -       |
+| Lines                  | NL59 | Lines                                                      |     X     |               |
 | Canvas                 | NL29 | Squares                                                    |     X     |       X       |
 
  x  = Supported  (-) = unknown (no device available to test)
index 471dafb362268097996ba9c13cd80166b321ba69..4e63d3de46712ba61d1763ae6983267a95be24af 100644 (file)
@@ -35,9 +35,9 @@ public enum ShapeType {
     SHAPES_CONTROLLER("Controller (Shapes)", 12, 0, 0, 1, DrawingAlgorithm.NONE),
     ELEMENTS_HEXAGON("Elements Hexagon", 14, 134, 6, 1, DrawingAlgorithm.HEXAGON),
     ELEMENTS_HEXAGON_CORNER("Elements Hexagon - Corner", 15, 58, 6, 6, DrawingAlgorithm.CORNER),
-    LINES_CONNECTOR("Lines Connector", 16, 11, 1, 1, DrawingAlgorithm.LINE),
+    LINES_CONNECTOR("Lines Connector", 16, 11, 1, 1, DrawingAlgorithm.NONE),
     LIGHT_LINES("Light Lines", 17, 154, 1, 1, DrawingAlgorithm.LINE),
-    LINES_LINES_SINGLE("Light Lines - Single Sone", 18, 77, 1, 1, DrawingAlgorithm.LINE),
+    LINES_LINES_SINGLE("Light Lines - Single Sone", 18, 77, 2, 2, DrawingAlgorithm.LINE),
     CONTROLLER_CAP("Controller Cap", 19, 11, 0, 1, DrawingAlgorithm.NONE),
     POWER_CONNECTOR("Power Connector", 20, 11, 0, 1, DrawingAlgorithm.NONE);
 
diff --git a/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/layout/shape/NoDraw.java b/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/layout/shape/NoDraw.java
new file mode 100644 (file)
index 0000000..991066f
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2010-2022 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.layout.shape;
+
+import java.awt.Graphics2D;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.nanoleaf.internal.layout.DrawingSettings;
+import org.openhab.binding.nanoleaf.internal.layout.PanelState;
+import org.openhab.binding.nanoleaf.internal.layout.Point2D;
+import org.openhab.binding.nanoleaf.internal.layout.ShapeType;
+
+/**
+ * A panel that shouldn't be drawn (power connector, controller, ...).
+ *
+ * Especially lines can have controllers and power connectors etc on top of each other.
+ *
+ * @author Jørgen Austvik - Initial contribution
+ */
+@NonNullByDefault
+public class NoDraw extends Panel {
+
+    private final Point2D position;
+
+    public NoDraw(ShapeType shapeType, int panelId, Point2D position) {
+        super(shapeType);
+        this.position = position;
+    }
+
+    @Override
+    public List<Point2D> generateOutline() {
+        return Arrays.asList(position);
+    }
+
+    @Override
+    public void draw(Graphics2D graphics, DrawingSettings settings, PanelState state) {
+    }
+}
index ec15a0f6743fffb70f723ebee38d152b8bca8d86..f0425f45b5b3f9cbd7b165bfc2675e75ecccf679 100644 (file)
@@ -81,13 +81,21 @@ public class PanelFactory {
                 Point2D pos3 = new Point2D(hexShape.getPosX(), hexShape.getPosY());
                 return new Hexagon(shapeType, hexShape.getPanelId(), pos3, hexShape.getOrientation());
 
+            case LINE:
+                return new SingleLine(shapeType, positionDatum);
+
             case CORNER:
                 return new HexagonCorners(shapeType, positionDatum);
 
+            case NONE:
+                PositionDatum noShape = positionDatum.get(0);
+                Point2D pos4 = new Point2D(noShape.getPosX(), noShape.getPosY());
+                return new NoDraw(shapeType, noShape.getPanelId(), pos4);
+
             default:
                 PositionDatum shape = positionDatum.get(0);
-                Point2D pos4 = new Point2D(shape.getPosX(), shape.getPosY());
-                return new Point(shapeType, shape.getPanelId(), pos4);
+                Point2D pos5 = new Point2D(shape.getPosX(), shape.getPosY());
+                return new Point(shapeType, shape.getPanelId(), pos5);
         }
     }
 }
diff --git a/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/layout/shape/SingleLine.java b/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/layout/shape/SingleLine.java
new file mode 100644 (file)
index 0000000..2097f42
--- /dev/null
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2010-2022 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.layout.shape;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Polygon;
+import java.awt.Stroke;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.nanoleaf.internal.layout.DrawingSettings;
+import org.openhab.binding.nanoleaf.internal.layout.ImagePoint2D;
+import org.openhab.binding.nanoleaf.internal.layout.PanelState;
+import org.openhab.binding.nanoleaf.internal.layout.Point2D;
+import org.openhab.binding.nanoleaf.internal.layout.ShapeType;
+import org.openhab.binding.nanoleaf.internal.model.PositionDatum;
+import org.openhab.core.library.types.HSBType;
+
+/**
+ * A single line.
+ *
+ * @author Jørgen Austvik - Initial contribution
+ */
+@NonNullByDefault
+public class SingleLine extends Panel {
+
+    private static final int CORNER_DIAMETER = 4;
+    private static final int LINE_WIDTH = 6;
+
+    private final List<PositionDatum> corners;
+
+    public SingleLine(ShapeType shapeType, List<PositionDatum> corners) {
+        super(shapeType);
+
+        this.corners = Collections.unmodifiableList(new ArrayList<>(corners));
+    }
+
+    @Override
+    public List<Point2D> generateOutline() {
+        List<Point2D> result = new ArrayList<>(corners.size());
+        for (PositionDatum corner : corners) {
+            result.add(new Point2D(corner.getPosX(), corner.getPosY()));
+        }
+
+        return result;
+    }
+
+    @Override
+    public void draw(Graphics2D graphics, DrawingSettings settings, PanelState state) {
+        List<ImagePoint2D> outline = settings.generateImagePoints(generateOutline());
+        Polygon p = new Polygon();
+        for (int i = 0; i < outline.size(); i++) {
+            ImagePoint2D pos = outline.get(i);
+            p.addPoint(pos.getX(), pos.getY());
+        }
+
+        if (settings.shouldFillWithColor()) {
+            Color corner1Color = getColor(corners.get(0).getPanelId(), state);
+            Color corner2Color = getColor(corners.get(0).getPanelId(), state);
+
+            ImagePoint2D center = findCenter(outline);
+
+            Stroke oldStroke = graphics.getStroke();
+            Stroke lineStroke = new BasicStroke(LINE_WIDTH, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
+            graphics.setStroke(lineStroke);
+            graphics.setColor(corner1Color);
+            graphics.drawLine(outline.get(0).getX(), outline.get(0).getY(), center.getX(), center.getY());
+            graphics.setColor(corner2Color);
+            graphics.drawLine(outline.get(1).getX(), outline.get(1).getY(), center.getX(), center.getY());
+            graphics.setStroke(oldStroke);
+        }
+
+        if (settings.shouldDrawOutline()) {
+            graphics.setColor(settings.getOutlineColor());
+            graphics.drawPolygon(p);
+        }
+
+        if (settings.shouldDrawCorners()) {
+            for (PositionDatum corner : corners) {
+                ImagePoint2D position = settings.generateImagePoint(new Point2D(corner.getPosX(), corner.getPosY()));
+                graphics.setColor(getColor(corner.getPanelId(), state));
+                graphics.fillOval(position.getX() - CORNER_DIAMETER / 2, position.getY() - CORNER_DIAMETER / 2,
+                        CORNER_DIAMETER, CORNER_DIAMETER);
+
+                if (settings.shouldDrawOutline()) {
+                    graphics.setColor(settings.getOutlineColor());
+                    graphics.drawOval(position.getX() - CORNER_DIAMETER / 2, position.getY() - CORNER_DIAMETER / 2,
+                            CORNER_DIAMETER, CORNER_DIAMETER);
+                }
+            }
+        }
+
+        if (settings.shouldDrawLabels()) {
+            graphics.setColor(settings.getLabelColor());
+
+            for (PositionDatum corner : corners) {
+                ImagePoint2D position = settings.generateImagePoint(new Point2D(corner.getPosX(), corner.getPosY()));
+                graphics.drawString(Integer.toString(corner.getPanelId()), position.getX(), position.getY());
+            }
+        }
+    }
+
+    private ImagePoint2D findCenter(List<ImagePoint2D> outline) {
+        Point2D[] bounds = findBounds(outline);
+        int midX = bounds[0].getX() + (bounds[1].getX() - bounds[0].getX()) / 2;
+        int midY = bounds[0].getY() + (bounds[1].getY() - bounds[0].getY()) / 2;
+        return new ImagePoint2D(midX, midY);
+    }
+
+    private static Color getColor(int panelId, PanelState state) {
+        HSBType color = state.getHSBForPanel(panelId);
+        return new Color(color.getRGB());
+    }
+}
index c6344abd54da068f8d6e72893261b5c9b50809f7..e7704879424c6b64c474375d035713e7a42e9dd6 100644 (file)
@@ -47,7 +47,8 @@ public class NanoleafLayoutTest {
     static @Nullable Path temporaryDirectory;
 
     @ParameterizedTest
-    @ValueSource(strings = { "lasvegas.json", "theduck.json", "squares.json", "wings.json", "spaceinvader.json" })
+    @ValueSource(strings = { "lasvegas.json", "theduck.json", "squares.json", "wings.json", "spaceinvader.json",
+            "lines.json" })
     public void testFile(String fileName) throws Exception {
         Path file = Path.of("src/test/resources/", fileName);
         assertTrue(Files.exists(file), "File should exist: " + file);
diff --git a/bundles/org.openhab.binding.nanoleaf/src/test/resources/lines.json b/bundles/org.openhab.binding.nanoleaf/src/test/resources/lines.json
new file mode 100644 (file)
index 0000000..592d886
--- /dev/null
@@ -0,0 +1 @@
+{"name":"Lines","serialNo":"S1234567","manufacturer":"Nanoleaf","firmwareVersion":"7.1.0","hardwareVersion":"0.0.4-0","model":"NL59","discovery":null,"effects":{"effectsList":["Beat Drop","Cotton Candy","Cozy Blaze","Fiesta","Good Vibes","Hip Hop","Jalapeno Heat","Kaleidoscope","Mountain Air","Mystic Night","Neon Dreams","Northern Lights","Pop Rocks","Prism","Radioactive","Raspberry Lemonade","Sakura Blossom","Starry Sky","Tuscany Sunset","Waterfall"],"select":"Raspberry Lemonade"},"firmwareUpgrade":null,"panelLayout":{"globalOrientation":{"value":88,"max":360,"min":0},"layout":{"numPanels":13,"sideLength":154,"positionData":[{"panelId":15376,"x":227,"y":337,"o":0,"shapeType":20},{"panelId":12105,"x":227,"y":212,"o":0,"shapeType":18},{"panelId":56841,"x":227,"y":289,"o":0,"shapeType":18},{"panelId":24127,"x":227,"y":164,"o":120,"shapeType":16},{"panelId":55776,"x":119,"y":274,"o":300,"shapeType":18},{"panelId":10400,"x":185,"y":313,"o":300,"shapeType":18},{"panelId":54069,"x":77,"y":250,"o":180,"shapeType":16},{"panelId":6876,"x":119,"y":226,"o":240,"shapeType":18},{"panelId":35357,"x":185,"y":188,"o":240,"shapeType":18},{"panelId":45376,"x":77,"y":125,"o":0,"shapeType":18},{"panelId":16384,"x":77,"y":202,"o":0,"shapeType":18},{"panelId":49828,"x":77,"y":77,"o":300,"shapeType":16},{"panelId":5591,"x":227,"y":337,"o":0,"shapeType":19}]}},"qkihnokomhartlnp":{},"schedules":{},"state":{"brightness":{"value":63,"max":100,"min":0},"colorMode":"effect","ct":{"value":4000,"max":6500,"min":1200},"hue":{"value":0,"max":360,"min":0},"on":{"value":true},"sat":{"value":0,"max":100,"min":0}}}