[Nanolaef] Visual State Bugfix (#13880)

* Nanoleaf Visual State fix

Fix the visual state channel name.

Also:
- Better name (from state to visual state) of the (new) channel
- Better logs which has helped us debug the problem
- Some more information on when it will work in the README

Signed-off-by: Jørgen Austvik <jaustvik@acm.org>
This commit is contained in:
Jørgen Austvik 2022-12-08 21:00:11 +01:00 committed by GitHub
parent 6a16c889f2
commit 177ce2a217
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 49 additions and 10 deletions

View File

@ -110,6 +110,8 @@ Compare the following output with the right picture at the beginning of the arti
The state channel shows an image of the panels on the wall.
You have to configure things for each panel to get the correct color.
Since the colors of the panels can make it difficult to see the panel ids, please use the layout channel where the background color is always white to identify them.
For state to work, you need to set static colors to your panel.
This is because Nanoleaf does not return updates on colors for dynamic effects and animations.
![Image](doc/NanoCanvas_rendered.jpg)

View File

@ -59,7 +59,7 @@ public class NanoleafBindingConstants {
public static final String CHANNEL_SWIPE_EVENT_LEFT = "LEFT";
public static final String CHANNEL_SWIPE_EVENT_RIGHT = "RIGHT";
public static final String CHANNEL_LAYOUT = "layout";
public static final String CHANNEL_STATE = "state";
public static final String CHANNEL_VISUAL_STATE = "visualState";
// List of light panel channels
public static final String CHANNEL_PANEL_COLOR = "color";

View File

@ -669,7 +669,7 @@ public class NanoleafControllerHandler extends BaseBridgeHandler {
updateProperties();
updateConfiguration();
updateLayout(controllerInfo.getPanelLayout());
updateState(controllerInfo.getPanelLayout());
updateVisualState(controllerInfo.getPanelLayout());
for (NanoleafControllerListener controllerListener : controllerListeners) {
controllerListener.onControllerInfoFetched(getThing().getUID(), controllerInfo);
@ -711,16 +711,27 @@ public class NanoleafControllerHandler extends BaseBridgeHandler {
}
}
private void updateState(PanelLayout panelLayout) {
ChannelUID stateChannel = new ChannelUID(getThing().getUID(), CHANNEL_STATE);
private void updateVisualState(PanelLayout panelLayout) {
ChannelUID stateChannel = new ChannelUID(getThing().getUID(), CHANNEL_VISUAL_STATE);
Bridge bridge = getThing();
List<Thing> things = bridge.getThings();
if (things == null) {
logger.trace("No things to get state from!");
return;
}
try {
LayoutSettings settings = new LayoutSettings(false, true, true, true);
byte[] bytes = NanoleafLayout.render(panelLayout, new PanelState(things), settings);
logger.trace("Getting panel state for {} things", things.size());
PanelState panelState = new PanelState(things);
byte[] bytes = NanoleafLayout.render(panelLayout, panelState, settings);
if (bytes.length > 0) {
updateState(stateChannel, new RawType(bytes, "image/png"));
logger.trace("Rendered visual state of panel {} in updateState has {} bytes", getThing().getUID(),
bytes.length);
} else {
logger.debug("Visual state of {} failed to produce any image", getThing().getUID());
}
previousPanelLayout = panelLayout;
@ -740,7 +751,8 @@ public class NanoleafControllerHandler extends BaseBridgeHandler {
}
if (previousPanelLayout.equals(panelLayout)) {
logger.trace("Not rendering panel layout as it is the same as previous rendered panel layout");
logger.trace("Not rendering panel layout for {} as it is the same as previous rendered panel layout",
getThing().getUID());
return;
}
@ -751,6 +763,10 @@ public class NanoleafControllerHandler extends BaseBridgeHandler {
byte[] bytes = NanoleafLayout.render(panelLayout, new PanelState(things), settings);
if (bytes.length > 0) {
updateState(layoutChannel, new RawType(bytes, "image/png"));
logger.trace("Rendered layout of panel {} in updateState has {} bytes", getThing().getUID(),
bytes.length);
} else {
logger.debug("Layout of {} failed to produce any image", getThing().getUID());
}
previousPanelLayout = panelLayout;

View File

@ -31,6 +31,8 @@ import org.openhab.binding.nanoleaf.internal.model.GlobalOrientation;
import org.openhab.binding.nanoleaf.internal.model.Layout;
import org.openhab.binding.nanoleaf.internal.model.PanelLayout;
import org.openhab.binding.nanoleaf.internal.model.PositionDatum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Renders the Nanoleaf layout to an image.
@ -40,6 +42,7 @@ import org.openhab.binding.nanoleaf.internal.model.PositionDatum;
@NonNullByDefault
public class NanoleafLayout {
private static final Logger logger = LoggerFactory.getLogger(NanoleafLayout.class);
private static final Color COLOR_BACKGROUND = Color.WHITE;
public static byte[] render(PanelLayout panelLayout, PanelState state, LayoutSettings settings) throws IOException {
@ -51,11 +54,13 @@ public class NanoleafLayout {
Layout layout = panelLayout.getLayout();
if (layout == null) {
logger.warn("Returning no image as we don't have any layout to render");
return new byte[] {};
}
List<PositionDatum> positionDatums = layout.getPositionData();
if (positionDatums == null) {
logger.warn("Returning no image as we don't have any position datums to render");
return new byte[] {};
}

View File

@ -23,6 +23,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.nanoleaf.internal.handler.NanoleafPanelHandler;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Stores the state of the panels.
@ -32,6 +34,7 @@ import org.openhab.core.thing.Thing;
@NonNullByDefault
public class PanelState {
private static final Logger logger = LoggerFactory.getLogger(PanelState.class);
private final Map<Integer, HSBType> panelStates = new HashMap<>();
public PanelState(List<Thing> panels) {
@ -40,13 +43,26 @@ public class PanelState {
NanoleafPanelHandler panelHandler = (NanoleafPanelHandler) panel.getHandler();
if (panelHandler != null) {
HSBType c = panelHandler.getColor();
if (c == null) {
logger.trace("Panel {}: Failed to get color", panelId);
}
HSBType color = (c == null) ? HSBType.BLACK : c;
panelStates.put(panelId, color);
} else {
logger.trace("Panel {}: Couldn't find handler", panelId);
}
}
}
public HSBType getHSBForPanel(Integer panelId) {
if (logger.isTraceEnabled()) {
if (!panelStates.containsKey(panelId)) {
logger.trace("Failed to get color for panel {}, falling back to black", panelId);
}
}
return panelStates.getOrDefault(panelId, HSBType.BLACK);
}
}

View File

@ -40,8 +40,8 @@ channel-type.nanoleaf.swipe.label = Swipe
channel-type.nanoleaf.swipe.description = Swipe over the panels
channel-type.nanoleaf.layout.label = Layout
channel-type.nanoleaf.layout.description = Layout of the panels
channel-type.nanoleaf.state.label = State
channel-type.nanoleaf.state.description = Current state of the panels
channel-type.nanoleaf.state.label = Visual State
channel-type.nanoleaf.state.description = Current visual state of the panels
# error messages
error.nanoleaf.controller.noIp = IP/host address and/or port are not configured for the controller.

View File

@ -19,7 +19,7 @@
<channel id="rhythmMode" typeId="rhythmMode"/>
<channel id="swipe" typeId="swipe"/>
<channel id="layout" typeId="layout"/>
<channel id="currentState" typeId="state"/>
<channel id="visualState" typeId="visualState"/>
</channels>
<properties>
@ -115,7 +115,7 @@
<description>@text/channel-type.nanoleaf.layout.description</description>
</channel-type>
<channel-type id="state">
<channel-type id="visualState">
<item-type>Image</item-type>
<label>@text/channel-type.nanoleaf.state.label</label>
<description>@text/channel-type.nanoleaf.state.description</description>