]> git.basschouten.com Git - openhab-addons.git/blob
db6baee7ba164c45da96ce2ad04629f0cf42d0b6
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.mqtt.homeassistant.internal.component;
14
15 import java.math.BigDecimal;
16 import java.util.List;
17
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
21 import org.openhab.binding.mqtt.generic.mapping.ColorMode;
22 import org.openhab.binding.mqtt.generic.values.ColorValue;
23 import org.openhab.binding.mqtt.generic.values.NumberValue;
24 import org.openhab.binding.mqtt.generic.values.OnOffValue;
25 import org.openhab.binding.mqtt.generic.values.PercentageValue;
26 import org.openhab.binding.mqtt.generic.values.TextValue;
27 import org.openhab.binding.mqtt.homeassistant.internal.ComponentChannel;
28 import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
29 import org.openhab.binding.mqtt.homeassistant.internal.exception.UnsupportedComponentException;
30 import org.openhab.core.library.unit.Units;
31 import org.openhab.core.thing.ChannelUID;
32 import org.openhab.core.types.Command;
33
34 import com.google.gson.annotations.SerializedName;
35
36 /**
37  * A MQTT light, following the
38  * https://www.home-assistant.io/components/light.mqtt/ specification.
39  *
40  * Individual concrete classes implement the differing semantics of the
41  * three different schemas.
42  *
43  * As of now, only on/off, brightness, and RGB are fully implemented and tested.
44  * HS and XY are implemented, but not tested. Color temp is only
45  * implemented (but not tested) for the default schema.
46  *
47  * @author David Graeff - Initial contribution
48  * @author Cody Cutrer - Re-write for (nearly) full support
49  */
50 @NonNullByDefault
51 public abstract class Light extends AbstractComponent<Light.ChannelConfiguration>
52         implements ChannelStateUpdateListener {
53     protected static final String DEFAULT_SCHEMA = "default";
54     protected static final String JSON_SCHEMA = "json";
55     protected static final String TEMPLATE_SCHEMA = "template";
56
57     protected static final String STATE_CHANNEL_ID = "state";
58     protected static final String ON_OFF_CHANNEL_ID = "on_off";
59     protected static final String BRIGHTNESS_CHANNEL_ID = "brightness";
60     protected static final String COLOR_MODE_CHANNEL_ID = "color_mode";
61     protected static final String COLOR_TEMP_CHANNEL_ID = "color_temp";
62     protected static final String EFFECT_CHANNEL_ID = "effect";
63     // This channel is a synthetic channel that may send to other channels
64     // underneath
65     protected static final String COLOR_CHANNEL_ID = "color";
66
67     protected static final String DUMMY_TOPIC = "dummy";
68
69     protected static final String ON_COMMAND_TYPE_FIRST = "first";
70     protected static final String ON_COMMAND_TYPE_BRIGHTNESS = "brightness";
71     protected static final String ON_COMMAND_TYPE_LAST = "last";
72
73     /**
74      * Configuration class for MQTT component
75      */
76     static class ChannelConfiguration extends AbstractChannelConfiguration {
77         ChannelConfiguration() {
78             super("MQTT Light");
79         }
80
81         /* Attributes that control the basic structure of the light */
82
83         protected String schema = DEFAULT_SCHEMA;
84         protected @Nullable Boolean optimistic; // All schemas
85         protected boolean brightness = false; // JSON schema only
86         @SerializedName("color_mode")
87         protected boolean colorMode = false; // JSON schema only
88         @SerializedName("supported_color_modes")
89         protected @Nullable List<LightColorMode> supportedColorModes; // JSON schema only
90         // Defines when on the payload_on is sent. Using last (the default) will send
91         // any style (brightness, color, etc)
92         // topics first and then a payload_on to the command_topic. Using first will
93         // send the payload_on and then any
94         // style topics. Using brightness will only send brightness commands instead of
95         // the payload_on to turn the light
96         // on.
97         @SerializedName("on_command_type")
98         protected String onCommandType = ON_COMMAND_TYPE_LAST; // Default schema only
99
100         /* Basic control attributes */
101
102         @SerializedName("state_topic")
103         protected @Nullable String stateTopic; // All Schemas
104         @SerializedName("state_value_template")
105         protected @Nullable String stateValueTemplate; // Default schema only
106         @SerializedName("state_template")
107         protected @Nullable String stateTemplate; // Template schema only
108         @SerializedName("payload_on")
109         protected String payloadOn = "ON"; // Default schema only
110         @SerializedName("payload_off")
111         protected String payloadOff = "OFF"; // Default schema only
112         @SerializedName("command_topic")
113         protected @Nullable String commandTopic; // All schemas
114         @SerializedName("command_on_template")
115         protected @Nullable String commandOnTemplate; // Template schema only; required
116         @SerializedName("command_off_template")
117         protected @Nullable String commandOffTemplate; // Template schema only; required
118
119         /* Brightness attributes */
120
121         @SerializedName("brightness_scale")
122         protected int brightnessScale = 255; // Default, JSON schemas only
123         @SerializedName("brightness_state_topic")
124         protected @Nullable String brightnessStateTopic; // Default schema only
125         @SerializedName("brightness_value_template")
126         protected @Nullable String brightnessValueTemplate; // Default schema only
127         @SerializedName("brightness_template")
128         protected @Nullable String brightnessTemplate; // Template schema only
129         @SerializedName("brightness_command_topic")
130         protected @Nullable String brightnessCommandTopic; // Default schema only
131         @SerializedName("brightness_command_template")
132         protected @Nullable String brightnessCommandTemplate; // Default schema only
133
134         /* White value attributes */
135
136         @SerializedName("white_scale")
137         protected int whiteScale = 255; // Default, JSON schemas only
138         @SerializedName("white_command_topic")
139         protected @Nullable String whiteCommandTopic; // Default schema only
140
141         /* Color mode attributes */
142
143         @SerializedName("color_mode_state_topic")
144         protected @Nullable String colorModeStateTopic; // Default schema only
145         @SerializedName("color_mode_value_template")
146         protected @Nullable String colorModeValueTemplate; // Default schema only
147
148         /* Color temp attributes */
149
150         @SerializedName("min_mireds")
151         protected @Nullable Integer minMireds; // All schemas
152         @SerializedName("max_mireds")
153         protected @Nullable Integer maxMireds; // All schemas
154         @SerializedName("color_temp_state_topic")
155         protected @Nullable String colorTempStateTopic; // Default schema only
156         @SerializedName("color_temp_value_template")
157         protected @Nullable String colorTempValueTemplate; // Default schema only
158         @SerializedName("color_temp_template")
159         protected @Nullable String colorTempTemplate; // Template schema only
160         @SerializedName("color_temp_command_topic")
161         protected @Nullable String colorTempCommandTopic; // Default schema only
162         @SerializedName("color_temp_command_template")
163         protected @Nullable String colorTempCommandTemplate; // Default schema only
164
165         /* Effect attributes */
166         @SerializedName("effect_list")
167         protected @Nullable List<String> effectList; // All schemas
168         @SerializedName("effect_state_topic")
169         protected @Nullable String effectStateTopic; // Default schema only
170         @SerializedName("effect_value_template")
171         protected @Nullable String effectValueTemplate; // Default schema only
172         @SerializedName("effect_template")
173         protected @Nullable String effectTemplate; // Template schema only
174         @SerializedName("effect_command_topic")
175         protected @Nullable String effectCommandTopic; // Default schema only
176         @SerializedName("effect_command_template")
177         protected @Nullable String effectCommandTemplate; // Default schema only
178
179         /* HS attributes */
180         @SerializedName("hs_state_topic")
181         protected @Nullable String hsStateTopic; // Default schema only
182         @SerializedName("hs_value_template")
183         protected @Nullable String hsValueTemplate; // Default schema only
184         @SerializedName("hs_command_topic")
185         protected @Nullable String hsCommandTopic; // Default schema only
186
187         /* RGB attributes */
188         @SerializedName("rgb_state_topic")
189         protected @Nullable String rgbStateTopic; // Default schema only
190         @SerializedName("rgb_value_template")
191         protected @Nullable String rgbValueTemplate; // Default schema only
192         @SerializedName("red_template")
193         protected @Nullable String redTemplate; // Template schema only
194         @SerializedName("green_template")
195         protected @Nullable String greenTemplate; // Template schema only
196         @SerializedName("blue_template")
197         protected @Nullable String blueTemplate; // Template schema only
198         @SerializedName("rgb_command_topic")
199         protected @Nullable String rgbCommandTopic; // Default schema only
200         @SerializedName("rgb_command_template")
201         protected @Nullable String rgbCommandTemplate; // Default schema only
202
203         /* RGBW attributes */
204         @SerializedName("rgbw_state_topic")
205         protected @Nullable String rgbwStateTopic; // Default schema only
206         @SerializedName("rgbw_value_template")
207         protected @Nullable String rgbwValueTemplate; // Default schema only
208         @SerializedName("rgbw_command_topic")
209         protected @Nullable String rgbwCommandTopic; // Default schema only
210         @SerializedName("rgbw_command_template")
211         protected @Nullable String rgbwCommandTemplate; // Default schema only
212
213         /* RGBWW attributes */
214         @SerializedName("rgbww_state_topic")
215         protected @Nullable String rgbwwStateTopic; // Default schema only
216         @SerializedName("rgbww_value_template")
217         protected @Nullable String rgbwwValueTemplate; // Default schema only
218         @SerializedName("rgbww_command_topic")
219         protected @Nullable String rgbwwCommandTopic; // Default schema only
220         @SerializedName("rgbww_command_template")
221         protected @Nullable String rgbwwCommandTemplate; // Default schema only
222
223         /* XY attributes */
224         @SerializedName("xy_command_topic")
225         protected @Nullable String xyCommandTopic; // Default schema only
226         @SerializedName("xy_state_topic")
227         protected @Nullable String xyStateTopic; // Default schema only
228         @SerializedName("xy_value_template")
229         protected @Nullable String xyValueTemplate; // Default schema only
230     }
231
232     protected final boolean optimistic;
233     protected boolean hasColorChannel = false;
234
235     protected @Nullable ComponentChannel onOffChannel;
236     protected @Nullable ComponentChannel brightnessChannel;
237
238     // State has to be stored here, in order to mux multiple
239     // MQTT sources into single OpenHAB channels
240     protected OnOffValue onOffValue;
241     protected PercentageValue brightnessValue;
242     protected final NumberValue colorTempValue;
243     protected final @Nullable TextValue effectValue;
244     protected final ColorValue colorValue = new ColorValue(ColorMode.HSB, null, null, 100);
245
246     protected final ChannelStateUpdateListener channelStateUpdateListener;
247
248     public static Light create(ComponentFactory.ComponentConfiguration builder, boolean newStyleChannels)
249             throws UnsupportedComponentException {
250         String schema = builder.getConfig(ChannelConfiguration.class).schema;
251         switch (schema) {
252             case DEFAULT_SCHEMA:
253                 return new DefaultSchemaLight(builder, newStyleChannels);
254             case JSON_SCHEMA:
255                 return new JSONSchemaLight(builder, newStyleChannels);
256             default:
257                 throw new UnsupportedComponentException(
258                         "Component '" + builder.getHaID() + "' of schema '" + schema + "' is not supported!");
259         }
260     }
261
262     protected Light(ComponentFactory.ComponentConfiguration builder, boolean newStyleChannels) {
263         super(builder, ChannelConfiguration.class, newStyleChannels);
264         this.channelStateUpdateListener = builder.getUpdateListener();
265
266         @Nullable
267         Boolean optimistic = channelConfiguration.optimistic;
268         if (optimistic != null) {
269             this.optimistic = optimistic;
270         } else {
271             this.optimistic = (channelConfiguration.stateTopic == null);
272         }
273
274         onOffValue = new OnOffValue(channelConfiguration.payloadOn, channelConfiguration.payloadOff);
275         brightnessValue = new PercentageValue(null, new BigDecimal(channelConfiguration.brightnessScale), null, null,
276                 null);
277         @Nullable
278         List<String> effectList = channelConfiguration.effectList;
279         if (effectList != null) {
280             effectValue = new TextValue(effectList.toArray(new String[0]));
281         } else {
282             effectValue = null;
283         }
284         @Nullable
285         BigDecimal min = null, max = null;
286         if (channelConfiguration.minMireds != null) {
287             min = new BigDecimal(channelConfiguration.minMireds);
288         }
289         if (channelConfiguration.maxMireds != null) {
290             max = new BigDecimal(channelConfiguration.maxMireds);
291         }
292         colorTempValue = new NumberValue(min, max, BigDecimal.ONE, Units.MIRED);
293
294         buildChannels();
295     }
296
297     protected abstract void buildChannels();
298
299     @Override
300     public void postChannelCommand(ChannelUID channelUID, Command value) {
301         throw new UnsupportedOperationException();
302     }
303
304     @Override
305     public void triggerChannel(ChannelUID channelUID, String eventPayload) {
306         throw new UnsupportedOperationException();
307     }
308 }