[wled] Change to bridge/thing structure and add global controls (#12199)
* Update to using bridge/thing * remove white channels. * Improve Discovery * Add more sleep/ timed light / NL features * Change advanced channels * fix bug for sleep duration * Update readme with new channels * Move channels into separate readme heading. * fix white jumps to 0 after moving control. Signed-off-by: Matthew Skinner <matt@pcmus.com>
This commit is contained in:
@@ -14,6 +14,7 @@ package org.openhab.binding.wled.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.wled.internal.handlers.WLedBridgeHandler;
|
||||
import org.openhab.core.automation.annotation.ActionInput;
|
||||
import org.openhab.core.automation.annotation.RuleAction;
|
||||
import org.openhab.core.thing.binding.ThingActions;
|
||||
@@ -32,11 +33,11 @@ import org.slf4j.LoggerFactory;
|
||||
@NonNullByDefault
|
||||
public class WLedActions implements ThingActions {
|
||||
public final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private @Nullable WLedHandler handler;
|
||||
private @Nullable WLedBridgeHandler handler;
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
this.handler = (WLedHandler) handler;
|
||||
this.handler = (WLedBridgeHandler) handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,7 +63,7 @@ public class WLedActions implements ThingActions {
|
||||
public void savePreset(
|
||||
@ActionInput(name = "presetNumber", label = "Preset Slot", description = "Number for the preset slot you wish to use") int presetNumber,
|
||||
@ActionInput(name = "presetName", label = "Preset Name", description = "Name for the preset that you wish to use") String presetName) {
|
||||
WLedHandler localHandler = handler;
|
||||
WLedBridgeHandler localHandler = handler;
|
||||
if (localHandler != null) {
|
||||
localHandler.savePreset(presetNumber, presetName);
|
||||
}
|
||||
|
||||
@@ -28,12 +28,14 @@ import org.openhab.core.thing.ThingTypeUID;
|
||||
public class WLedBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "wled";
|
||||
public static final String BRIDGE_TYPE_ID = "json";
|
||||
public static final BigDecimal BIG_DECIMAL_2_55 = new BigDecimal(2.55);
|
||||
public static final BigDecimal BIG_DECIMAL_182_04 = new BigDecimal(182.04);
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_WLED = new ThingTypeUID(BINDING_ID, "wled");
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_WLED);
|
||||
public static final ThingTypeUID THING_TYPE_SEGMENT = new ThingTypeUID(BINDING_ID, "segment");
|
||||
public static final ThingTypeUID THING_TYPE_JSON = new ThingTypeUID(BINDING_ID, BRIDGE_TYPE_ID);
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_SEGMENT, THING_TYPE_JSON);
|
||||
|
||||
// Configs
|
||||
public static final String CONFIG_ADDRESS = "address";
|
||||
@@ -42,6 +44,7 @@ public class WLedBindingConstants {
|
||||
public static final String CONFIG_SAT_THRESHOLD = "saturationThreshold";
|
||||
|
||||
// Channels
|
||||
public static final String CHANNEL_GLOBAL_BRIGHTNESS = "globalBrightness";
|
||||
public static final String CHANNEL_MASTER_CONTROLS = "masterControls";
|
||||
public static final String CHANNEL_SEGMENT_BRIGHTNESS = "segmentBrightness";
|
||||
public static final String CHANNEL_PRIMARY_COLOR = "primaryColor";
|
||||
@@ -65,6 +68,9 @@ public class WLedBindingConstants {
|
||||
public static final String CHANNEL_SPACING = "spacing";
|
||||
public static final String CHANNEL_LIVE_OVERRIDE = "liveOverride";
|
||||
public static final String CHANNEL_SLEEP = "sleep";
|
||||
public static final String CHANNEL_SLEEP_MODE = "sleepMode";
|
||||
public static final String CHANNEL_SLEEP_DURATION = "sleepDuration";
|
||||
public static final String CHANNEL_SLEEP_BRIGHTNESS = "sleepTargetBrightness";
|
||||
public static final String CHANNEL_SYNC_SEND = "syncSend";
|
||||
public static final String CHANNEL_SYNC_RECEIVE = "syncReceive";
|
||||
}
|
||||
|
||||
@@ -22,9 +22,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
@NonNullByDefault
|
||||
public class WLedConfiguration {
|
||||
public String address = "";
|
||||
public int pollTime;
|
||||
public int segmentIndex;
|
||||
public int pollTime = 5;
|
||||
public int saturationThreshold;
|
||||
public boolean sortEffects = false;
|
||||
public boolean sortPalettes = false;
|
||||
public boolean sortEffects = true;
|
||||
public boolean sortPalettes = true;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ package org.openhab.binding.wled.internal;
|
||||
|
||||
import static org.openhab.binding.wled.internal.WLedBindingConstants.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@@ -92,22 +91,20 @@ public class WLedDiscoveryService implements MDNSDiscoveryParticipant {
|
||||
return null;
|
||||
}
|
||||
String response = sendGetRequest(address[0], "/json");
|
||||
// LinkedList<String> segmentIndexList = WLedHelper.listOfResults(response, "{\"id\":", ",");
|
||||
// How to create multiple things from the returned list of segments?
|
||||
String label = WLedHelper.getValue(response, "\"name\":\"", "\"");
|
||||
if (label.isEmpty()) {
|
||||
label = "WLED @ " + address[0];
|
||||
}
|
||||
String macAddress = WLedHelper.getValue(response, "\"mac\":\"", "\"");
|
||||
String firmware = WLedHelper.getValue(response, "\"ver\":\"", "\"");
|
||||
ThingTypeUID thingtypeuid = new ThingTypeUID("wled", "wled");
|
||||
ThingUID thingUID = new ThingUID(thingtypeuid, macAddress);
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(Thing.PROPERTY_MAC_ADDRESS, macAddress);
|
||||
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, firmware);
|
||||
return DiscoveryResultBuilder.create(thingUID).withProperty(CONFIG_ADDRESS, address[0])
|
||||
.withProperty(CONFIG_SEGMENT_INDEX, 0).withLabel(label).withProperties(properties)
|
||||
.withRepresentationProperty(Thing.PROPERTY_MAC_ADDRESS).build();
|
||||
if (!macAddress.isBlank()) {
|
||||
String firmware = WLedHelper.getValue(response, "\"ver\":\"", "\"");
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_JSON, macAddress);
|
||||
Map<String, Object> properties = Map.of(Thing.PROPERTY_MAC_ADDRESS, macAddress,
|
||||
Thing.PROPERTY_FIRMWARE_VERSION, firmware, CONFIG_ADDRESS, address[0]);
|
||||
return DiscoveryResultBuilder.create(thingUID).withLabel(label).withProperties(properties)
|
||||
.withRepresentationProperty(Thing.PROPERTY_MAC_ADDRESS).build();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,11 +12,14 @@
|
||||
*/
|
||||
package org.openhab.binding.wled.internal;
|
||||
|
||||
import static org.openhab.binding.wled.internal.WLedBindingConstants.SUPPORTED_THING_TYPES;
|
||||
import static org.openhab.binding.wled.internal.WLedBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.wled.internal.api.WledApiFactory;
|
||||
import org.openhab.binding.wled.internal.handlers.WLedBridgeHandler;
|
||||
import org.openhab.binding.wled.internal.handlers.WLedSegmentHandler;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
@@ -53,8 +56,10 @@ public class WLedHandlerFactory extends BaseThingHandlerFactory {
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
if (SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
|
||||
return new WLedHandler(thing, apiFactory, stateDescriptionProvider);
|
||||
if (THING_TYPE_SEGMENT.equals(thingTypeUID)) {
|
||||
return new WLedSegmentHandler(thing);
|
||||
} else if (THING_TYPE_JSON.equals(thingTypeUID)) {
|
||||
return new WLedBridgeHandler((Bridge) thing, apiFactory, stateDescriptionProvider);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
*/
|
||||
package org.openhab.binding.wled.internal;
|
||||
|
||||
import static org.openhab.binding.wled.internal.WLedBindingConstants.BIG_DECIMAL_2_55;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -44,7 +47,7 @@ public class WLedHelper {
|
||||
// example message rgb in array brackets [255.0, 255.0, 255.0, 255.0]
|
||||
List<String> colors = Arrays.asList(message.replaceAll("\\[|\\]", "").split("\\s*,\\s*"));
|
||||
try {
|
||||
return new PercentType(new BigDecimal(colors.get(2)));
|
||||
return new PercentType(new BigDecimal(colors.get(3)).divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return new PercentType();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.wled.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link WLedSegmentConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Matthew Skinner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class WLedSegmentConfiguration {
|
||||
public int segmentIndex;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.wled.internal;
|
||||
|
||||
import static org.openhab.binding.wled.internal.WLedBindingConstants.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.wled.internal.api.WledApi;
|
||||
import org.openhab.binding.wled.internal.handlers.WLedBridgeHandler;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
|
||||
/**
|
||||
* The {@link WLedSegmentDiscoveryService} Discovers and adds any Wled segments found by the bridge device.
|
||||
*
|
||||
* @author Matthew Skinner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class WLedSegmentDiscoveryService extends AbstractDiscoveryService
|
||||
implements DiscoveryService, ThingHandlerService {
|
||||
private @Nullable WLedBridgeHandler bridgeHandler;
|
||||
private @Nullable ThingUID bridgeUID;
|
||||
private static final int SEARCH_TIME = 10;
|
||||
|
||||
public WLedSegmentDiscoveryService() {
|
||||
super(SUPPORTED_THING_TYPES, SEARCH_TIME);
|
||||
}
|
||||
|
||||
public WLedSegmentDiscoveryService(Set<ThingTypeUID> supportedThingTypes, int timeout)
|
||||
throws IllegalArgumentException {
|
||||
super(supportedThingTypes, timeout);
|
||||
}
|
||||
|
||||
private void buildThing(int segmentIndex, String segmentName) {
|
||||
ThingUID localBridgeUID = bridgeUID;
|
||||
if (localBridgeUID == null) {
|
||||
return;
|
||||
}
|
||||
String newThingUID = localBridgeUID.getId() + "-" + segmentIndex;
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_SEGMENT, localBridgeUID, newThingUID);
|
||||
Map<String, Object> properties = Map.of(Thing.PROPERTY_SERIAL_NUMBER, newThingUID, CONFIG_SEGMENT_INDEX,
|
||||
segmentIndex);
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withLabel(segmentName)
|
||||
.withProperties(properties).withBridge(bridgeUID)
|
||||
.withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER).build();
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
WLedBridgeHandler localBridgeHandler = bridgeHandler;
|
||||
if (localBridgeHandler != null) {
|
||||
WledApi localAPI = localBridgeHandler.api;
|
||||
if (localAPI != null) {
|
||||
List<String> names = localAPI.getSegmentNames();
|
||||
for (int count = 0; count < names.size(); count++) {
|
||||
buildThing(count, names.get(count));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
if (handler instanceof WLedBridgeHandler) {
|
||||
bridgeHandler = (WLedBridgeHandler) handler;
|
||||
bridgeUID = bridgeHandler.getThing().getUID();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return bridgeHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
}
|
||||
}
|
||||
@@ -91,6 +91,7 @@ public class WledState {
|
||||
public boolean sel = true;
|
||||
public boolean rev = false;
|
||||
public boolean mi = false;
|
||||
public String n = "Segment X";
|
||||
}
|
||||
|
||||
public class NightLightState {
|
||||
|
||||
@@ -13,10 +13,12 @@
|
||||
package org.openhab.binding.wled.internal.api;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.types.StateOption;
|
||||
|
||||
/**
|
||||
* The {@link WledApi} is the JSON API methods that can be extended for different firmware versions.
|
||||
@@ -70,6 +72,12 @@ public interface WledApi {
|
||||
|
||||
public abstract void setSleep(boolean bool) throws ApiException;
|
||||
|
||||
public abstract void setSleepMode(String value) throws ApiException;
|
||||
|
||||
public abstract void setSleepDuration(BigDecimal time) throws ApiException;
|
||||
|
||||
public abstract void setSleepTargetBrightness(PercentType percent) throws ApiException;
|
||||
|
||||
public abstract void setUdpSend(boolean bool) throws ApiException;
|
||||
|
||||
public abstract void setUdpRecieve(boolean bool) throws ApiException;
|
||||
@@ -102,4 +110,10 @@ public interface WledApi {
|
||||
*
|
||||
*/
|
||||
public abstract void savePreset(int position, String presetName) throws ApiException;
|
||||
|
||||
public abstract List<StateOption> getUpdatedFxList();
|
||||
|
||||
public abstract List<StateOption> getUpdatedPaletteList();
|
||||
|
||||
public abstract List<String> getSegmentNames();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ package org.openhab.binding.wled.internal.api;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.wled.internal.WLedHandler;
|
||||
import org.openhab.binding.wled.internal.handlers.WLedBridgeHandler;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
@@ -39,7 +39,7 @@ public class WledApiFactory {
|
||||
this.httpClient = httpClientFactory.getCommonHttpClient();
|
||||
}
|
||||
|
||||
public WledApi getApi(WLedHandler handler) throws ApiException {
|
||||
public WledApi getApi(WLedBridgeHandler handler) throws ApiException {
|
||||
WledApi lowestSupportedApi = new WledApiV084(handler, httpClient);
|
||||
int version = lowestSupportedApi.getFirmwareVersion();
|
||||
logger.debug("Treating firmware as int:{}", version);
|
||||
|
||||
@@ -21,8 +21,8 @@ import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.wled.internal.WLedHandler;
|
||||
import org.openhab.binding.wled.internal.WledState.PresetState;
|
||||
import org.openhab.binding.wled.internal.handlers.WLedBridgeHandler;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.types.StateOption;
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link WledApiV0130} is the json Api methods for firmware version 0.11.0 and newer
|
||||
* The {@link WledApiV0110} is the json Api methods for firmware version 0.11.0 and newer
|
||||
* as newer firmwares come out with breaking changes, extend this class into a newer firmware version class.
|
||||
*
|
||||
* @author Matthew Skinner - Initial contribution
|
||||
@@ -39,7 +39,7 @@ import com.google.gson.JsonSyntaxException;
|
||||
@NonNullByDefault
|
||||
public class WledApiV0110 extends WledApiV084 {
|
||||
|
||||
public WledApiV0110(WLedHandler handler, HttpClient httpClient) {
|
||||
public WledApiV0110(WLedBridgeHandler handler, HttpClient httpClient) {
|
||||
super(handler, httpClient);
|
||||
}
|
||||
|
||||
@@ -89,4 +89,9 @@ public class WledApiV0110 extends WledApiV084 {
|
||||
}
|
||||
postState("{\"psave\":" + position + ",\"n\":\"" + name + "\",\"ib\":true,\"sb\":true}");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSleepMode(String value) throws ApiException {
|
||||
postState("{\"nl\":{\"mode\":" + value + "}}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,12 @@ package org.openhab.binding.wled.internal.api;
|
||||
import static org.openhab.binding.wled.internal.WLedBindingConstants.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.wled.internal.WLedHandler;
|
||||
import org.openhab.binding.wled.internal.WledState.SegmentState;
|
||||
import org.openhab.binding.wled.internal.handlers.WLedBridgeHandler;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Channel;
|
||||
|
||||
@@ -31,7 +33,7 @@ import org.openhab.core.thing.Channel;
|
||||
@NonNullByDefault
|
||||
public class WledApiV0130 extends WledApiV0110 {
|
||||
|
||||
public WledApiV0130(WLedHandler handler, HttpClient httpClient) {
|
||||
public WledApiV0130(WLedBridgeHandler handler, HttpClient httpClient) {
|
||||
super(handler, httpClient);
|
||||
}
|
||||
|
||||
@@ -48,12 +50,24 @@ public class WledApiV0130 extends WledApiV0110 {
|
||||
if (channel != null) {
|
||||
removeChannels.add(channel);
|
||||
}
|
||||
handler.removeChannels(removeChannels);
|
||||
if (!removeChannels.isEmpty()) {
|
||||
handler.removeBridgeChannels(removeChannels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processState() throws ApiException {
|
||||
super.processState();
|
||||
protected void processState(int segmentIndex) throws ApiException {
|
||||
super.processState(segmentIndex);
|
||||
handler.update(CHANNEL_PLAYLISTS, new StringType(Integer.toString(state.stateResponse.pl)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSegmentNames() {
|
||||
// segment names was only first added in 0.13.0 firmware
|
||||
List<String> segmentNames = new ArrayList<>(state.stateResponse.seg.length);
|
||||
for (SegmentState state : state.stateResponse.seg) {
|
||||
segmentNames.add(state.n);
|
||||
}
|
||||
return segmentNames;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,13 +31,13 @@ import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.openhab.binding.wled.internal.WLedHandler;
|
||||
import org.openhab.binding.wled.internal.WLedHelper;
|
||||
import org.openhab.binding.wled.internal.WledState;
|
||||
import org.openhab.binding.wled.internal.WledState.InfoResponse;
|
||||
import org.openhab.binding.wled.internal.WledState.JsonResponse;
|
||||
import org.openhab.binding.wled.internal.WledState.LedInfo;
|
||||
import org.openhab.binding.wled.internal.WledState.StateResponse;
|
||||
import org.openhab.binding.wled.internal.handlers.WLedBridgeHandler;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
@@ -45,8 +45,6 @@ import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.types.StateOption;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -65,12 +63,12 @@ public class WledApiV084 implements WledApi {
|
||||
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
protected final Gson gson = new Gson();
|
||||
protected final HttpClient httpClient;
|
||||
protected final WLedHandler handler;
|
||||
protected final WLedBridgeHandler handler;
|
||||
protected final String address;
|
||||
protected WledState state = new WledState();
|
||||
private int version = 0;
|
||||
|
||||
public WledApiV084(WLedHandler handler, HttpClient httpClient) {
|
||||
public WledApiV084(WLedBridgeHandler handler, HttpClient httpClient) {
|
||||
this.handler = handler;
|
||||
this.address = handler.config.address;
|
||||
this.httpClient = httpClient;
|
||||
@@ -79,33 +77,13 @@ public class WledApiV084 implements WledApi {
|
||||
@Override
|
||||
public void initialize() throws ApiException {
|
||||
state.jsonResponse = getJson();
|
||||
getUpdatedFxList();
|
||||
getUpdatedPaletteList();
|
||||
|
||||
state.infoResponse = getInfo();
|
||||
@Nullable
|
||||
LedInfo localLedInfo = gson.fromJson(state.infoResponse.leds.toString(), LedInfo.class);
|
||||
if (localLedInfo != null) {
|
||||
state.ledInfo = localLedInfo;
|
||||
}
|
||||
|
||||
handler.hasWhite = state.ledInfo.rgbw;
|
||||
ArrayList<Channel> removeChannels = new ArrayList<>();
|
||||
if (!state.ledInfo.rgbw) {
|
||||
logger.debug("WLED is not setup to use RGBW, so removing un-needed white channels");
|
||||
Channel channel = handler.getThing().getChannel(CHANNEL_PRIMARY_WHITE);
|
||||
if (channel != null) {
|
||||
removeChannels.add(channel);
|
||||
}
|
||||
channel = handler.getThing().getChannel(CHANNEL_SECONDARY_WHITE);
|
||||
if (channel != null) {
|
||||
removeChannels.add(channel);
|
||||
}
|
||||
channel = handler.getThing().getChannel(CHANNEL_THIRD_WHITE);
|
||||
if (channel != null) {
|
||||
removeChannels.add(channel);
|
||||
}
|
||||
}
|
||||
handler.removeChannels(removeChannels);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -172,7 +150,10 @@ public class WledApiV084 implements WledApi {
|
||||
}
|
||||
state.stateResponse = response;
|
||||
state.unpackJsonObjects();
|
||||
processState();
|
||||
processBridgeStates();
|
||||
for (int count = 0; count < state.stateResponse.seg.length; count++) {
|
||||
processState(count);
|
||||
}
|
||||
} catch (JsonSyntaxException | ApiException e) {
|
||||
logger.debug("Reply back when a command was sent triggered an exception:{}", jsonState);
|
||||
}
|
||||
@@ -199,6 +180,7 @@ public class WledApiV084 implements WledApi {
|
||||
if (response == null) {
|
||||
throw new ApiException("Could not GET:/json/info");
|
||||
}
|
||||
logger.trace("/json/info:{}", returnContent);
|
||||
return response;
|
||||
} catch (JsonSyntaxException e) {
|
||||
throw new ApiException("JsonSyntaxException:{}", e);
|
||||
@@ -222,10 +204,14 @@ public class WledApiV084 implements WledApi {
|
||||
public void update() throws ApiException {
|
||||
state.stateResponse = getState();
|
||||
state.unpackJsonObjects();
|
||||
processState();
|
||||
processBridgeStates();
|
||||
for (int count = 0; count < state.stateResponse.seg.length; count++) {
|
||||
processState(count);
|
||||
}
|
||||
}
|
||||
|
||||
protected void getUpdatedFxList() {
|
||||
@Override
|
||||
public List<StateOption> getUpdatedFxList() {
|
||||
List<StateOption> fxOptions = new ArrayList<>();
|
||||
int counter = 0;
|
||||
for (String value : state.jsonResponse.effects) {
|
||||
@@ -234,11 +220,11 @@ public class WledApiV084 implements WledApi {
|
||||
if (handler.config.sortEffects) {
|
||||
fxOptions.sort(Comparator.comparing(o -> o.getValue().equals("0") ? "" : o.getLabel()));
|
||||
}
|
||||
handler.stateDescriptionProvider.setStateOptions(new ChannelUID(handler.getThing().getUID(), CHANNEL_FX),
|
||||
fxOptions);
|
||||
return fxOptions;
|
||||
}
|
||||
|
||||
protected void getUpdatedPaletteList() {
|
||||
@Override
|
||||
public List<StateOption> getUpdatedPaletteList() {
|
||||
List<StateOption> palleteOptions = new ArrayList<>();
|
||||
int counter = 0;
|
||||
for (String value : state.jsonResponse.palettes) {
|
||||
@@ -247,8 +233,7 @@ public class WledApiV084 implements WledApi {
|
||||
if (handler.config.sortPalettes) {
|
||||
palleteOptions.sort(Comparator.comparing(o -> o.getValue().equals("0") ? "" : o.getLabel()));
|
||||
}
|
||||
handler.stateDescriptionProvider.setStateOptions(new ChannelUID(handler.getThing().getUID(), CHANNEL_PALETTES),
|
||||
palleteOptions);
|
||||
return palleteOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -264,46 +249,20 @@ public class WledApiV084 implements WledApi {
|
||||
return version;
|
||||
}
|
||||
|
||||
protected void processState() throws ApiException {
|
||||
if (state.stateResponse.seg.length <= handler.config.segmentIndex) {
|
||||
throw new ApiException("Segment " + handler.config.segmentIndex
|
||||
+ " is not currently setup correctly in the WLED firmware");
|
||||
}
|
||||
HSBType tempHSB = WLedHelper
|
||||
.parseToHSBType(state.stateResponse.seg[handler.config.segmentIndex].col[0].toString());
|
||||
handler.update(CHANNEL_PRIMARY_COLOR, tempHSB);
|
||||
handler.update(CHANNEL_SECONDARY_COLOR,
|
||||
WLedHelper.parseToHSBType(state.stateResponse.seg[handler.config.segmentIndex].col[1].toString()));
|
||||
handler.update(CHANNEL_THIRD_COLOR,
|
||||
WLedHelper.parseToHSBType(state.stateResponse.seg[handler.config.segmentIndex].col[2].toString()));
|
||||
if (state.ledInfo.rgbw) {
|
||||
handler.update(CHANNEL_PRIMARY_WHITE, WLedHelper
|
||||
.parseWhitePercent(state.stateResponse.seg[handler.config.segmentIndex].col[0].toString()));
|
||||
handler.update(CHANNEL_SECONDARY_WHITE, WLedHelper
|
||||
.parseWhitePercent(state.stateResponse.seg[handler.config.segmentIndex].col[1].toString()));
|
||||
handler.update(CHANNEL_THIRD_WHITE, WLedHelper
|
||||
.parseWhitePercent(state.stateResponse.seg[handler.config.segmentIndex].col[2].toString()));
|
||||
}
|
||||
// Global OFF or Segment OFF needs to be treated as OFF
|
||||
if (!state.stateResponse.seg[handler.config.segmentIndex].on || !state.stateResponse.on) {
|
||||
handler.update(CHANNEL_MASTER_CONTROLS, OnOffType.OFF);
|
||||
handler.update(CHANNEL_SEGMENT_BRIGHTNESS, OnOffType.OFF);
|
||||
protected void processBridgeStates() throws ApiException {
|
||||
if (!state.stateResponse.on) {
|
||||
handler.update(CHANNEL_GLOBAL_BRIGHTNESS, OnOffType.OFF);
|
||||
} else {
|
||||
handler.update(CHANNEL_MASTER_CONTROLS, tempHSB);
|
||||
handler.update(CHANNEL_SEGMENT_BRIGHTNESS,
|
||||
new PercentType(new BigDecimal(state.stateResponse.seg[handler.config.segmentIndex].bri)
|
||||
.divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP)));
|
||||
handler.update(CHANNEL_GLOBAL_BRIGHTNESS, new PercentType(
|
||||
new BigDecimal(state.stateResponse.bri).divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP)));
|
||||
}
|
||||
handler.update(CHANNEL_LIVE_OVERRIDE, new StringType(Integer.toString(state.stateResponse.lor)));
|
||||
handler.update(CHANNEL_PRESETS, new StringType(Integer.toString(state.stateResponse.ps)));
|
||||
if (state.nightLightState.on) {
|
||||
handler.update(CHANNEL_SLEEP, OnOffType.ON);
|
||||
} else {
|
||||
handler.update(CHANNEL_SLEEP, OnOffType.OFF);
|
||||
}
|
||||
if (state.stateResponse.pl == 0) {
|
||||
handler.update(CHANNEL_PRESET_CYCLE, OnOffType.ON);
|
||||
} else {
|
||||
handler.update(CHANNEL_PRESET_CYCLE, OnOffType.OFF);
|
||||
}
|
||||
if (state.udpnState.recv) {
|
||||
handler.update(CHANNEL_SYNC_RECEIVE, OnOffType.ON);
|
||||
} else {
|
||||
@@ -314,32 +273,75 @@ public class WledApiV084 implements WledApi {
|
||||
} else {
|
||||
handler.update(CHANNEL_SYNC_SEND, OnOffType.OFF);
|
||||
}
|
||||
if (state.stateResponse.seg[handler.config.segmentIndex].mi) {
|
||||
handler.update(CHANNEL_MIRROR, OnOffType.ON);
|
||||
if (state.stateResponse.pl == 0) {
|
||||
handler.update(CHANNEL_PRESET_CYCLE, OnOffType.ON);
|
||||
} else {
|
||||
handler.update(CHANNEL_MIRROR, OnOffType.OFF);
|
||||
}
|
||||
if (state.stateResponse.seg[handler.config.segmentIndex].rev) {
|
||||
handler.update(CHANNEL_REVERSE, OnOffType.ON);
|
||||
} else {
|
||||
handler.update(CHANNEL_REVERSE, OnOffType.OFF);
|
||||
handler.update(CHANNEL_PRESET_CYCLE, OnOffType.OFF);
|
||||
}
|
||||
handler.update(CHANNEL_TRANS_TIME, new QuantityType<>(
|
||||
new BigDecimal(state.stateResponse.transition).divide(BigDecimal.TEN), Units.SECOND));
|
||||
handler.update(CHANNEL_PRESETS, new StringType(Integer.toString(state.stateResponse.ps)));
|
||||
handler.update(CHANNEL_FX,
|
||||
new StringType(Integer.toString(state.stateResponse.seg[handler.config.segmentIndex].fx)));
|
||||
handler.update(CHANNEL_PALETTES,
|
||||
new StringType(Integer.toString(state.stateResponse.seg[handler.config.segmentIndex].pal)));
|
||||
handler.update(CHANNEL_SPEED,
|
||||
new PercentType(new BigDecimal(state.stateResponse.seg[handler.config.segmentIndex].sx)
|
||||
.divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP)));
|
||||
handler.update(CHANNEL_INTENSITY,
|
||||
new PercentType(new BigDecimal(state.stateResponse.seg[handler.config.segmentIndex].ix)
|
||||
.divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP)));
|
||||
handler.update(CHANNEL_LIVE_OVERRIDE, new StringType(Integer.toString(state.stateResponse.lor)));
|
||||
handler.update(CHANNEL_GROUPING, new DecimalType(state.stateResponse.seg[handler.config.segmentIndex].grp));
|
||||
handler.update(CHANNEL_SPACING, new DecimalType(state.stateResponse.seg[handler.config.segmentIndex].spc));
|
||||
handler.update(CHANNEL_SLEEP_DURATION,
|
||||
new QuantityType<>(new BigDecimal(state.nightLightState.dur), Units.MINUTE));
|
||||
handler.update(CHANNEL_SLEEP_BRIGHTNESS, new PercentType(
|
||||
new BigDecimal(state.nightLightState.tbri).divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP)));
|
||||
handler.update(CHANNEL_SLEEP_MODE, new StringType(Integer.toString(state.nightLightState.mode)));
|
||||
}
|
||||
|
||||
protected void processState(int segmentIndex) throws ApiException {
|
||||
if (state.stateResponse.seg.length <= segmentIndex) {
|
||||
throw new ApiException(
|
||||
"Segment " + segmentIndex + " is not currently setup correctly in the WLED firmware");
|
||||
}
|
||||
if (handler.handlerMissing(segmentIndex)) {
|
||||
// There is no thing setup for this segmentIndex.
|
||||
return;
|
||||
}
|
||||
HSBType tempHSB = WLedHelper.parseToHSBType(state.stateResponse.seg[segmentIndex].col[0].toString());
|
||||
handler.update(segmentIndex, CHANNEL_PRIMARY_COLOR, tempHSB);
|
||||
handler.update(segmentIndex, CHANNEL_SECONDARY_COLOR,
|
||||
WLedHelper.parseToHSBType(state.stateResponse.seg[segmentIndex].col[1].toString()));
|
||||
handler.update(segmentIndex, CHANNEL_THIRD_COLOR,
|
||||
WLedHelper.parseToHSBType(state.stateResponse.seg[segmentIndex].col[2].toString()));
|
||||
if (state.ledInfo.rgbw) {
|
||||
handler.update(segmentIndex, CHANNEL_PRIMARY_WHITE,
|
||||
WLedHelper.parseWhitePercent(state.stateResponse.seg[segmentIndex].col[0].toString()));
|
||||
handler.update(segmentIndex, CHANNEL_SECONDARY_WHITE,
|
||||
WLedHelper.parseWhitePercent(state.stateResponse.seg[segmentIndex].col[1].toString()));
|
||||
handler.update(segmentIndex, CHANNEL_THIRD_WHITE,
|
||||
WLedHelper.parseWhitePercent(state.stateResponse.seg[segmentIndex].col[2].toString()));
|
||||
}
|
||||
// Global OFF or Segment OFF needs to be treated as OFF
|
||||
if (!state.stateResponse.seg[segmentIndex].on || !state.stateResponse.on) {
|
||||
handler.update(segmentIndex, CHANNEL_MASTER_CONTROLS, OnOffType.OFF);
|
||||
handler.update(segmentIndex, CHANNEL_SEGMENT_BRIGHTNESS, OnOffType.OFF);
|
||||
} else {
|
||||
handler.update(segmentIndex, CHANNEL_MASTER_CONTROLS, tempHSB);
|
||||
handler.update(segmentIndex, CHANNEL_SEGMENT_BRIGHTNESS,
|
||||
new PercentType(new BigDecimal(state.stateResponse.seg[segmentIndex].bri).divide(BIG_DECIMAL_2_55,
|
||||
RoundingMode.HALF_UP)));
|
||||
}
|
||||
if (state.stateResponse.seg[segmentIndex].mi) {
|
||||
handler.update(segmentIndex, CHANNEL_MIRROR, OnOffType.ON);
|
||||
} else {
|
||||
handler.update(segmentIndex, CHANNEL_MIRROR, OnOffType.OFF);
|
||||
}
|
||||
if (state.stateResponse.seg[segmentIndex].rev) {
|
||||
handler.update(segmentIndex, CHANNEL_REVERSE, OnOffType.ON);
|
||||
} else {
|
||||
handler.update(segmentIndex, CHANNEL_REVERSE, OnOffType.OFF);
|
||||
}
|
||||
handler.update(segmentIndex, CHANNEL_FX,
|
||||
new StringType(Integer.toString(state.stateResponse.seg[segmentIndex].fx)));
|
||||
handler.update(segmentIndex, CHANNEL_PALETTES,
|
||||
new StringType(Integer.toString(state.stateResponse.seg[segmentIndex].pal)));
|
||||
handler.update(segmentIndex, CHANNEL_SPEED,
|
||||
new PercentType(new BigDecimal(state.stateResponse.seg[segmentIndex].sx).divide(BIG_DECIMAL_2_55,
|
||||
RoundingMode.HALF_UP)));
|
||||
handler.update(segmentIndex, CHANNEL_INTENSITY,
|
||||
new PercentType(new BigDecimal(state.stateResponse.seg[segmentIndex].ix).divide(BIG_DECIMAL_2_55,
|
||||
RoundingMode.HALF_UP)));
|
||||
handler.update(segmentIndex, CHANNEL_GROUPING, new DecimalType(state.stateResponse.seg[segmentIndex].grp));
|
||||
handler.update(segmentIndex, CHANNEL_SPACING, new DecimalType(state.stateResponse.seg[segmentIndex].spc));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -512,4 +514,28 @@ public class WledApiV084 implements WledApi {
|
||||
public void setSpacing(int value, int segmentIndex) throws ApiException {
|
||||
postState("{\"seg\":[{\"id\":" + segmentIndex + ",\"spc\":" + value + "}]}");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSegmentNames() {
|
||||
List<String> segmentNames = new ArrayList<>(state.stateResponse.seg.length);
|
||||
for (int count = 0; count < state.stateResponse.seg.length; count++) {
|
||||
segmentNames.add("Segment " + count);
|
||||
}
|
||||
return segmentNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSleepMode(String value) throws ApiException {
|
||||
// Binding requires firmware 0.11.0 and newer
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSleepDuration(BigDecimal time) throws ApiException {
|
||||
postState("{\"nl\":{\"dur\":" + time + "}}");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSleepTargetBrightness(PercentType percent) throws ApiException {
|
||||
postState("{\"nl\":{\"tbri\":" + percent.toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "}}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.wled.internal.handlers;
|
||||
|
||||
import static org.openhab.binding.wled.internal.WLedBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.wled.internal.WLedActions;
|
||||
import org.openhab.binding.wled.internal.WLedConfiguration;
|
||||
import org.openhab.binding.wled.internal.WLedSegmentDiscoveryService;
|
||||
import org.openhab.binding.wled.internal.WledDynamicStateDescriptionProvider;
|
||||
import org.openhab.binding.wled.internal.api.ApiException;
|
||||
import org.openhab.binding.wled.internal.api.WledApi;
|
||||
import org.openhab.binding.wled.internal.api.WledApiFactory;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link WLedBridgeHandler} is responsible for talking and parsing data to/from the WLED device.
|
||||
*
|
||||
* @author Matthew Skinner - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class WLedBridgeHandler extends BaseBridgeHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
public final WledDynamicStateDescriptionProvider stateDescriptionProvider;
|
||||
private Map<Integer, WLedSegmentHandler> segmentHandlers = new HashMap<Integer, WLedSegmentHandler>();
|
||||
private WledApiFactory apiFactory;
|
||||
public boolean hasWhite = false;
|
||||
public @Nullable WledApi api;
|
||||
private @Nullable ScheduledFuture<?> pollingFuture = null;
|
||||
public WLedConfiguration config = new WLedConfiguration();
|
||||
|
||||
public WLedBridgeHandler(Bridge bridge, WledApiFactory apiFactory,
|
||||
WledDynamicStateDescriptionProvider stateDescriptionProvider) {
|
||||
super(bridge);
|
||||
this.apiFactory = apiFactory;
|
||||
this.stateDescriptionProvider = stateDescriptionProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* If no thing is setup for specified segmentIndex this will return FALSE.
|
||||
*/
|
||||
public boolean handlerMissing(int segmentIndex) {
|
||||
return (segmentHandlers.get(segmentIndex) == null);
|
||||
}
|
||||
|
||||
public void savePreset(int position, String presetName) {
|
||||
WledApi localAPI = api;
|
||||
try {
|
||||
if (localAPI != null) {
|
||||
localAPI.savePreset(position, presetName);
|
||||
}
|
||||
} catch (ApiException e) {
|
||||
logger.debug("Error occured when trying to save a preset:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void removeBridgeChannels(ArrayList<Channel> removeChannels) {
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
thingBuilder.withoutChannels(removeChannels);
|
||||
updateThing(thingBuilder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a channel with a new state for a child of this bridge using the segmentIndex
|
||||
*
|
||||
* @param segmentIndex
|
||||
* @param channelID
|
||||
* @param state
|
||||
*/
|
||||
public void update(int segmentIndex, String channelID, State state) {
|
||||
WLedSegmentHandler segmentHandler = segmentHandlers.get(segmentIndex);
|
||||
if (segmentHandler != null) {
|
||||
segmentHandler.update(channelID, state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the bridges channels with a new state.
|
||||
*
|
||||
* @param channelID
|
||||
* @param state
|
||||
*/
|
||||
public void update(String channelID, State state) {
|
||||
updateState(channelID, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childHandlerInitialized(final ThingHandler childHandler, final Thing childThing) {
|
||||
BigDecimal segmentIndex = (BigDecimal) childThing.getConfiguration().get(CONFIG_SEGMENT_INDEX);
|
||||
segmentHandlers.put(segmentIndex.intValue(), (WLedSegmentHandler) childHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childHandlerDisposed(final ThingHandler childHandler, final Thing childThing) {
|
||||
BigDecimal segmentIndex = (BigDecimal) childThing.getConfiguration().get(CONFIG_SEGMENT_INDEX);
|
||||
segmentHandlers.remove(segmentIndex.intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
WledApi localApi = api;
|
||||
if (localApi == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_GLOBAL_BRIGHTNESS:
|
||||
if (command instanceof OnOffType) {
|
||||
localApi.setGlobalOn(OnOffType.ON.equals(command));
|
||||
} else if (command instanceof PercentType) {
|
||||
if (PercentType.ZERO.equals(command)) {
|
||||
localApi.setGlobalOn(false);
|
||||
return;
|
||||
}
|
||||
localApi.setGlobalBrightness((PercentType) command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_SLEEP:
|
||||
localApi.setSleep(OnOffType.ON.equals(command));
|
||||
break;
|
||||
case CHANNEL_SLEEP_MODE:
|
||||
localApi.setSleepMode(command.toString());
|
||||
break;
|
||||
case CHANNEL_SLEEP_BRIGHTNESS:
|
||||
if (command instanceof PercentType) {
|
||||
localApi.setSleepTargetBrightness((PercentType) command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_SLEEP_DURATION:
|
||||
if (command instanceof QuantityType) {
|
||||
QuantityType<?> minutes = ((QuantityType<?>) command).toUnit(Units.MINUTE);
|
||||
if (minutes != null) {
|
||||
localApi.setSleepDuration(new BigDecimal(minutes.intValue()));
|
||||
}
|
||||
} else if (command instanceof DecimalType) {
|
||||
localApi.setSleepDuration(new BigDecimal(((DecimalType) command).intValue()));
|
||||
}
|
||||
break;
|
||||
case CHANNEL_PLAYLISTS:
|
||||
localApi.setPreset(command.toString());
|
||||
break;
|
||||
case CHANNEL_SYNC_SEND:
|
||||
localApi.setUdpSend(OnOffType.ON.equals(command));
|
||||
break;
|
||||
case CHANNEL_SYNC_RECEIVE:
|
||||
localApi.setUdpRecieve(OnOffType.ON.equals(command));
|
||||
break;
|
||||
case CHANNEL_LIVE_OVERRIDE:
|
||||
localApi.setLiveOverride(command.toString());
|
||||
break;
|
||||
case CHANNEL_PRESETS:
|
||||
localApi.setPreset(command.toString());
|
||||
break;
|
||||
case CHANNEL_TRANS_TIME:
|
||||
if (command instanceof QuantityType) {
|
||||
QuantityType<?> seconds = ((QuantityType<?>) command).toUnit(Units.SECOND);
|
||||
if (seconds != null) {
|
||||
localApi.setTransitionTime(new BigDecimal(seconds.multiply(BigDecimal.TEN).intValue()));
|
||||
}
|
||||
} else if (command instanceof DecimalType) {
|
||||
localApi.setTransitionTime(
|
||||
new BigDecimal(((DecimalType) command).intValue()).multiply(BigDecimal.TEN));
|
||||
}
|
||||
break;
|
||||
case CHANNEL_PRESET_DURATION:// ch removed in firmware 0.13.0 and newer
|
||||
if (command instanceof QuantityType) {
|
||||
QuantityType<?> seconds = ((QuantityType<?>) command).toUnit(Units.SECOND);
|
||||
if (seconds != null) {
|
||||
BigDecimal bigTemp = new BigDecimal(seconds.intValue()).multiply(new BigDecimal(1000));
|
||||
localApi.sendGetRequest("/win&PT=" + bigTemp.intValue());
|
||||
}
|
||||
} else if (command instanceof DecimalType) {
|
||||
BigDecimal bigTemp = new BigDecimal(((DecimalType) command).intValue())
|
||||
.multiply(new BigDecimal(1000));
|
||||
localApi.sendGetRequest("/win&PT=" + bigTemp.intValue());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_PRESET_CYCLE: // ch removed in firmware 0.13.0 and newer
|
||||
if (command instanceof OnOffType) {
|
||||
localApi.setPresetCycle(OnOffType.ON.equals(command));
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (ApiException e) {
|
||||
logger.debug("Exception occured when Channel:{}, Command:{}, Error:{}", channelUID.getId(), command,
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void pollState() {
|
||||
WledApi localApi = api;
|
||||
try {
|
||||
if (localApi == null) {
|
||||
api = localApi = apiFactory.getApi(this);
|
||||
localApi.initialize();
|
||||
}
|
||||
localApi.update();
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} catch (ApiException e) {
|
||||
api = null;// Firmware may be updated so need to check next connect
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
config = getConfigAs(WLedConfiguration.class);
|
||||
if (!config.address.contains("://")) {
|
||||
logger.debug("Address was not entered in correct format, it may be the raw IP so adding http:// to start");
|
||||
config.address = "http://" + config.address;
|
||||
}
|
||||
pollingFuture = scheduler.scheduleWithFixedDelay(this::pollState, 0, config.pollTime, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
Future<?> future = pollingFuture;
|
||||
if (future != null) {
|
||||
future.cancel(true);
|
||||
pollingFuture = null;
|
||||
}
|
||||
api = null; // re-initialize api after configuration change
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Set.of(WLedActions.class, WLedSegmentDiscoveryService.class);
|
||||
}
|
||||
}
|
||||
@@ -10,37 +10,30 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.wled.internal;
|
||||
package org.openhab.binding.wled.internal.handlers;
|
||||
|
||||
import static org.openhab.binding.wled.internal.WLedBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.wled.internal.WLedSegmentConfiguration;
|
||||
import org.openhab.binding.wled.internal.api.ApiException;
|
||||
import org.openhab.binding.wled.internal.api.WledApi;
|
||||
import org.openhab.binding.wled.internal.api.WledApiFactory;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.library.types.IncreaseDecreaseType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
@@ -49,40 +42,67 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link WLedHandler} is responsible for handling commands and states, which are
|
||||
* sent to one of the channels or http replies back.
|
||||
* The {@link WLedSegmentHandler} is responsible for handling only a single segment from a WLED device.
|
||||
*
|
||||
* @author Matthew Skinner - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class WLedHandler extends BaseThingHandler {
|
||||
public class WLedSegmentHandler extends BaseThingHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
public final WledDynamicStateDescriptionProvider stateDescriptionProvider;
|
||||
private WledApiFactory apiFactory;
|
||||
private @Nullable WledApi api;
|
||||
private @Nullable ScheduledFuture<?> pollingFuture = null;
|
||||
private WLedSegmentConfiguration config = new WLedSegmentConfiguration();
|
||||
private BigDecimal masterBrightness255 = BigDecimal.ZERO;
|
||||
public boolean hasWhite = false;
|
||||
private HSBType primaryColor = new HSBType();
|
||||
private HSBType secondaryColor = new HSBType();
|
||||
private HSBType thirdColor = new HSBType();
|
||||
public WLedConfiguration config = new WLedConfiguration();
|
||||
|
||||
public WLedHandler(Thing thing, WledApiFactory apiFactory,
|
||||
WledDynamicStateDescriptionProvider stateDescriptionProvider) {
|
||||
public WLedSegmentHandler(Thing thing) {
|
||||
super(thing);
|
||||
this.apiFactory = apiFactory;
|
||||
this.stateDescriptionProvider = stateDescriptionProvider;
|
||||
}
|
||||
|
||||
public void update(String channelID, State state) {
|
||||
updateState(channelID, state);
|
||||
}
|
||||
|
||||
private void removeWhiteChannels() {
|
||||
List<Channel> removeChannels = new ArrayList<>();
|
||||
Channel channel = getThing().getChannel(CHANNEL_PRIMARY_WHITE);
|
||||
if (channel != null) {
|
||||
removeChannels.add(channel);
|
||||
}
|
||||
channel = getThing().getChannel(CHANNEL_SECONDARY_WHITE);
|
||||
if (channel != null) {
|
||||
removeChannels.add(channel);
|
||||
}
|
||||
channel = getThing().getChannel(CHANNEL_THIRD_WHITE);
|
||||
if (channel != null) {
|
||||
removeChannels.add(channel);
|
||||
}
|
||||
removeChannels(removeChannels);
|
||||
}
|
||||
|
||||
private void removeChannels(List<Channel> removeChannels) {
|
||||
if (!removeChannels.isEmpty()) {
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
thingBuilder.withoutChannels(removeChannels);
|
||||
updateThing(thingBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
WledApi localApi = api;
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge == null) {
|
||||
return;
|
||||
}
|
||||
WLedBridgeHandler bridgeHandler = (WLedBridgeHandler) bridge.getHandler();
|
||||
if (bridgeHandler == null) {
|
||||
return;
|
||||
}
|
||||
WledApi localApi = bridgeHandler.api;
|
||||
if (localApi == null) {
|
||||
return;
|
||||
}
|
||||
BigDecimal bigTemp;
|
||||
if (command instanceof RefreshType) {
|
||||
return;// no need to check for refresh below
|
||||
}
|
||||
@@ -103,9 +123,6 @@ public class WLedHandler extends BaseThingHandler {
|
||||
case CHANNEL_MIRROR:
|
||||
localApi.setMirror(OnOffType.ON.equals(command), config.segmentIndex);
|
||||
break;
|
||||
case CHANNEL_LIVE_OVERRIDE:
|
||||
localApi.setLiveOverride(command.toString());
|
||||
break;
|
||||
case CHANNEL_SPACING:
|
||||
if (command instanceof DecimalType) {
|
||||
localApi.setSpacing(((DecimalType) command).intValue(), config.segmentIndex);
|
||||
@@ -119,12 +136,6 @@ public class WLedHandler extends BaseThingHandler {
|
||||
case CHANNEL_REVERSE:
|
||||
localApi.setReverse(OnOffType.ON.equals(command), config.segmentIndex);
|
||||
break;
|
||||
case CHANNEL_SYNC_SEND:
|
||||
localApi.setUdpSend(OnOffType.ON.equals(command));
|
||||
break;
|
||||
case CHANNEL_SYNC_RECEIVE:
|
||||
localApi.setUdpRecieve(OnOffType.ON.equals(command));
|
||||
break;
|
||||
case CHANNEL_PRIMARY_WHITE:
|
||||
if (command instanceof PercentType) {
|
||||
localApi.sendGetRequest(
|
||||
@@ -165,10 +176,11 @@ public class WLedHandler extends BaseThingHandler {
|
||||
}
|
||||
localApi.setGlobalOn(true);
|
||||
primaryColor = (HSBType) command;
|
||||
if (primaryColor.getSaturation().intValue() < config.saturationThreshold && hasWhite) {
|
||||
if (primaryColor.getSaturation().intValue() < bridgeHandler.config.saturationThreshold
|
||||
&& bridgeHandler.hasWhite) {
|
||||
localApi.setWhiteOnly((PercentType) command, config.segmentIndex);
|
||||
} else if (primaryColor.getSaturation().intValue() == 32
|
||||
&& primaryColor.getHue().intValue() == 36 && hasWhite) {
|
||||
&& primaryColor.getHue().intValue() == 36 && bridgeHandler.hasWhite) {
|
||||
localApi.setWhiteOnly((PercentType) command, config.segmentIndex);
|
||||
} else {
|
||||
localApi.setMasterHSB((HSBType) command, config.segmentIndex);
|
||||
@@ -216,105 +228,38 @@ public class WLedHandler extends BaseThingHandler {
|
||||
case CHANNEL_INTENSITY:
|
||||
localApi.setFxIntencity((PercentType) command, config.segmentIndex);
|
||||
break;
|
||||
case CHANNEL_SLEEP:
|
||||
localApi.setSleep(OnOffType.ON.equals(command));
|
||||
break;
|
||||
case CHANNEL_PLAYLISTS:
|
||||
case CHANNEL_PRESETS:
|
||||
localApi.setPreset(command.toString());
|
||||
break;
|
||||
case CHANNEL_PRESET_DURATION:// ch removed in firmware 0.13.0 and newer
|
||||
if (command instanceof QuantityType) {
|
||||
QuantityType<?> seconds = ((QuantityType<?>) command).toUnit(Units.SECOND);
|
||||
if (seconds != null) {
|
||||
bigTemp = new BigDecimal(seconds.intValue()).multiply(new BigDecimal(1000));
|
||||
localApi.sendGetRequest("/win&PT=" + bigTemp.intValue());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_TRANS_TIME:
|
||||
if (command instanceof QuantityType) {
|
||||
QuantityType<?> seconds = ((QuantityType<?>) command).toUnit(Units.SECOND);
|
||||
if (seconds != null) {
|
||||
localApi.setTransitionTime(new BigDecimal(seconds.multiply(BigDecimal.TEN).intValue()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_PRESET_CYCLE: // ch removed in firmware 0.13.0 and newer
|
||||
if (command instanceof OnOffType) {
|
||||
localApi.setPresetCycle(OnOffType.ON.equals(command));
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (ApiException e) {
|
||||
logger.debug("Exception occured:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void savePreset(int position, String presetName) {
|
||||
try {
|
||||
if (api != null) {
|
||||
api.savePreset(position, presetName);
|
||||
}
|
||||
} catch (ApiException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void removeChannels(ArrayList<Channel> removeChannels) {
|
||||
if (!removeChannels.isEmpty()) {
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
thingBuilder.withoutChannels(removeChannels);
|
||||
updateThing(thingBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
public void update(String channelID, State state) {
|
||||
updateState(channelID, state);
|
||||
}
|
||||
|
||||
private void pollState() {
|
||||
WledApi localApi = api;
|
||||
try {
|
||||
if (localApi == null) {
|
||||
api = apiFactory.getApi(this);
|
||||
api.initialize();
|
||||
}
|
||||
if (localApi == null) {
|
||||
return;
|
||||
}
|
||||
localApi.update();
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} catch (ApiException e) {
|
||||
api = null;// Firmware may be updated so need to check next connect
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
config = getConfigAs(WLedConfiguration.class);
|
||||
if (config.segmentIndex < 0) {
|
||||
config.segmentIndex = 0;
|
||||
config = getConfigAs(WLedSegmentConfiguration.class);
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No bridge is selected.");
|
||||
} else {
|
||||
WLedBridgeHandler localBridgeHandler = (WLedBridgeHandler) bridge.getHandler();
|
||||
if (localBridgeHandler == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
|
||||
return;
|
||||
}
|
||||
WledApi localAPI = localBridgeHandler.api;
|
||||
if (localAPI != null) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
localBridgeHandler.stateDescriptionProvider
|
||||
.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_FX), localAPI.getUpdatedFxList());
|
||||
localBridgeHandler.stateDescriptionProvider.setStateOptions(
|
||||
new ChannelUID(getThing().getUID(), CHANNEL_PALETTES), localAPI.getUpdatedPaletteList());
|
||||
if (!localBridgeHandler.hasWhite) {
|
||||
logger.debug("WLED is not setup to use RGBW, so removing un-needed white channels");
|
||||
removeWhiteChannels();
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
|
||||
}
|
||||
}
|
||||
if (!config.address.contains("://")) {
|
||||
logger.debug("Address was not entered in correct format, it may be the raw IP so adding http:// to start");
|
||||
config.address = "http://" + config.address;
|
||||
}
|
||||
pollingFuture = scheduler.scheduleWithFixedDelay(this::pollState, 0, config.pollTime, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
Future<?> future = pollingFuture;
|
||||
if (future != null) {
|
||||
future.cancel(true);
|
||||
pollingFuture = null;
|
||||
}
|
||||
api = null; // re-initialize api after configuration change
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Collections.singleton(WLedActions.class);
|
||||
}
|
||||
}
|
||||
@@ -5,24 +5,32 @@ binding.wled.description = This is the binding for WLED
|
||||
|
||||
# thing types
|
||||
|
||||
thing-type.wled.wled.label = WLED String
|
||||
thing-type.wled.wled.description = A WLED string of LEDs
|
||||
thing-type.wled.json.label = WLED via JSON API
|
||||
thing-type.wled.json.description = A connection to a WLED device controlled via the JSON API.
|
||||
thing-type.wled.segment.label = WLED Segment
|
||||
thing-type.wled.segment.description = Controls an entire LED strip, or a section of the strip if the LED string is split into multiple segments.
|
||||
|
||||
# thing types config
|
||||
|
||||
thing-type.config.wled.wled.address.label = Address
|
||||
thing-type.config.wled.wled.address.description = Use this format http://192.168.1.2:80
|
||||
thing-type.config.wled.wled.pollTime.label = Poll States
|
||||
thing-type.config.wled.wled.pollTime.description = Time in seconds of how often to fetch the state of the LEDs.
|
||||
thing-type.config.wled.wled.saturationThreshold.label = Saturation Threshold
|
||||
thing-type.config.wled.wled.saturationThreshold.description = This feature allows you to specify a number that if the saturation drops below, will trigger white.
|
||||
thing-type.config.wled.wled.segmentIndex.label = Segment Index
|
||||
thing-type.config.wled.wled.segmentIndex.description = Leave this as 0 if you are not using segments, otherwise set this to the segment index number that you wish to control.
|
||||
thing-type.config.wled.json.address.label = Address
|
||||
thing-type.config.wled.json.address.description = Use this format http://192.168.1.2:80
|
||||
thing-type.config.wled.json.pollTime.label = Poll Time
|
||||
thing-type.config.wled.json.pollTime.description = Time in seconds of how often to fetch the state of the LEDs.
|
||||
thing-type.config.wled.json.saturationThreshold.label = Saturation Threshold
|
||||
thing-type.config.wled.json.saturationThreshold.description = This feature allows you to specify a number that if the saturation drops below, will trigger white.
|
||||
thing-type.config.wled.json.sortEffects.label = Sort Effects
|
||||
thing-type.config.wled.json.sortEffects.description = If set, will sort the state options of the effects channel alphabetically while keeping the first option (Solid) at the top.
|
||||
thing-type.config.wled.json.sortPalettes.label = Sort Palettes
|
||||
thing-type.config.wled.json.sortPalettes.description = If set, will sort the state options of the palettes channel alphabetically while keeping the first option (Default) at the top.
|
||||
thing-type.config.wled.segment.segmentIndex.label = Segment Index
|
||||
thing-type.config.wled.segment.segmentIndex.description = Leave this as 0 if you are not using multiple segments, otherwise set this to the segment index number that you wish to control.
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.wled.fx.label = Effect
|
||||
channel-type.wled.fx.description = Use the built in FX
|
||||
channel-type.wled.globalBrightness.label = Global Brightness
|
||||
channel-type.wled.globalBrightness.description = Allows you to fade and turn all segments ON and OFF at the same time
|
||||
channel-type.wled.grouping.label = Grouping
|
||||
channel-type.wled.grouping.description = How many consecutive LEDs of the same segment will be grouped to the same color
|
||||
channel-type.wled.intensity.label = FX Intensity
|
||||
@@ -46,22 +54,6 @@ channel-type.wled.presetDuration.label = Preset Duration
|
||||
channel-type.wled.presetDuration.description = Time for how long to show each preset for before moving to the next
|
||||
channel-type.wled.presets.label = Presets
|
||||
channel-type.wled.presets.description = Auto rotate or change to a saved preset
|
||||
channel-type.wled.presets.state.option.1 = Preset 1
|
||||
channel-type.wled.presets.state.option.2 = Preset 2
|
||||
channel-type.wled.presets.state.option.3 = Preset 3
|
||||
channel-type.wled.presets.state.option.4 = Preset 4
|
||||
channel-type.wled.presets.state.option.5 = Preset 5
|
||||
channel-type.wled.presets.state.option.6 = Preset 6
|
||||
channel-type.wled.presets.state.option.7 = Preset 7
|
||||
channel-type.wled.presets.state.option.8 = Preset 8
|
||||
channel-type.wled.presets.state.option.9 = Preset 9
|
||||
channel-type.wled.presets.state.option.10 = Preset 10
|
||||
channel-type.wled.presets.state.option.11 = Preset 11
|
||||
channel-type.wled.presets.state.option.12 = Preset 12
|
||||
channel-type.wled.presets.state.option.13 = Preset 13
|
||||
channel-type.wled.presets.state.option.14 = Preset 14
|
||||
channel-type.wled.presets.state.option.15 = Preset 15
|
||||
channel-type.wled.presets.state.option.16 = Preset 16
|
||||
channel-type.wled.primaryColor.label = Primary Color
|
||||
channel-type.wled.primaryColor.description = Allows you to change the primary color used in FX
|
||||
channel-type.wled.primaryWhite.label = Primary White
|
||||
@@ -76,6 +68,30 @@ channel-type.wled.segmentBrightness.label = Segment Brightness
|
||||
channel-type.wled.segmentBrightness.description = Changes the brightness of the whole segment
|
||||
channel-type.wled.sleep.label = Sleep Timer
|
||||
channel-type.wled.sleep.description = Fade the level of light and turn off after set time
|
||||
channel-type.wled.sleepDuration.label = Sleep Duration
|
||||
channel-type.wled.sleepDuration.description = Time it takes to change/fade to the target brightness.
|
||||
channel-type.wled.sleepDuration.state.option.1min = 1 Minute
|
||||
channel-type.wled.sleepDuration.state.option.5min = 5 Minutes
|
||||
channel-type.wled.sleepDuration.state.option.10min = 10 Minutes
|
||||
channel-type.wled.sleepDuration.state.option.15min = 15 Minutes
|
||||
channel-type.wled.sleepDuration.state.option.20min = 20 Minutes
|
||||
channel-type.wled.sleepDuration.state.option.25min = 25 Minutes
|
||||
channel-type.wled.sleepDuration.state.option.30min = 30 Minutes
|
||||
channel-type.wled.sleepDuration.state.option.40min = 40 Minutes
|
||||
channel-type.wled.sleepDuration.state.option.50min = 50 Minutes
|
||||
channel-type.wled.sleepDuration.state.option.60min = 1 Hour
|
||||
channel-type.wled.sleepDuration.state.option.90min = 1.5 Hours
|
||||
channel-type.wled.sleepDuration.state.option.120min = 2 Hours
|
||||
channel-type.wled.sleepDuration.state.option.150min = 2.5 Hours
|
||||
channel-type.wled.sleepDuration.state.option.240min = 4 Hours
|
||||
channel-type.wled.sleepMode.label = Sleep Mode
|
||||
channel-type.wled.sleepMode.description = Timed Light Mode selects how the light will fade or increase when the sleep timer is turned ON.
|
||||
channel-type.wled.sleepMode.state.option.0 = Instant
|
||||
channel-type.wled.sleepMode.state.option.1 = Fade
|
||||
channel-type.wled.sleepMode.state.option.2 = Color Fade
|
||||
channel-type.wled.sleepMode.state.option.3 = Sunrise
|
||||
channel-type.wled.sleepTargetBrightness.label = Sleep Target Brightness
|
||||
channel-type.wled.sleepTargetBrightness.description = Sets how bright the light will be after the sleep duration time has expired.
|
||||
channel-type.wled.spacing.label = Spacing
|
||||
channel-type.wled.spacing.description = How many LEDs are turned off and skipped between each group
|
||||
channel-type.wled.speed.label = FX Speed
|
||||
@@ -90,3 +106,16 @@ channel-type.wled.tertiaryWhite.label = Tertiary White
|
||||
channel-type.wled.tertiaryWhite.description = Changes the brightness of the third white LED
|
||||
channel-type.wled.transformTime.label = Transform Time
|
||||
channel-type.wled.transformTime.description = Time it takes to change/fade from one look to the next.
|
||||
channel-type.wled.transformTime.state.option.0s = 0 Seconds
|
||||
channel-type.wled.transformTime.state.option.0.3s = 0.3 Seconds
|
||||
channel-type.wled.transformTime.state.option.0.7s = 0.7 Seconds
|
||||
channel-type.wled.transformTime.state.option.1s = 1 Second
|
||||
channel-type.wled.transformTime.state.option.2s = 2 Seconds
|
||||
channel-type.wled.transformTime.state.option.3s = 3 Seconds
|
||||
channel-type.wled.transformTime.state.option.4s = 4 Seconds
|
||||
channel-type.wled.transformTime.state.option.5s = 5 Seconds
|
||||
channel-type.wled.transformTime.state.option.6s = 6 Seconds
|
||||
channel-type.wled.transformTime.state.option.7s = 7 Seconds
|
||||
channel-type.wled.transformTime.state.option.8s = 8 Seconds
|
||||
channel-type.wled.transformTime.state.option.9s = 9 Seconds
|
||||
channel-type.wled.transformTime.state.option.10s = 10 Seconds
|
||||
|
||||
@@ -4,9 +4,65 @@
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<thing-type id="wled">
|
||||
<label>WLED String</label>
|
||||
<description>A WLED string of LEDs</description>
|
||||
<bridge-type id="json">
|
||||
<label>WLED via JSON API</label>
|
||||
<description>A connection to a WLED device controlled via the JSON API.</description>
|
||||
<channels>
|
||||
<channel id="globalBrightness" typeId="globalBrightness"/>
|
||||
<channel id="playlists" typeId="playlists"/>
|
||||
<channel id="presets" typeId="presets"/>
|
||||
<channel id="presetDuration" typeId="presetDuration"/>
|
||||
<channel id="transformTime" typeId="transformTime"/>
|
||||
<channel id="presetCycle" typeId="presetCycle"/>
|
||||
<channel id="liveOverride" typeId="liveOverride"/>
|
||||
<channel id="sleep" typeId="sleep"/>
|
||||
<channel id="sleepMode" typeId="sleepMode"/>
|
||||
<channel id="sleepDuration" typeId="sleepDuration"/>
|
||||
<channel id="sleepTargetBrightness" typeId="sleepTargetBrightness"/>
|
||||
<channel id="syncSend" typeId="syncSend"/>
|
||||
<channel id="syncReceive" typeId="syncReceive"/>
|
||||
</channels>
|
||||
<config-description>
|
||||
<parameter name="address" type="text" required="true">
|
||||
<label>Address</label>
|
||||
<description>Use this format http://192.168.1.2:80</description>
|
||||
</parameter>
|
||||
<parameter name="pollTime" type="integer" min="1" unit="s">
|
||||
<label>Poll Time</label>
|
||||
<description>Time in seconds of how often to fetch the state of the LEDs.</description>
|
||||
<default>5</default>
|
||||
</parameter>
|
||||
<parameter name="saturationThreshold" type="integer" min="0" max="99">
|
||||
<label>Saturation Threshold</label>
|
||||
<description>This feature allows you to specify a number that if the saturation drops below, will trigger white.
|
||||
</description>
|
||||
<advanced>true</advanced>
|
||||
<default>0</default>
|
||||
</parameter>
|
||||
<parameter name="sortEffects" type="boolean">
|
||||
<label>Sort Effects</label>
|
||||
<description>If set, will sort the state options of the effects channel alphabetically while keeping the first
|
||||
option (Solid) at the top.</description>
|
||||
<advanced>true</advanced>
|
||||
<default>true</default>
|
||||
</parameter>
|
||||
<parameter name="sortPalettes" type="boolean">
|
||||
<label>Sort Palettes</label>
|
||||
<description>If set, will sort the state options of the palettes channel alphabetically while keeping the first
|
||||
option (Default) at the top.</description>
|
||||
<advanced>true</advanced>
|
||||
<default>true</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
|
||||
<thing-type id="segment">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="json"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>WLED Segment</label>
|
||||
<description>Controls an entire LED strip, or a section of the strip if the LED string is split into multiple
|
||||
segments.</description>
|
||||
<category>ColorLight</category>
|
||||
<channels>
|
||||
<channel id="masterControls" typeId="masterControls"/>
|
||||
@@ -17,11 +73,6 @@
|
||||
<channel id="secondaryWhite" typeId="secondaryWhite"/>
|
||||
<channel id="tertiaryColor" typeId="tertiaryColor"/>
|
||||
<channel id="tertiaryWhite" typeId="tertiaryWhite"/>
|
||||
<channel id="presets" typeId="presets"/>
|
||||
<channel id="playlists" typeId="playlists"/>
|
||||
<channel id="presetDuration" typeId="presetDuration"/>
|
||||
<channel id="transformTime" typeId="transformTime"/>
|
||||
<channel id="presetCycle" typeId="presetCycle"/>
|
||||
<channel id="palettes" typeId="palettes"/>
|
||||
<channel id="fx" typeId="fx"/>
|
||||
<channel id="speed" typeId="speed"/>
|
||||
@@ -30,48 +81,24 @@
|
||||
<channel id="reverse" typeId="reverse"/>
|
||||
<channel id="grouping" typeId="grouping"/>
|
||||
<channel id="spacing" typeId="spacing"/>
|
||||
<channel id="liveOverride" typeId="liveOverride"/>
|
||||
<channel id="sleep" typeId="sleep"/>
|
||||
<channel id="syncSend" typeId="syncSend"/>
|
||||
<channel id="syncReceive" typeId="syncReceive"/>
|
||||
</channels>
|
||||
<config-description>
|
||||
<parameter name="address" type="text" required="true">
|
||||
<label>Address</label>
|
||||
<description>Use this format http://192.168.1.2:80</description>
|
||||
</parameter>
|
||||
<parameter name="pollTime" type="integer" required="true" min="1" unit="s">
|
||||
<label>Poll States</label>
|
||||
<description>Time in seconds of how often to fetch the state of the LEDs.</description>
|
||||
<default>10</default>
|
||||
</parameter>
|
||||
<parameter name="segmentIndex" type="integer" required="true" min="0">
|
||||
<parameter name="segmentIndex" type="integer" min="0">
|
||||
<label>Segment Index</label>
|
||||
<description>Leave this as 0 if you are not using segments, otherwise set this to the segment index number that you
|
||||
wish to control.</description>
|
||||
<description>Leave this as 0 if you are not using multiple segments, otherwise set this to the segment index number
|
||||
that you wish to control.</description>
|
||||
<default>0</default>
|
||||
</parameter>
|
||||
<parameter name="saturationThreshold" type="integer" required="true" min="0" max="99">
|
||||
<label>Saturation Threshold</label>
|
||||
<description>This feature allows you to specify a number that if the saturation drops below, will trigger white.
|
||||
</description>
|
||||
<default>0</default>
|
||||
</parameter>
|
||||
<parameter name="sortEffects" type="boolean">
|
||||
<label>Sort Effects</label>
|
||||
<description>If set, will sort the state options of the effects channel alphabetically while keeping the first
|
||||
option (Solid) at the top.</description>
|
||||
<default>false</default>
|
||||
</parameter>
|
||||
<parameter name="sortPalettes" type="boolean">
|
||||
<label>Sort Palettes</label>
|
||||
<description>If set, will sort the state options of the palettes channel alphabetically while keeping the first
|
||||
option (Default) at the top.</description>
|
||||
<default>false</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="globalBrightness">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Global Brightness</label>
|
||||
<description>Allows you to fade and turn all segments ON and OFF at the same time</description>
|
||||
<category>ColorLight</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="masterControls">
|
||||
<item-type>Color</item-type>
|
||||
<label>Master Controls</label>
|
||||
@@ -83,11 +110,11 @@
|
||||
</tags>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="segmentBrightness" advanced="true">
|
||||
<channel-type id="segmentBrightness">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Segment Brightness</label>
|
||||
<description>Changes the brightness of the whole segment</description>
|
||||
<category>Light</category>
|
||||
<category>ColorLight</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="primaryColor" advanced="true">
|
||||
@@ -101,7 +128,7 @@
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Primary White</label>
|
||||
<description>Changes the brightness of the primary white LED</description>
|
||||
<category>Light</category>
|
||||
<category>ColorLight</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="secondaryColor" advanced="true">
|
||||
@@ -115,7 +142,7 @@
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Secondary White</label>
|
||||
<description>Changes the brightness of the secondary white LED</description>
|
||||
<category>Light</category>
|
||||
<category>ColorLight</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="tertiaryColor" advanced="true">
|
||||
@@ -129,7 +156,7 @@
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Tertiary White</label>
|
||||
<description>Changes the brightness of the third white LED</description>
|
||||
<category>Light</category>
|
||||
<category>ColorLight</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="palettes">
|
||||
@@ -148,26 +175,6 @@
|
||||
<item-type>String</item-type>
|
||||
<label>Presets</label>
|
||||
<description>Auto rotate or change to a saved preset</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="1">Preset 1</option>
|
||||
<option value="2">Preset 2</option>
|
||||
<option value="3">Preset 3</option>
|
||||
<option value="4">Preset 4</option>
|
||||
<option value="5">Preset 5</option>
|
||||
<option value="6">Preset 6</option>
|
||||
<option value="7">Preset 7</option>
|
||||
<option value="8">Preset 8</option>
|
||||
<option value="9">Preset 9</option>
|
||||
<option value="10">Preset 10</option>
|
||||
<option value="11">Preset 11</option>
|
||||
<option value="12">Preset 12</option>
|
||||
<option value="13">Preset 13</option>
|
||||
<option value="14">Preset 14</option>
|
||||
<option value="15">Preset 15</option>
|
||||
<option value="16">Preset 16</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="playlists">
|
||||
@@ -218,19 +225,19 @@
|
||||
<category>Time</category>
|
||||
<state>
|
||||
<options>
|
||||
<option value="0 s"/>
|
||||
<option value="0.3 s"/>
|
||||
<option value="0.7 s"/>
|
||||
<option value="1 s"/>
|
||||
<option value="2 s"/>
|
||||
<option value="3 s"/>
|
||||
<option value="4 s"/>
|
||||
<option value="5 s"/>
|
||||
<option value="6 s"/>
|
||||
<option value="7 s"/>
|
||||
<option value="8 s"/>
|
||||
<option value="9 s"/>
|
||||
<option value="10 s"/>
|
||||
<option value="0s">0 Seconds</option>
|
||||
<option value="0.3s">0.3 Seconds</option>
|
||||
<option value="0.7s">0.7 Seconds</option>
|
||||
<option value="1s">1 Second</option>
|
||||
<option value="2s">2 Seconds</option>
|
||||
<option value="3s">3 Seconds</option>
|
||||
<option value="4s">4 Seconds</option>
|
||||
<option value="5s">5 Seconds</option>
|
||||
<option value="6s">6 Seconds</option>
|
||||
<option value="7s">7 Seconds</option>
|
||||
<option value="8s">8 Seconds</option>
|
||||
<option value="9s">9 Seconds</option>
|
||||
<option value="10s">10 Seconds</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
@@ -266,6 +273,51 @@
|
||||
<category>Time</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sleepMode" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Sleep Mode</label>
|
||||
<description>Timed Light Mode selects how the light will fade or increase when the sleep timer is turned ON.</description>
|
||||
<state readOnly="false">
|
||||
<options>
|
||||
<option value="0">Instant</option>
|
||||
<option value="1">Fade</option>
|
||||
<option value="2">Color Fade</option>
|
||||
<option value="3">Sunrise</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sleepDuration" advanced="true">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Sleep Duration</label>
|
||||
<description>Time it takes to change/fade to the target brightness.</description>
|
||||
<category>Time</category>
|
||||
<state min="1" max="255" step="1" readOnly="false">
|
||||
<options>
|
||||
<option value="1min">1 Minute</option>
|
||||
<option value="5min">5 Minutes</option>
|
||||
<option value="10min">10 Minutes</option>
|
||||
<option value="15min">15 Minutes</option>
|
||||
<option value="20min">20 Minutes</option>
|
||||
<option value="25min">25 Minutes</option>
|
||||
<option value="30min">30 Minutes</option>
|
||||
<option value="40min">40 Minutes</option>
|
||||
<option value="50min">50 Minutes</option>
|
||||
<option value="60min">1 Hour</option>
|
||||
<option value="90min">1.5 Hours</option>
|
||||
<option value="120min">2 Hours</option>
|
||||
<option value="150min">2.5 Hours</option>
|
||||
<option value="240min">4 Hours</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sleepTargetBrightness" advanced="true">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Sleep Target Brightness</label>
|
||||
<description>Sets how bright the light will be after the sleep duration time has expired.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="presetCycle" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Preset Cycle</label>
|
||||
|
||||
Reference in New Issue
Block a user