]> git.basschouten.com Git - openhab-addons.git/blob
46f26d530f7570d449f26de628adb14a0a438ed3
[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("supported_color_modes")
87         protected @Nullable List<LightColorMode> supportedColorModes; // JSON schema only
88         // Defines when on the payload_on is sent. Using last (the default) will send
89         // any style (brightness, color, etc)
90         // topics first and then a payload_on to the command_topic. Using first will
91         // send the payload_on and then any
92         // style topics. Using brightness will only send brightness commands instead of
93         // the payload_on to turn the light
94         // on.
95         @SerializedName("on_command_type")
96         protected String onCommandType = ON_COMMAND_TYPE_LAST; // Default schema only
97
98         /* Basic control attributes */
99
100         @SerializedName("state_topic")
101         protected @Nullable String stateTopic; // All Schemas
102         @SerializedName("state_value_template")
103         protected @Nullable String stateValueTemplate; // Default schema only
104         @SerializedName("state_template")
105         protected @Nullable String stateTemplate; // Template schema only
106         @SerializedName("payload_on")
107         protected String payloadOn = "ON"; // Default schema only
108         @SerializedName("payload_off")
109         protected String payloadOff = "OFF"; // Default schema only
110         @SerializedName("command_topic")
111         protected @Nullable String commandTopic; // All schemas
112         @SerializedName("command_on_template")
113         protected @Nullable String commandOnTemplate; // Template schema only; required
114         @SerializedName("command_off_template")
115         protected @Nullable String commandOffTemplate; // Template schema only; required
116
117         /* Brightness attributes */
118
119         @SerializedName("brightness_scale")
120         protected int brightnessScale = 255; // Default, JSON schemas only
121         @SerializedName("brightness_state_topic")
122         protected @Nullable String brightnessStateTopic; // Default schema only
123         @SerializedName("brightness_value_template")
124         protected @Nullable String brightnessValueTemplate; // Default schema only
125         @SerializedName("brightness_template")
126         protected @Nullable String brightnessTemplate; // Template schema only
127         @SerializedName("brightness_command_topic")
128         protected @Nullable String brightnessCommandTopic; // Default schema only
129         @SerializedName("brightness_command_template")
130         protected @Nullable String brightnessCommandTemplate; // Default schema only
131
132         /* White value attributes */
133
134         @SerializedName("white_scale")
135         protected int whiteScale = 255; // Default, JSON schemas only
136         @SerializedName("white_command_topic")
137         protected @Nullable String whiteCommandTopic; // Default schema only
138
139         /* Color mode attributes */
140
141         @SerializedName("color_mode_state_topic")
142         protected @Nullable String colorModeStateTopic; // Default schema only
143         @SerializedName("color_mode_value_template")
144         protected @Nullable String colorModeValueTemplate; // Default schema only
145
146         /* Color temp attributes */
147
148         @SerializedName("min_mireds")
149         protected @Nullable Integer minMireds; // All schemas
150         @SerializedName("max_mireds")
151         protected @Nullable Integer maxMireds; // All schemas
152         @SerializedName("color_temp_state_topic")
153         protected @Nullable String colorTempStateTopic; // Default schema only
154         @SerializedName("color_temp_value_template")
155         protected @Nullable String colorTempValueTemplate; // Default schema only
156         @SerializedName("color_temp_template")
157         protected @Nullable String colorTempTemplate; // Template schema only
158         @SerializedName("color_temp_command_topic")
159         protected @Nullable String colorTempCommandTopic; // Default schema only
160         @SerializedName("color_temp_command_template")
161         protected @Nullable String colorTempCommandTemplate; // Default schema only
162
163         /* Effect attributes */
164         @SerializedName("effect_list")
165         protected @Nullable List<String> effectList; // All schemas
166         @SerializedName("effect_state_topic")
167         protected @Nullable String effectStateTopic; // Default schema only
168         @SerializedName("effect_value_template")
169         protected @Nullable String effectValueTemplate; // Default schema only
170         @SerializedName("effect_template")
171         protected @Nullable String effectTemplate; // Template schema only
172         @SerializedName("effect_command_topic")
173         protected @Nullable String effectCommandTopic; // Default schema only
174         @SerializedName("effect_command_template")
175         protected @Nullable String effectCommandTemplate; // Default schema only
176
177         /* HS attributes */
178         @SerializedName("hs_state_topic")
179         protected @Nullable String hsStateTopic; // Default schema only
180         @SerializedName("hs_value_template")
181         protected @Nullable String hsValueTemplate; // Default schema only
182         @SerializedName("hs_command_topic")
183         protected @Nullable String hsCommandTopic; // Default schema only
184
185         /* RGB attributes */
186         @SerializedName("rgb_state_topic")
187         protected @Nullable String rgbStateTopic; // Default schema only
188         @SerializedName("rgb_value_template")
189         protected @Nullable String rgbValueTemplate; // Default schema only
190         @SerializedName("red_template")
191         protected @Nullable String redTemplate; // Template schema only
192         @SerializedName("green_template")
193         protected @Nullable String greenTemplate; // Template schema only
194         @SerializedName("blue_template")
195         protected @Nullable String blueTemplate; // Template schema only
196         @SerializedName("rgb_command_topic")
197         protected @Nullable String rgbCommandTopic; // Default schema only
198         @SerializedName("rgb_command_template")
199         protected @Nullable String rgbCommandTemplate; // Default schema only
200
201         /* RGBW attributes */
202         @SerializedName("rgbw_state_topic")
203         protected @Nullable String rgbwStateTopic; // Default schema only
204         @SerializedName("rgbw_value_template")
205         protected @Nullable String rgbwValueTemplate; // Default schema only
206         @SerializedName("rgbw_command_topic")
207         protected @Nullable String rgbwCommandTopic; // Default schema only
208         @SerializedName("rgbw_command_template")
209         protected @Nullable String rgbwCommandTemplate; // Default schema only
210
211         /* RGBWW attributes */
212         @SerializedName("rgbww_state_topic")
213         protected @Nullable String rgbwwStateTopic; // Default schema only
214         @SerializedName("rgbww_value_template")
215         protected @Nullable String rgbwwValueTemplate; // Default schema only
216         @SerializedName("rgbww_command_topic")
217         protected @Nullable String rgbwwCommandTopic; // Default schema only
218         @SerializedName("rgbww_command_template")
219         protected @Nullable String rgbwwCommandTemplate; // Default schema only
220
221         /* XY attributes */
222         @SerializedName("xy_command_topic")
223         protected @Nullable String xyCommandTopic; // Default schema only
224         @SerializedName("xy_state_topic")
225         protected @Nullable String xyStateTopic; // Default schema only
226         @SerializedName("xy_value_template")
227         protected @Nullable String xyValueTemplate; // Default schema only
228     }
229
230     protected final boolean optimistic;
231
232     protected @Nullable ComponentChannel onOffChannel;
233     protected @Nullable ComponentChannel brightnessChannel;
234     protected @Nullable ComponentChannel colorChannel;
235
236     // State has to be stored here, in order to mux multiple
237     // MQTT sources into single OpenHAB channels
238     protected OnOffValue onOffValue;
239     protected PercentageValue brightnessValue;
240     protected final NumberValue colorTempValue;
241     protected final @Nullable TextValue effectValue;
242     protected final ColorValue colorValue = new ColorValue(ColorMode.HSB, null, null, 100);
243
244     protected final ChannelStateUpdateListener channelStateUpdateListener;
245
246     public static Light create(ComponentFactory.ComponentConfiguration builder, boolean newStyleChannels)
247             throws UnsupportedComponentException {
248         String schema = builder.getConfig(ChannelConfiguration.class).schema;
249         switch (schema) {
250             case DEFAULT_SCHEMA:
251                 return new DefaultSchemaLight(builder, newStyleChannels);
252             case JSON_SCHEMA:
253                 return new JSONSchemaLight(builder, newStyleChannels);
254             case TEMPLATE_SCHEMA:
255                 return new TemplateSchemaLight(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         finalizeChannels();
296     }
297
298     protected abstract void buildChannels();
299
300     @Override
301     public void postChannelCommand(ChannelUID channelUID, Command value) {
302         throw new UnsupportedOperationException();
303     }
304
305     @Override
306     public void triggerChannel(ChannelUID channelUID, String eventPayload) {
307         throw new UnsupportedOperationException();
308     }
309 }