2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.mqtt.generic.values;
15 import java.util.List;
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.openhab.core.library.CoreItemFactory;
20 import org.openhab.core.library.types.PercentType;
21 import org.openhab.core.library.types.StopMoveType;
22 import org.openhab.core.library.types.StringType;
23 import org.openhab.core.library.types.UpDownType;
24 import org.openhab.core.types.Command;
27 * Implements a rollershutter value.
29 * The stop, up and down strings have multiple purposes.
30 * For one if those strings are received via MQTT they are recognised as corresponding commands
31 * and also posted as Commands to the framework.
32 * And if a user commands an Item->Channel to perform Stop the corresponding string is send. For Up,Down
33 * the percentage 0 and 100 is send.
35 * @author David Graeff - Initial contribution
38 public class RollershutterValue extends Value {
39 // openHAB interprets open rollershutters as 0, and closed as 100
40 private static final String UP_VALUE = "0";
41 private static final String DOWN_VALUE = "100";
42 // other devices may interpret it the opposite, so we need to be able
44 private static final String INVERTED_UP_VALUE = DOWN_VALUE;
45 private static final String INVERTED_DOWN_VALUE = UP_VALUE;
47 private final @Nullable String upCommandString;
48 private final @Nullable String downCommandString;
49 private final @Nullable String stopCommandString;
50 private final @Nullable String upStateString;
51 private final @Nullable String downStateString;
52 private final boolean inverted;
53 private final boolean transformExtentsToString;
56 * Creates a new rollershutter value.
58 * @param upCommandString The UP command string.
59 * @param downCommandString The DOWN command string.
60 * @param stopCommandString The STOP command string.
61 * @param upStateString The UP value string. This will be compared to MQTT messages.
62 * @param downStateString The DOWN value string. This will be compared to MQTT messages.
63 * @param inverted Whether to invert 0-100/100-0
64 * @param transformExtentsToString Whether 0/100 will be sent as UP/DOWN
66 public RollershutterValue(@Nullable String upCommandString, @Nullable String downCommandString,
67 @Nullable String stopCommandString, @Nullable String upStateString, @Nullable String downStateString,
68 boolean inverted, boolean transformExtentsToString) {
69 super(CoreItemFactory.ROLLERSHUTTER,
70 List.of(UpDownType.class, StopMoveType.class, PercentType.class, StringType.class));
71 this.upCommandString = upCommandString;
72 this.downCommandString = downCommandString;
73 this.stopCommandString = stopCommandString;
74 this.upStateString = upStateString;
75 this.downStateString = downStateString;
76 this.inverted = inverted;
77 this.transformExtentsToString = transformExtentsToString;
81 * Creates a new rollershutter value.
83 * @param upString The UP value string. This will be compared to MQTT messages.
84 * @param downString The DOWN value string. This will be compared to MQTT messages.
85 * @param stopString The STOP value string. This will be compared to MQTT messages.
87 public RollershutterValue(@Nullable String upString, @Nullable String downString, @Nullable String stopString) {
88 this(upString, downString, stopString, upString, downString, false, true);
91 private Command parseType(Command command, @Nullable String upString, @Nullable String downString)
92 throws IllegalArgumentException {
93 if (command instanceof StopMoveType) {
94 if (command == StopMoveType.STOP && stopCommandString != null) {
97 throw new IllegalArgumentException(command.toString() + " is not a valid command for MQTT.");
99 } else if (command instanceof UpDownType) {
100 if (command == UpDownType.UP) {
101 if (upString != null) {
104 // Do not handle inversion here. See parseCommand below
105 return PercentType.ZERO;
108 if (downString != null) {
111 // Do not handle inversion here. See parseCommand below
112 return PercentType.HUNDRED;
115 } else if (command instanceof PercentType percentage) {
117 } else if (command instanceof StringType) {
118 final String updatedValue = command.toString();
119 if (updatedValue.equals(upString)) {
120 return UpDownType.UP;
121 } else if (updatedValue.equals(downString)) {
122 return UpDownType.DOWN;
123 } else if (updatedValue.equals(stopCommandString)) {
124 return StopMoveType.STOP;
126 return PercentType.valueOf(updatedValue);
129 throw new IllegalStateException("Cannot call parseCommand() with " + command.toString());
133 public Command parseCommand(Command command) throws IllegalArgumentException {
134 // Do not handle inversion in this code path. parseCommand might be called
135 // multiple times when sending a command TO an MQTT topic. The inversion is
136 // handled _only_ in getMQTTpublishValue
137 return parseType(command, upCommandString, downCommandString);
141 public Command parseMessage(Command command) throws IllegalArgumentException {
142 command = parseType(command, upStateString, downStateString);
143 if (inverted && command instanceof PercentType percentType) {
144 return new PercentType(100 - percentType.intValue());
150 public String getMQTTpublishValue(Command command, @Nullable String pattern) {
151 return getMQTTpublishValue(command, transformExtentsToString);
154 public String getMQTTpublishValue(Command command, boolean transformExtentsToString) {
155 final String upCommandString = this.upCommandString;
156 final String downCommandString = this.downCommandString;
157 final String stopCommandString = this.stopCommandString;
158 if (command == UpDownType.UP) {
159 if (upCommandString != null) {
160 return upCommandString;
162 return (inverted ? INVERTED_UP_VALUE : UP_VALUE);
164 } else if (command == UpDownType.DOWN) {
165 if (downCommandString != null) {
166 return downCommandString;
168 return (inverted ? INVERTED_DOWN_VALUE : DOWN_VALUE);
170 } else if (command == StopMoveType.STOP) {
171 if (stopCommandString != null) {
172 return stopCommandString;
174 return ((StopMoveType) command).name();
176 } else if (command instanceof PercentType percentage) {
177 if (transformExtentsToString && command.equals(PercentType.HUNDRED) && downCommandString != null) {
178 return downCommandString;
179 } else if (transformExtentsToString && command.equals(PercentType.ZERO) && upCommandString != null) {
180 return upCommandString;
182 int value = percentage.intValue();
186 return String.valueOf(value);
189 throw new IllegalArgumentException("Invalid command type for Rollershutter item");