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 if (upStateString == null) {
75 this.upStateString = upCommandString;
77 this.upStateString = upStateString;
79 if (downStateString == null) {
80 this.downStateString = downCommandString;
82 this.downStateString = downStateString;
84 this.inverted = inverted;
85 this.transformExtentsToString = transformExtentsToString;
89 * Creates a new rollershutter value.
91 * @param upString The UP value string. This will be compared to MQTT messages.
92 * @param downString The DOWN value string. This will be compared to MQTT messages.
93 * @param stopString The STOP value string. This will be compared to MQTT messages.
95 public RollershutterValue(@Nullable String upString, @Nullable String downString, @Nullable String stopString) {
96 this(upString, downString, stopString, upString, downString, false, true);
99 private Command parseType(Command command, @Nullable String upString, @Nullable String downString)
100 throws IllegalArgumentException {
101 if (command instanceof StopMoveType) {
102 if (command == StopMoveType.STOP && stopCommandString != null) {
105 throw new IllegalArgumentException(command.toString() + " is not a valid command for MQTT.");
107 } else if (command instanceof UpDownType) {
108 if (command == UpDownType.UP) {
109 if (upString != null) {
112 // Do not handle inversion here. See parseCommand below
113 return PercentType.ZERO;
116 if (downString != null) {
119 // Do not handle inversion here. See parseCommand below
120 return PercentType.HUNDRED;
123 } else if (command instanceof PercentType percentage) {
125 } else if (command instanceof StringType) {
126 final String updatedValue = command.toString();
127 if (updatedValue.equals(upString)) {
128 return UpDownType.UP;
129 } else if (updatedValue.equals(downString)) {
130 return UpDownType.DOWN;
131 } else if (updatedValue.equals(stopCommandString)) {
132 return StopMoveType.STOP;
134 return PercentType.valueOf(updatedValue);
137 throw new IllegalStateException("Cannot call parseCommand() with " + command.toString());
141 public Command parseCommand(Command command) throws IllegalArgumentException {
142 // Do not handle inversion in this code path. parseCommand might be called
143 // multiple times when sending a command TO an MQTT topic. The inversion is
144 // handled _only_ in getMQTTpublishValue
145 return parseType(command, upCommandString, downCommandString);
149 public Command parseMessage(Command command) throws IllegalArgumentException {
150 command = parseType(command, upStateString, downStateString);
151 if (inverted && command instanceof PercentType percentType) {
152 return new PercentType(100 - percentType.intValue());
158 public String getMQTTpublishValue(Command command, @Nullable String pattern) {
159 return getMQTTpublishValue(command, transformExtentsToString);
162 public String getMQTTpublishValue(Command command, boolean transformExtentsToString) {
163 final String upCommandString = this.upCommandString;
164 final String downCommandString = this.downCommandString;
165 final String stopCommandString = this.stopCommandString;
166 if (command == UpDownType.UP) {
167 if (upCommandString != null) {
168 return upCommandString;
170 return (inverted ? INVERTED_UP_VALUE : UP_VALUE);
172 } else if (command == UpDownType.DOWN) {
173 if (downCommandString != null) {
174 return downCommandString;
176 return (inverted ? INVERTED_DOWN_VALUE : DOWN_VALUE);
178 } else if (command == StopMoveType.STOP) {
179 if (stopCommandString != null) {
180 return stopCommandString;
182 return ((StopMoveType) command).name();
184 } else if (command instanceof PercentType percentage) {
185 if (transformExtentsToString && command.equals(PercentType.HUNDRED) && downCommandString != null) {
186 return downCommandString;
187 } else if (transformExtentsToString && command.equals(PercentType.ZERO) && upCommandString != null) {
188 return upCommandString;
190 int value = percentage.intValue();
194 return String.valueOf(value);
197 throw new IllegalArgumentException("Invalid command type for Rollershutter item");