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

[mqtt.generic] Send ON/OFF for dimmer channels when so configured #15929

Merged
merged 1 commit into from
Jul 23, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public PercentageValue(@Nullable BigDecimal min, @Nullable BigDecimal max, @Null
}

@Override
public PercentType parseCommand(Command command) throws IllegalArgumentException {
public Command parseCommand(Command command) throws IllegalArgumentException {
PercentType oldvalue = (state instanceof UnDefType) ? new PercentType() : (PercentType) state;
// Nothing do to -> We have received a percentage
if (command instanceof PercentType percent) {
Expand Down Expand Up @@ -105,8 +105,8 @@ public PercentType parseCommand(Command command) throws IllegalArgumentException
}
} else //
// On/Off equals 100 or 0 percent
if (command instanceof OnOffType increaseDecreaseCommand) {
return increaseDecreaseCommand == OnOffType.ON ? PercentType.HUNDRED : PercentType.ZERO;
if (command instanceof OnOffType) {
return command;
} else//
// Increase or decrease by "step"
if (command instanceof UpDownType upDownCommand) {
Expand All @@ -121,9 +121,9 @@ public PercentType parseCommand(Command command) throws IllegalArgumentException
// Check against custom on/off values
if (command instanceof StringType) {
if (onValue != null && command.toString().equals(onValue)) {
return new PercentType(max);
return OnOffType.ON;
} else if (offValue != null && command.toString().equals(offValue)) {
return new PercentType(min);
return OnOffType.OFF;
} else {
throw new IllegalStateException("Unable to parse " + command.toString() + " as a percent.");
}
Expand All @@ -135,17 +135,36 @@ public PercentType parseCommand(Command command) throws IllegalArgumentException

@Override
public String getMQTTpublishValue(Command command, @Nullable String pattern) {
String formatPattern = pattern;
if (formatPattern == null) {
formatPattern = "%s";
}

if (command instanceof OnOffType onOffCommand) {
if (onOffCommand == OnOffType.ON) {
if (onValue != null) {
command = new StringType(onValue);
} else {
command = PercentType.HUNDRED;
}
} else {
if (offValue != null) {
command = new StringType(offValue);
} else {
command = PercentType.ZERO;
}
}
}
if (command instanceof StringType) {
return command.format(formatPattern);
}

// Formula: From percentage to custom min/max: value*span/100+min
// Calculation need to happen with big decimals to either return a straight integer or a decimal depending on
// the value.
BigDecimal value = ((PercentType) command).toBigDecimal().multiply(span).divide(HUNDRED, MathContext.DECIMAL128)
.add(min).stripTrailingZeros();

String formatPattern = pattern;
if (formatPattern == null) {
formatPattern = "%s";
}

return new DecimalType(value).format(formatPattern);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,12 @@
<advanced>true</advanced>
</parameter>
<parameter name="on" type="text">
<label>Custom On/Open Value</label>
<description>A number (like 1, 10) or a string (like "enabled") that is additionally recognised as on/open state. You
can use this parameter for a second keyword, next to ON (OPEN respectively on a Contact).</description>
<default>1</default>
<label>Custom ON Command</label>
<description>A string (like "ON") that is sent to MQTT when an ON command is received, instead of an explicit 100%.</description>
</parameter>
<parameter name="off" type="text">
<label>Custom Off/Closed Value</label>
<description>A number (like 0, -10) or a string (like "disabled") that is additionally recognised as off/closed
state. You can use this parameter for a second keyword, next to OFF (CLOSED respectively on a Contact).</description>
<default>0</default>
<label>Custom OFF Command</label>
<description>A string (like "OFF") that is sent to MQTT when an OFF command is received, instead of an explicit 0%.</description>
</parameter>
</config-description>
</config-description:config-descriptions>
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ thing-type.config.mqtt.dimmer_channel.max.label = Absolute Maximum
thing-type.config.mqtt.dimmer_channel.max.description = This configuration represents the maximum of the allowed range. For a percentage channel that equals one-hundred percent.
thing-type.config.mqtt.dimmer_channel.min.label = Absolute Minimum
thing-type.config.mqtt.dimmer_channel.min.description = This configuration represents the minimum of the allowed range. For a percentage channel that equals zero percent.
thing-type.config.mqtt.dimmer_channel.off.label = Custom Off/Closed Value
thing-type.config.mqtt.dimmer_channel.off.description = A number (like 0, -10) or a string (like "disabled") that is additionally recognised as off/closed state. You can use this parameter for a second keyword, next to OFF (CLOSED respectively on a Contact).
thing-type.config.mqtt.dimmer_channel.on.label = Custom On/Open Value
thing-type.config.mqtt.dimmer_channel.on.description = A number (like 1, 10) or a string (like "enabled") that is additionally recognised as on/open state. You can use this parameter for a second keyword, next to ON (OPEN respectively on a Contact).
thing-type.config.mqtt.dimmer_channel.off.label = Custom OFF Command
thing-type.config.mqtt.dimmer_channel.off.description = A string (like "OFF") that is sent to MQTT when an OFF command is received, instead of an explicit 0%.
thing-type.config.mqtt.dimmer_channel.on.label = Custom ON Command
thing-type.config.mqtt.dimmer_channel.on.description = A string (like "ON") that is sent to MQTT when an ON command is received, instead of an explicit 100%.
thing-type.config.mqtt.dimmer_channel.postCommand.label = Is Command
thing-type.config.mqtt.dimmer_channel.postCommand.description = If the received MQTT value should not only update the state of linked items, but command them, enable this option.
thing-type.config.mqtt.dimmer_channel.qos.label = QoS
Expand Down Expand Up @@ -170,6 +170,8 @@ thing-type.config.mqtt.string_channel.formatBeforePublish.label = Outgoing Value
thing-type.config.mqtt.string_channel.formatBeforePublish.description = Format a value before it is published to the MQTT broker. The default is to just pass the channel/item state. If you want to apply a prefix, say "MYCOLOR,", you would use "MYCOLOR,%s". If you want to adjust the precision of a number to for example 4 digits, you would use "%.4f".
thing-type.config.mqtt.string_channel.group.transformations.label = Transform Values
thing-type.config.mqtt.string_channel.group.transformations.description = These configuration parameters allow you to alter a value before it is published to MQTT or before a received value is assigned to an item.
thing-type.config.mqtt.string_channel.nullValue.label = NULL Value
thing-type.config.mqtt.string_channel.nullValue.description = If the received MQTT value matches this, treat it as NULL.
thing-type.config.mqtt.string_channel.postCommand.label = Is Command
thing-type.config.mqtt.string_channel.postCommand.description = If the received MQTT value should not only update the state of linked items, but command them, enable this option.
thing-type.config.mqtt.string_channel.qos.label = QoS
Expand All @@ -185,8 +187,6 @@ thing-type.config.mqtt.string_channel.transformationPattern.label = Incoming Val
thing-type.config.mqtt.string_channel.transformationPattern.description = Applies transformations to an incoming MQTT topic value. A transformation example for a received JSON would be "JSONPATH:$.device.status.temperature" for a json {device: {status: { temperature: 23.2 }}}. You can chain transformations by separating them with the intersection character ∩.
thing-type.config.mqtt.string_channel.transformationPatternOut.label = Outgoing Value Transformation
thing-type.config.mqtt.string_channel.transformationPatternOut.description = Applies a transformation before publishing a MQTT topic value. Transformations are specialised in extracting a value, but some transformations like the MAP one could be useful.
thing-type.config.mqtt.string_channel.nullValue.label = NULL Value
thing-type.config.mqtt.string_channel.nullValue.description = If the received MQTT value matches this, treat it as NULL.
thing-type.config.mqtt.switch_channel.commandTopic.label = MQTT Command Topic
thing-type.config.mqtt.switch_channel.commandTopic.description = An MQTT topic that this thing will send a command to. If not set, this will be a read-only switch.
thing-type.config.mqtt.switch_channel.formatBeforePublish.label = Outgoing Value Format
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,10 @@ public void percentCalc() {
assertThat(v.parseCommand(new DecimalType(10.0)), is(PercentType.ZERO));
assertThat(v.getMQTTpublishValue(PercentType.ZERO, null), is("10"));

assertThat(v.parseCommand(OnOffType.ON), is(PercentType.HUNDRED));
assertThat(v.parseCommand(OnOffType.OFF), is(PercentType.ZERO));
assertThat(v.parseCommand(OnOffType.ON), is(OnOffType.ON));
assertThat(v.getMQTTpublishValue(OnOffType.ON, null), is("110"));
assertThat(v.parseCommand(OnOffType.OFF), is(OnOffType.OFF));
assertThat(v.getMQTTpublishValue(OnOffType.OFF, null), is("10"));
}

@Test
Expand All @@ -332,8 +334,10 @@ public void percentMQTTValue() {
public void percentCustomOnOff() {
PercentageValue v = new PercentageValue(new BigDecimal("0.0"), new BigDecimal("100.0"), new BigDecimal("1.0"),
"on", "off");
assertThat(v.parseCommand(new StringType("on")), is(PercentType.HUNDRED));
assertThat(v.parseCommand(new StringType("off")), is(PercentType.ZERO));
assertThat(v.parseCommand(new StringType("on")), is(OnOffType.ON));
assertThat(v.getMQTTpublishValue(OnOffType.ON, "%s"), is("on"));
assertThat(v.parseCommand(new StringType("off")), is(OnOffType.OFF));
assertThat(v.getMQTTpublishValue(OnOffType.OFF, "%s"), is("off"));
}

@Test
Expand All @@ -342,7 +346,7 @@ public void decimalCalc() {
null, null);
assertThat(v.parseCommand(new DecimalType(1.0)), is(PercentType.HUNDRED));
assertThat(v.parseCommand(new DecimalType(0.1)), is(PercentType.ZERO));
PercentType command = v.parseCommand(new DecimalType(0.2));
PercentType command = (PercentType) v.parseCommand(new DecimalType(0.2));
assertEquals(command.floatValue(), 11.11f, 0.01f);
}

Expand All @@ -352,26 +356,26 @@ public void increaseDecreaseCalc() {
null, null);

// Normal operation.
PercentType command = v.parseCommand(new DecimalType("6.0"));
PercentType command = (PercentType) v.parseCommand(new DecimalType("6.0"));
assertEquals(command.floatValue(), 50.0f, 0.01f);
v.update(command);
command = v.parseCommand(IncreaseDecreaseType.INCREASE);
command = (PercentType) v.parseCommand(IncreaseDecreaseType.INCREASE);
assertEquals(command.floatValue(), 55.0f, 0.01f);
command = v.parseCommand(IncreaseDecreaseType.DECREASE);
command = (PercentType) v.parseCommand(IncreaseDecreaseType.DECREASE);
assertEquals(command.floatValue(), 45.0f, 0.01f);

// Lower limit.
command = v.parseCommand(new DecimalType("1.1"));
command = (PercentType) v.parseCommand(new DecimalType("1.1"));
assertEquals(command.floatValue(), 1.0f, 0.01f);
v.update(command);
command = v.parseCommand(IncreaseDecreaseType.DECREASE);
command = (PercentType) v.parseCommand(IncreaseDecreaseType.DECREASE);
assertEquals(command.floatValue(), 0.0f, 0.01f);

// Upper limit.
command = v.parseCommand(new DecimalType("10.8"));
command = (PercentType) v.parseCommand(new DecimalType("10.8"));
assertEquals(command.floatValue(), 98.0f, 0.01f);
v.update(command);
command = v.parseCommand(IncreaseDecreaseType.INCREASE);
command = (PercentType) v.parseCommand(IncreaseDecreaseType.INCREASE);
assertEquals(command.floatValue(), 100.0f, 0.01f);
}

Expand All @@ -381,26 +385,26 @@ public void upDownCalc() {
null, null);

// Normal operation.
PercentType command = v.parseCommand(new DecimalType("6.0"));
PercentType command = (PercentType) v.parseCommand(new DecimalType("6.0"));
assertEquals(command.floatValue(), 50.0f, 0.01f);
v.update(command);
command = v.parseCommand(UpDownType.UP);
command = (PercentType) v.parseCommand(UpDownType.UP);
assertEquals(command.floatValue(), 55.0f, 0.01f);
command = v.parseCommand(UpDownType.DOWN);
command = (PercentType) v.parseCommand(UpDownType.DOWN);
assertEquals(command.floatValue(), 45.0f, 0.01f);

// Lower limit.
command = v.parseCommand(new DecimalType("1.1"));
command = (PercentType) v.parseCommand(new DecimalType("1.1"));
assertEquals(command.floatValue(), 1.0f, 0.01f);
v.update(command);
command = v.parseCommand(UpDownType.DOWN);
command = (PercentType) v.parseCommand(UpDownType.DOWN);
assertEquals(command.floatValue(), 0.0f, 0.01f);

// Upper limit.
command = v.parseCommand(new DecimalType("10.8"));
command = (PercentType) v.parseCommand(new DecimalType("10.8"));
assertEquals(command.floatValue(), 98.0f, 0.01f);
v.update(command);
command = v.parseCommand(UpDownType.UP);
command = (PercentType) v.parseCommand(UpDownType.UP);
assertEquals(command.floatValue(), 100.0f, 0.01f);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,13 +255,15 @@ public void updateChannelState(ChannelUID channel, State state) {

boolean off = false;
if (jsonState.state != null) {
onOffValue.update(onOffValue.parseCommand(new StringType(jsonState.state)));
onOffValue.update((State) onOffValue.parseMessage(new StringType(jsonState.state)));
off = onOffValue.getChannelState().equals(OnOffType.OFF);
if (brightnessValue.getChannelState() instanceof UnDefType) {
brightnessValue.update(off ? PercentType.ZERO : PercentType.HUNDRED);
}
if (colorValue.getChannelState() instanceof UnDefType) {
colorValue.update(off ? HSBType.BLACK : HSBType.WHITE);
if (onOffValue.getChannelState() instanceof OnOffType onOffState) {
if (brightnessValue.getChannelState() instanceof UnDefType) {
brightnessValue.update(Objects.requireNonNull(onOffState.as(PercentType.class)));
}
if (colorValue.getChannelState() instanceof UnDefType) {
colorValue.update(Objects.requireNonNull(onOffState.as(PercentType.class)));
}
}
}

Expand Down