Skip to content

Commit

Permalink
Fix state updates for components that have additional state processin…
Browse files Browse the repository at this point in the history
…g handlers

Only need to adjust for channels that could be renamed due to being single
channel components

Signed-off-by: Cody Cutrer <[email protected]>
  • Loading branch information
ccutrer committed Oct 2, 2024
1 parent d86a5bf commit 884f472
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ protected void buildChannels() {
.build();
}

boolean hasColorChannel = false;
if (channelConfiguration.rgbStateTopic != null || channelConfiguration.rgbCommandTopic != null) {
hasColorChannel = true;
hiddenChannels.add(rgbChannel = buildChannel(RGB_CHANNEL_ID, ComponentChannelType.COLOR,
Expand Down Expand Up @@ -167,7 +168,7 @@ protected void buildChannels() {
if (localBrightnessChannel != null) {
hiddenChannels.add(localBrightnessChannel);
}
buildChannel(COLOR_CHANNEL_ID, ComponentChannelType.COLOR, colorValue, "Color", this)
colorChannel = buildChannel(COLOR_CHANNEL_ID, ComponentChannelType.COLOR, colorValue, "Color", this)
.commandTopic(DUMMY_TOPIC, channelConfiguration.isRetain(), channelConfiguration.getQos())
.commandFilter(this::handleColorCommand).build();
} else if (localBrightnessChannel != null) {
Expand Down Expand Up @@ -280,74 +281,76 @@ private boolean handleColorCommand(Command command) {
@Override
public void updateChannelState(ChannelUID channel, State state) {
ChannelStateUpdateListener listener = this.channelStateUpdateListener;
switch (channel.getIdWithoutGroup()) {
case ON_OFF_CHANNEL_ID:
if (hasColorChannel) {
HSBType newOnState = colorValue.getChannelState() instanceof HSBType
? (HSBType) colorValue.getChannelState()
: HSBType.WHITE;
if (state.equals(OnOffType.ON)) {
colorValue.update(newOnState);
}

listener.updateChannelState(buildChannelUID(COLOR_CHANNEL_ID),
state.equals(OnOffType.ON) ? newOnState : HSBType.BLACK);
} else if (brightnessChannel != null) {
listener.updateChannelState(new ChannelUID(channel.getThingUID(), BRIGHTNESS_CHANNEL_ID),
state.equals(OnOffType.ON) ? brightnessValue.getChannelState() : PercentType.ZERO);
} else {
listener.updateChannelState(channel, state);
}
return;
case BRIGHTNESS_CHANNEL_ID:
onOffValue.update(Objects.requireNonNull(state.as(OnOffType.class)));
if (hasColorChannel) {
if (colorValue.getChannelState() instanceof HSBType) {
HSBType hsb = (HSBType) (colorValue.getChannelState());
colorValue.update(new HSBType(hsb.getHue(), hsb.getSaturation(),
(PercentType) brightnessValue.getChannelState()));
} else {
colorValue.update(new HSBType(DecimalType.ZERO, PercentType.ZERO,
(PercentType) brightnessValue.getChannelState()));
}
listener.updateChannelState(buildChannelUID(COLOR_CHANNEL_ID), colorValue.getChannelState());
} else {
listener.updateChannelState(channel, state);
}
return;
case COLOR_TEMP_CHANNEL_ID:
case EFFECT_CHANNEL_ID:
// Real channels; pass through
listener.updateChannelState(channel, state);
return;
case HS_CHANNEL_ID:
case XY_CHANNEL_ID:
if (brightnessValue.getChannelState() instanceof UnDefType) {
brightnessValue.update(PercentType.HUNDRED);
}
String[] split = state.toString().split(",");
if (split.length != 2) {
throw new IllegalArgumentException(state.toString() + " is not a valid string syntax");
String id = channel.getIdWithoutGroup();
ComponentChannel localBrightnessChannel = brightnessChannel;
ComponentChannel localColorChannel = colorChannel;
ChannelUID primaryChannelUID;
if (localColorChannel != null) {
primaryChannelUID = localColorChannel.getChannel().getUID();
} else if (localBrightnessChannel != null) {
primaryChannelUID = localBrightnessChannel.getChannel().getUID();
} else {
primaryChannelUID = onOffChannel.getChannel().getUID();
}
// on_off, brightness, and color might exist as a sole channel, which means
// they got renamed. they need to be compared against the actual UID of the
// channel. all the rest we can just check against the basic ID
if (channel.equals(onOffChannel.getChannel().getUID())) {
if (localColorChannel != null) {
HSBType newOnState = colorValue.getChannelState() instanceof HSBType
? (HSBType) colorValue.getChannelState()
: HSBType.WHITE;
if (state.equals(OnOffType.ON)) {
colorValue.update(newOnState);
}
float x = Float.parseFloat(split[0]);
float y = Float.parseFloat(split[1]);
PercentType brightness = (PercentType) brightnessValue.getChannelState();
if (channel.getIdWithoutGroup().equals(HS_CHANNEL_ID)) {
colorValue.update(new HSBType(new DecimalType(x), new PercentType(new BigDecimal(y)), brightness));

listener.updateChannelState(primaryChannelUID, state.equals(OnOffType.ON) ? newOnState : HSBType.BLACK);
} else if (brightnessChannel != null) {
listener.updateChannelState(primaryChannelUID,
state.equals(OnOffType.ON) ? brightnessValue.getChannelState() : PercentType.ZERO);
} else {
listener.updateChannelState(primaryChannelUID, state);
}
} else if (localBrightnessChannel != null && localBrightnessChannel.getChannel().getUID().equals(channel)) {
onOffValue.update(Objects.requireNonNull(state.as(OnOffType.class)));
if (localColorChannel != null) {
if (colorValue.getChannelState() instanceof HSBType) {
HSBType hsb = (HSBType) (colorValue.getChannelState());
colorValue.update(new HSBType(hsb.getHue(), hsb.getSaturation(),
(PercentType) brightnessValue.getChannelState()));
} else {
HSBType xyColor = HSBType.fromXY(x, y);
colorValue.update(new HSBType(xyColor.getHue(), xyColor.getSaturation(), brightness));
colorValue.update(new HSBType(DecimalType.ZERO, PercentType.ZERO,
(PercentType) brightnessValue.getChannelState()));
}
listener.updateChannelState(buildChannelUID(COLOR_CHANNEL_ID), colorValue.getChannelState());
return;
case RGB_CHANNEL_ID:
colorValue.update((HSBType) state);
listener.updateChannelState(buildChannelUID(COLOR_CHANNEL_ID), colorValue.getChannelState());
break;
case RGBW_CHANNEL_ID:
case RGBWW_CHANNEL_ID:
// TODO: update color value
break;
listener.updateChannelState(primaryChannelUID, colorValue.getChannelState());
} else {
listener.updateChannelState(primaryChannelUID, state);
}
} else if (id.equals(COLOR_TEMP_CHANNEL_ID) || channel.getIdWithoutGroup().equals(EFFECT_CHANNEL_ID)) {
// Real channels; pass through
listener.updateChannelState(channel, state);
} else if (id.equals(HS_CHANNEL_ID) || id.equals(XY_CHANNEL_ID)) {
if (brightnessValue.getChannelState() instanceof UnDefType) {
brightnessValue.update(PercentType.HUNDRED);
}
String[] split = state.toString().split(",");
if (split.length != 2) {
throw new IllegalArgumentException(state.toString() + " is not a valid string syntax");
}
float x = Float.parseFloat(split[0]);
float y = Float.parseFloat(split[1]);
PercentType brightness = (PercentType) brightnessValue.getChannelState();
if (channel.getIdWithoutGroup().equals(HS_CHANNEL_ID)) {
colorValue.update(new HSBType(new DecimalType(x), new PercentType(new BigDecimal(y)), brightness));
} else {
HSBType xyColor = HSBType.fromXY(x, y);
colorValue.update(new HSBType(xyColor.getHue(), xyColor.getSaturation(), brightness));
}
listener.updateChannelState(primaryChannelUID, colorValue.getChannelState());
} else if (id.equals(RGB_CHANNEL_ID)) {
colorValue.update((HSBType) state);
listener.updateChannelState(primaryChannelUID, colorValue.getChannelState());
}
// else rgbw channel, rgbww channel
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -118,6 +119,8 @@ static class ChannelConfiguration extends AbstractChannelConfiguration {
private final PercentageValue speedValue;
private State rawSpeedState;
private final ComponentChannel onOffChannel;
private final @Nullable ComponentChannel speedChannel;
private final ComponentChannel primaryChannel;
private final ChannelStateUpdateListener channelStateUpdateListener;

public Fan(ComponentFactory.ComponentConfiguration componentConfiguration, boolean newStyleChannels) {
Expand All @@ -144,11 +147,15 @@ public Fan(ComponentFactory.ComponentConfiguration componentConfiguration, boole

if (channelConfiguration.percentageCommandTopic != null) {
hiddenChannels.add(onOffChannel);
buildChannel(SPEED_CHANNEL_ID, ComponentChannelType.DIMMER, speedValue, "Speed", this)
primaryChannel = speedChannel = buildChannel(SPEED_CHANNEL_ID, ComponentChannelType.DIMMER, speedValue,
"Speed", this)
.stateTopic(channelConfiguration.percentageStateTopic, channelConfiguration.percentageValueTemplate)
.commandTopic(channelConfiguration.percentageCommandTopic, channelConfiguration.isRetain(),
channelConfiguration.getQos(), channelConfiguration.percentageCommandTemplate)
.commandFilter(this::handlePercentageCommand).build();
} else {
primaryChannel = onOffChannel;
speedChannel = null;
}

List<String> presetModes = channelConfiguration.presetModes;
Expand Down Expand Up @@ -198,7 +205,7 @@ private boolean handlePercentageCommand(Command command) {

@Override
public void updateChannelState(ChannelUID channel, State state) {
if (channel.getIdWithoutGroup().equals(SWITCH_CHANNEL_ID)) {
if (onOffChannel.getChannel().getUID().equals(channel)) {
if (rawSpeedState instanceof UnDefType && state.equals(OnOffType.ON)) {
// Assume full on if we don't yet know the actual speed
state = PercentType.HUNDRED;
Expand All @@ -207,15 +214,15 @@ public void updateChannelState(ChannelUID channel, State state) {
} else {
state = rawSpeedState;
}
} else if (channel.getIdWithoutGroup().equals(SPEED_CHANNEL_ID)) {
} else if (Objects.requireNonNull(speedChannel).getChannel().getUID().equals(channel)) {
rawSpeedState = state;
if (onOffValue.getChannelState().equals(OnOffType.OFF)) {
// Don't pass on percentage values while the fan is off
state = PercentType.ZERO;
}
}
speedValue.update(state);
channelStateUpdateListener.updateChannelState(buildChannelUID(SPEED_CHANNEL_ID), state);
channelStateUpdateListener.updateChannelState(primaryChannel.getChannel().getUID(), state);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
import org.openhab.binding.mqtt.generic.values.TextValue;
import org.openhab.binding.mqtt.homeassistant.internal.ComponentChannel;
import org.openhab.binding.mqtt.homeassistant.internal.ComponentChannelType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.HSBType;
Expand Down Expand Up @@ -77,6 +78,7 @@ public JSONSchemaLight(ComponentFactory.ComponentConfiguration builder, boolean

@Override
protected void buildChannels() {
boolean hasColorChannel = false;
List<LightColorMode> supportedColorModes = channelConfiguration.supportedColorModes;
if (supportedColorModes != null) {
if (LightColorMode.hasColorChannel(supportedColorModes)) {
Expand All @@ -99,7 +101,7 @@ protected void buildChannels() {
}

if (hasColorChannel) {
buildChannel(COLOR_CHANNEL_ID, ComponentChannelType.COLOR, colorValue, "Color", this)
colorChannel = buildChannel(COLOR_CHANNEL_ID, ComponentChannelType.COLOR, colorValue, "Color", this)
.commandTopic(DUMMY_TOPIC, true, 1).commandFilter(this::handleCommand).build();
} else if (channelConfiguration.brightness) {
brightnessChannel = buildChannel(BRIGHTNESS_CHANNEL_ID, ComponentChannelType.DIMMER, brightnessValue,
Expand Down Expand Up @@ -144,7 +146,7 @@ protected void publishState(HSBType state) {
.divide(new BigDecimal(100), MathContext.DECIMAL128).intValue();
}

if (hasColorChannel) {
if (colorChannel != null) {
json.color = new JSONState.Color();
if (channelConfiguration.supportedColorModes.contains(LightColorMode.COLOR_MODE_HS)) {
json.color.h = state.getHue().toBigDecimal();
Expand Down Expand Up @@ -318,12 +320,15 @@ public void updateChannelState(ChannelUID channel, State state) {

listener.updateChannelState(buildChannelUID(COLOR_MODE_CHANNEL_ID), colorModeValue.getChannelState());

if (hasColorChannel) {
listener.updateChannelState(buildChannelUID(COLOR_CHANNEL_ID), colorValue.getChannelState());
} else if (brightnessChannel != null) {
listener.updateChannelState(buildChannelUID(BRIGHTNESS_CHANNEL_ID), brightnessValue.getChannelState());
ComponentChannel localBrightnessChannel = brightnessChannel;
ComponentChannel localColorChannel = colorChannel;
if (localColorChannel != null) {
listener.updateChannelState(localColorChannel.getChannel().getUID(), colorValue.getChannelState());
} else if (localBrightnessChannel != null) {
listener.updateChannelState(localBrightnessChannel.getChannel().getUID(),
brightnessValue.getChannelState());
} else {
listener.updateChannelState(buildChannelUID(ON_OFF_CHANNEL_ID), onOffValue.getChannelState());
listener.updateChannelState(onOffChannel.getChannel().getUID(), onOffValue.getChannelState());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,10 @@ static class ChannelConfiguration extends AbstractChannelConfiguration {
}

protected final boolean optimistic;
protected boolean hasColorChannel = false;

protected @Nullable ComponentChannel onOffChannel;
protected @Nullable ComponentChannel brightnessChannel;
protected @Nullable ComponentChannel colorChannel;

// State has to be stored here, in order to mux multiple
// MQTT sources into single OpenHAB channels
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.openhab.binding.mqtt.generic.values.OnOffValue;
import org.openhab.binding.mqtt.generic.values.PercentageValue;
import org.openhab.binding.mqtt.generic.values.TextValue;
import org.openhab.binding.mqtt.homeassistant.internal.ComponentChannel;
import org.openhab.binding.mqtt.homeassistant.internal.ComponentChannelType;
import org.openhab.binding.mqtt.homeassistant.internal.HomeAssistantChannelTransformation;
import org.openhab.binding.mqtt.homeassistant.internal.exception.UnsupportedComponentException;
Expand Down Expand Up @@ -85,8 +86,7 @@ protected void buildChannels() {

if (channelConfiguration.redTemplate != null && channelConfiguration.greenTemplate != null
&& channelConfiguration.blueTemplate != null) {
hasColorChannel = true;
buildChannel(COLOR_CHANNEL_ID, ComponentChannelType.COLOR, colorValue, "Color", this)
colorChannel = buildChannel(COLOR_CHANNEL_ID, ComponentChannelType.COLOR, colorValue, "Color", this)
.commandTopic(DUMMY_TOPIC, true, 1).commandFilter(command -> handleCommand(command)).build();
} else if (channelConfiguration.brightnessTemplate != null) {
brightnessChannel = buildChannel(BRIGHTNESS_CHANNEL_ID, ComponentChannelType.DIMMER, brightnessValue,
Expand Down Expand Up @@ -127,7 +127,7 @@ protected void publishState(HSBType state) {
binding.put(TemplateVariables.BRIGHTNESS,
state.getBrightness().toBigDecimal().multiply(factor).intValue());
}
if (hasColorChannel) {
if (colorChannel != null) {
int[] rgb = ColorUtil.hsbToRgb(state);
binding.put(TemplateVariables.RED, rgb[0]);
binding.put(TemplateVariables.GREEN, rgb[1]);
Expand Down Expand Up @@ -249,13 +249,15 @@ public void updateChannelState(ChannelUID channel, State state) {
colorValue.update(HSBType.fromRGB(red, green, blue));
}
}

if (hasColorChannel) {
listener.updateChannelState(buildChannelUID(COLOR_CHANNEL_ID), colorValue.getChannelState());
} else if (brightnessChannel != null) {
listener.updateChannelState(buildChannelUID(BRIGHTNESS_CHANNEL_ID), brightnessValue.getChannelState());
ComponentChannel localBrightnessChannel = brightnessChannel;
ComponentChannel localColorChannel = colorChannel;
if (localColorChannel != null) {
listener.updateChannelState(localColorChannel.getChannel().getUID(), colorValue.getChannelState());
} else if (localBrightnessChannel != null) {
listener.updateChannelState(localBrightnessChannel.getChannel().getUID(),
brightnessValue.getChannelState());
} else {
listener.updateChannelState(buildChannelUID(ON_OFF_CHANNEL_ID), onOffValue.getChannelState());
listener.updateChannelState(onOffChannel.getChannel().getUID(), onOffValue.getChannelState());
}

template = channelConfiguration.effectTemplate;
Expand Down

0 comments on commit 884f472

Please sign in to comment.