]> git.basschouten.com Git - openhab-addons.git/blob
3bb92de950357d5b704c3ec0b719fae13d82e8e6
[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.wled.internal.handlers;
14
15 import static org.openhab.binding.wled.internal.WLedBindingConstants.*;
16
17 import java.math.BigDecimal;
18 import java.util.ArrayList;
19 import java.util.List;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.openhab.binding.wled.internal.WLedSegmentConfiguration;
23 import org.openhab.binding.wled.internal.api.ApiException;
24 import org.openhab.binding.wled.internal.api.WledApi;
25 import org.openhab.core.library.types.DecimalType;
26 import org.openhab.core.library.types.HSBType;
27 import org.openhab.core.library.types.IncreaseDecreaseType;
28 import org.openhab.core.library.types.OnOffType;
29 import org.openhab.core.library.types.PercentType;
30 import org.openhab.core.thing.Bridge;
31 import org.openhab.core.thing.Channel;
32 import org.openhab.core.thing.ChannelUID;
33 import org.openhab.core.thing.Thing;
34 import org.openhab.core.thing.ThingStatus;
35 import org.openhab.core.thing.ThingStatusDetail;
36 import org.openhab.core.thing.binding.BaseThingHandler;
37 import org.openhab.core.thing.binding.builder.ThingBuilder;
38 import org.openhab.core.types.Command;
39 import org.openhab.core.types.RefreshType;
40 import org.openhab.core.types.State;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 /**
45  * The {@link WLedSegmentHandler} is responsible for handling only a single segment from a WLED device.
46  *
47  * @author Matthew Skinner - Initial contribution
48  */
49
50 @NonNullByDefault
51 public class WLedSegmentHandler extends BaseThingHandler {
52     private final Logger logger = LoggerFactory.getLogger(getClass());
53     private WLedSegmentConfiguration config = new WLedSegmentConfiguration();
54     private BigDecimal masterBrightness255 = BigDecimal.ZERO;
55     private HSBType primaryColor = new HSBType();
56     private HSBType secondaryColor = new HSBType();
57     private HSBType thirdColor = new HSBType();
58
59     public WLedSegmentHandler(Thing thing) {
60         super(thing);
61     }
62
63     public void update(String channelID, State state) {
64         updateState(channelID, state);
65     }
66
67     private void removeWhiteChannels() {
68         List<Channel> removeChannels = new ArrayList<>();
69         Channel channel = getThing().getChannel(CHANNEL_PRIMARY_WHITE);
70         if (channel != null) {
71             removeChannels.add(channel);
72         }
73         channel = getThing().getChannel(CHANNEL_SECONDARY_WHITE);
74         if (channel != null) {
75             removeChannels.add(channel);
76         }
77         channel = getThing().getChannel(CHANNEL_THIRD_WHITE);
78         if (channel != null) {
79             removeChannels.add(channel);
80         }
81         removeChannels(removeChannels);
82     }
83
84     private void removeChannels(List<Channel> removeChannels) {
85         if (!removeChannels.isEmpty()) {
86             ThingBuilder thingBuilder = editThing();
87             thingBuilder.withoutChannels(removeChannels);
88             updateThing(thingBuilder.build());
89         }
90     }
91
92     @Override
93     public void handleCommand(ChannelUID channelUID, Command command) {
94         Bridge bridge = getBridge();
95         if (bridge == null) {
96             return;
97         }
98         WLedBridgeHandler bridgeHandler = (WLedBridgeHandler) bridge.getHandler();
99         if (bridgeHandler == null) {
100             return;
101         }
102         WledApi localApi = bridgeHandler.api;
103         if (localApi == null) {
104             return;
105         }
106         if (command instanceof RefreshType) {
107             return;// no need to check for refresh below
108         }
109         logger.debug("command {} sent to {}", command, channelUID.getId());
110         try {
111             switch (channelUID.getId()) {
112                 case CHANNEL_SEGMENT_BRIGHTNESS:
113                     if (command instanceof OnOffType) {
114                         localApi.setMasterOn(OnOffType.ON.equals(command), config.segmentIndex);
115                     } else if (command instanceof PercentType percentCommand) {
116                         if (PercentType.ZERO.equals(command)) {
117                             localApi.setMasterOn(false, config.segmentIndex);
118                             return;
119                         }
120                         // do not turn the globalOn in order to allow for configuring this segment for effects that
121                         // start later
122                         localApi.setMasterBrightness(percentCommand, config.segmentIndex);
123                     }
124                     break;
125                 case CHANNEL_MIRROR:
126                     localApi.setMirror(OnOffType.ON.equals(command), config.segmentIndex);
127                     break;
128                 case CHANNEL_SPACING:
129                     if (command instanceof DecimalType decimalCommand) {
130                         localApi.setSpacing(decimalCommand.intValue(), config.segmentIndex);
131                     }
132                     break;
133                 case CHANNEL_GROUPING:
134                     if (command instanceof DecimalType decimalCommand) {
135                         localApi.setGrouping(decimalCommand.intValue(), config.segmentIndex);
136                     }
137                     break;
138                 case CHANNEL_REVERSE:
139                     localApi.setReverse(OnOffType.ON.equals(command), config.segmentIndex);
140                     break;
141                 case CHANNEL_PRIMARY_WHITE:
142                     if (command instanceof PercentType percentCommand) {
143                         localApi.sendGetRequest("/win&W=" + percentCommand.toBigDecimal().multiply(BIG_DECIMAL_2_55));
144                     }
145                     break;
146                 case CHANNEL_SECONDARY_WHITE:
147                     if (command instanceof PercentType percentCommand) {
148                         localApi.sendGetRequest("/win&W2=" + percentCommand.toBigDecimal().multiply(BIG_DECIMAL_2_55));
149                     }
150                     break;
151                 case CHANNEL_MASTER_CONTROLS:
152                     if (command instanceof OnOffType) {
153                         if (OnOffType.ON.equals(command)) {
154                             // global may be off, but we don't want to switch global off and affect other segments
155                             localApi.setGlobalOn(true);
156                         }
157                         localApi.setMasterOn(OnOffType.ON.equals(command), config.segmentIndex);
158                     } else if (command instanceof IncreaseDecreaseType) {
159                         if (IncreaseDecreaseType.INCREASE.equals(command)) {
160                             localApi.setGlobalOn(true);
161                             if (masterBrightness255.intValue() < 240) {
162                                 localApi.sendGetRequest("/win&TT=1000&A=~15"); // 255 divided by 15 = 17 levels
163                             } else {
164                                 localApi.sendGetRequest("/win&TT=1000&A=255");
165                             }
166                         } else {
167                             if (masterBrightness255.intValue() > 15) {
168                                 localApi.sendGetRequest("/win&TT=1000&A=~-15");
169                             } else {
170                                 localApi.sendGetRequest("/win&TT=1000&A=0");
171                             }
172                         }
173                     } else if (command instanceof HSBType hsbCommand) {
174                         if ((hsbCommand.getBrightness()).equals(PercentType.ZERO)) {
175                             localApi.setMasterOn(false, config.segmentIndex);
176                             return;
177                         }
178                         localApi.setGlobalOn(true);
179                         primaryColor = hsbCommand;
180                         if (primaryColor.getSaturation().intValue() < bridgeHandler.config.saturationThreshold
181                                 && bridgeHandler.hasWhite) {
182                             localApi.setWhiteOnly(hsbCommand, config.segmentIndex);
183                         } else if (primaryColor.getSaturation().intValue() == 32
184                                 && primaryColor.getHue().intValue() == 36 && bridgeHandler.hasWhite) {
185                             localApi.setWhiteOnly(hsbCommand, config.segmentIndex);
186                         } else {
187                             localApi.setMasterHSB(hsbCommand, config.segmentIndex);
188                         }
189                     } else if (command instanceof PercentType percentCommand) {
190                         if (PercentType.ZERO.equals(percentCommand)) {
191                             localApi.setMasterOn(false, config.segmentIndex);
192                             return;
193                         }
194                         localApi.setGlobalOn(true);
195                         localApi.setMasterBrightness(percentCommand, config.segmentIndex);
196                     }
197                     return;
198                 case CHANNEL_PRIMARY_COLOR:
199                     if (command instanceof HSBType hsbCommand) {
200                         primaryColor = hsbCommand;
201                     } else if (command instanceof PercentType percentCommand) {
202                         primaryColor = new HSBType(primaryColor.getHue(), primaryColor.getSaturation(), percentCommand);
203                     }
204                     localApi.setPrimaryColor(primaryColor, config.segmentIndex);
205                     return;
206                 case CHANNEL_SECONDARY_COLOR:
207                     if (command instanceof HSBType hsbCommand) {
208                         secondaryColor = hsbCommand;
209                     } else if (command instanceof PercentType percentCommand) {
210                         secondaryColor = new HSBType(secondaryColor.getHue(), secondaryColor.getSaturation(),
211                                 percentCommand);
212                     }
213                     localApi.setSecondaryColor(secondaryColor, config.segmentIndex);
214                     return;
215                 case CHANNEL_THIRD_COLOR:
216                     if (command instanceof HSBType hsbCommand) {
217                         thirdColor = hsbCommand;
218                     } else if (command instanceof PercentType percentCommand) {
219                         thirdColor = new HSBType(thirdColor.getHue(), thirdColor.getSaturation(), percentCommand);
220                     }
221                     localApi.setTertiaryColor(thirdColor, config.segmentIndex);
222                     return;
223                 case CHANNEL_PALETTES:
224                     localApi.setPalette(command.toString(), config.segmentIndex);
225                     break;
226                 case CHANNEL_FX:
227                     localApi.setGlobalOn(true);
228                     localApi.setEffect(command.toString(), config.segmentIndex);
229                     break;
230                 case CHANNEL_SPEED:
231                     localApi.setFxSpeed((PercentType) command, config.segmentIndex);
232                     break;
233                 case CHANNEL_INTENSITY:
234                     localApi.setFxIntencity((PercentType) command, config.segmentIndex);
235                     break;
236             }
237         } catch (ApiException e) {
238             logger.debug("Exception occured:{}", e.getMessage());
239         }
240     }
241
242     @Override
243     public void initialize() {
244         config = getConfigAs(WLedSegmentConfiguration.class);
245         Bridge bridge = getBridge();
246         if (bridge == null) {
247             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No bridge is selected.");
248         } else {
249             WLedBridgeHandler localBridgeHandler = (WLedBridgeHandler) bridge.getHandler();
250             if (localBridgeHandler == null) {
251                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
252                 return;
253             }
254             WledApi localAPI = localBridgeHandler.api;
255             if (localAPI != null) {
256                 updateStatus(ThingStatus.ONLINE);
257                 localBridgeHandler.stateDescriptionProvider
258                         .setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_FX), localAPI.getUpdatedFxList());
259                 localBridgeHandler.stateDescriptionProvider.setStateOptions(
260                         new ChannelUID(getThing().getUID(), CHANNEL_PALETTES), localAPI.getUpdatedPaletteList());
261                 if (!localBridgeHandler.hasWhite) {
262                     logger.debug("WLED is not setup to use RGBW, so removing un-needed white channels");
263                     removeWhiteChannels();
264                 }
265             } else {
266                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
267             }
268         }
269     }
270 }