diff --git a/CODEOWNERS b/CODEOWNERS
index 98c606c95fb..d056887e994 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -267,6 +267,7 @@
/bundles/org.openhab.binding.wifiled/ @rvt @xylo
/bundles/org.openhab.binding.windcentrale/ @marcelrv
/bundles/org.openhab.binding.wlanthermo/ @CSchlipp
+/bundles/org.openhab.binding.wled/ @Skinah
/bundles/org.openhab.binding.xmltv/ @clinique
/bundles/org.openhab.binding.xmppclient/ @pavel-gololobov
/bundles/org.openhab.binding.yamahareceiver/ @davidgraeff @zarusz
diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml
index c6579d85a33..fc0b0d2c432 100644
--- a/bom/openhab-addons/pom.xml
+++ b/bom/openhab-addons/pom.xml
@@ -1321,6 +1321,11 @@
org.openhab.binding.wlanthermo${project.version}
+
+ org.openhab.addons.bundles
+ org.openhab.binding.wled
+ ${project.version}
+ org.openhab.addons.bundlesorg.openhab.binding.xmltv
diff --git a/bundles/org.openhab.binding.wled/NOTICE b/bundles/org.openhab.binding.wled/NOTICE
new file mode 100644
index 00000000000..38d625e3492
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/NOTICE
@@ -0,0 +1,13 @@
+This content is produced and maintained by the openHAB project.
+
+* Project home: https://www.openhab.org
+
+== Declared Project Licenses
+
+This program and the accompanying materials are made available under the terms
+of the Eclipse Public License 2.0 which is available at
+https://www.eclipse.org/legal/epl-2.0/.
+
+== Source Code
+
+https://github.com/openhab/openhab-addons
diff --git a/bundles/org.openhab.binding.wled/README.md b/bundles/org.openhab.binding.wled/README.md
new file mode 100644
index 00000000000..0f8f159f7bb
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/README.md
@@ -0,0 +1,86 @@
+# WLED Binding
+
+This binding allows you to auto discover and use LED strings based on the WLED project:
+
+
+## Supported Things
+
+| Thing Type ID | Description |
+|-|-|
+| `wled` | Use this for RGB and RGBW strings. |
+
+## Discovery
+
+The auto discovery will find your WLED if your network supports mDNS and the UDP port 5353 is not blocked by a fire wall.
+Before discovering any WLED devices, you may wish to name them by providing a 'Server description' in the WLED web page, CONFIG>User Interface> setup page.
+openHAB will then discover and auto name your WLED to the name provided as the 'Server description'.
+If it fails to find your WLED, you can still manually add a `wled` thing by using the UI or textual methods.
+For multiple segments, the binding will only auto find the first segment.
+For additional segments, you can add them manually and set the `segmentIndex` config to the correct number shown in the WLED control web page.
+
+## Thing Configuration
+
+| Parameter | Description | Required | Default |
+|-|-|-|-|
+| `address`| The full URL to your WLED device. Example is `http://192.168.0.2:80` | Y | |
+| `pollTime`| How often in seconds you want the states of the LED fetched in case you make changes with a non openHAB app, web browser, or the light is auto changing FX or presets. | Y | 10 |
+| `segmentIndex` | The index number to the LED segment you wish these channels to control. Leave on -1 if you do not know what a segment is. | Y | -1 |
+| `saturationThreshold` | Allows you to use a colorpicker control linked to the `masterControls` channel to trigger only using the pure white LEDs instead of creating fake white light from the RGB channels. Try setting the value to 12 or leave this on 0 for RGB strings. | Y | 0 |
+
+## Channels
+
+| Channel | Type | Description |
+|-|-|-|
+| `masterControls` | Color | Gives you control over the WLED like it is any normal light. Tag this control for Alexa or Google/Nest to change the lights instantly to any colour, brightness or on/off state that you ask for regardless of what mode the light is in. |
+| `primaryColor` | Color | The primary colour used in FX. |
+| `primaryWhite` | Dimmer | The amount of white light used in the primary colour if you have RGBW LEDs. |
+| `secondaryColor` | Color | The secondary colour used in FX. |
+| `secondaryWhite` | Dimmer | The amount of white light used in the secondary colour if you have RGBW LEDs. |
+| `palettes` | String | A list of colour palettes you can select from that are used in the FX. |
+| `fx` | String | A list of Effects you can select from. |
+| `speed` | Dimmer | Changes the speed of the loaded effect. |
+| `intensity` | Dimmer | Changes the intensity of the loaded effect. |
+| `presets` | String | A list of presets that you can select from. |
+| `presetCycle` | Switch | Turns ON/OFF the automatic changing from one preset to the next. |
+| `presetDuration` | Number:Time | How long in seconds it will display a preset for, before it begins to change from one preset to the next with `presetCycle` turned ON. |
+| `transformTime` | Number:Time | How long in seconds it takes to transform/morph from one look to the next. |
+| `sleep` | Switch | Turns on the sleep or 'night light' timer which can be configured to work in many different ways. Refer to WLED documentation for how this can be setup. The default action is the light will fade to OFF over the next 60 minutes. |
+| `syncSend` | Switch | Sends UDP packets that tell other WLED lights to follow this one. |
+| `syncReceive` | Switch | Allows UDP packets from other WLED lights to control this one. |
+
+## Rule Actions
+
+This binding has a rule Action `savePreset(int presetNumber)` which can save the current state of the WLED string into a preset slot that you can specify.
+Currently 1 to 16 are valid preset slots.
+
+In Xtend rules, you can use the Actions like this.
+
+```
+getActions("wled", "wled:wled:XmasTree").savePreset(5)
+```
+
+## Sitemap Example
+
+If you use the ADMIN>MODEL>`Create equipment from thing` feature you can use the below and just change the name before the underscore to match what you named the `wled` thing when it was added via the Inbox.
+
+*.sitemap
+
+```
+ Text label="XmasLights" icon="rgb"{
+ Switch item=XmasTree_MasterControls
+ Slider item=XmasTree_MasterControls
+ Colorpicker item=XmasTree_MasterControls
+ Switch item=XmasTree_SleepTimer
+ Colorpicker item=XmasTree_PrimaryColor
+ Colorpicker item=XmasTree_SecondaryColor
+ Selection item=XmasTree_Effect
+ Selection item=XmasTree_Palettes
+ Selection item=XmasTree_Presets
+ Default item=XmasTree_FXSpeed
+ Default item=XmasTree_FXIntensity
+ Default item=XmasTree_PresetCycle
+ Selection item=XmasTree_PresetDuration mappings=[2 ='2 seconds', 10='10 seconds', 30='30 seconds', 60='60 seconds']
+ Selection item=XmasTree_TransformTime mappings=[0='0 seconds', 2 ='2 seconds', 10='10 seconds', 30='30 seconds', 60='60 seconds']
+ }
+
+```
diff --git a/bundles/org.openhab.binding.wled/pom.xml b/bundles/org.openhab.binding.wled/pom.xml
new file mode 100644
index 00000000000..2ba1650742c
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/pom.xml
@@ -0,0 +1,17 @@
+
+
+
+ 4.0.0
+
+
+ org.openhab.addons.bundles
+ org.openhab.addons.reactor.bundles
+ 3.0.0-SNAPSHOT
+
+
+ org.openhab.binding.wled
+
+ openHAB Add-ons :: Bundles :: WLed Binding
+
+
diff --git a/bundles/org.openhab.binding.wled/src/main/feature/feature.xml b/bundles/org.openhab.binding.wled/src/main/feature/feature.xml
new file mode 100644
index 00000000000..bad17400543
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/src/main/feature/feature.xml
@@ -0,0 +1,8 @@
+
+
+ mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${project.version}/xml/features
+
+ openhab-runtime-base
+ mvn:org.openhab.addons.bundles/org.openhab.binding.wled/${project.version}
+
+
diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedActions.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedActions.java
new file mode 100644
index 00000000000..0c1460931fc
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedActions.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2010-2020 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;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.automation.annotation.ActionInput;
+import org.openhab.core.automation.annotation.RuleAction;
+import org.openhab.core.thing.binding.ThingActions;
+import org.openhab.core.thing.binding.ThingActionsScope;
+import org.openhab.core.thing.binding.ThingHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link WLedActions} is responsible for Actions.
+ *
+ * @author Matthew Skinner - Initial contribution
+ */
+
+@ThingActionsScope(name = "wled")
+@NonNullByDefault
+public class WLedActions implements ThingActions {
+ public final Logger logger = LoggerFactory.getLogger(getClass());
+ private @Nullable WLedHandler handler;
+
+ @Override
+ public void setThingHandler(@Nullable ThingHandler handler) {
+ this.handler = (WLedHandler) handler;
+ }
+
+ @Override
+ public @Nullable ThingHandler getThingHandler() {
+ return handler;
+ }
+
+ @RuleAction(label = "save state to preset", description = "Save a WLED state to a preset slot")
+ public void savePreset(
+ @ActionInput(name = "presetNumber", label = "Preset Slot", description = "Number for the preset slot you wish to use") int presetNumber) {
+ WLedHandler localHandler = handler;
+ if (presetNumber > 0 && localHandler != null) {
+ localHandler.savePreset(presetNumber);
+ }
+ }
+
+ public static void savePreset(@Nullable ThingActions actions, int presetNumber) {
+ if (actions instanceof WLedActions) {
+ ((WLedActions) actions).savePreset(presetNumber);
+ } else {
+ throw new IllegalArgumentException("Instance is not a WLED class.");
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedBindingConstants.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedBindingConstants.java
new file mode 100644
index 00000000000..757c8cc52cb
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedBindingConstants.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2010-2020 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 java.math.BigDecimal;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * The {@link WLedBindingConstants} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Matthew Skinner - Initial contribution
+ */
+@NonNullByDefault
+public class WLedBindingConstants {
+
+ public static final String BINDING_ID = "wled";
+ public static final BigDecimal BIG_DECIMAL_2_55 = new BigDecimal(2.55);
+
+ // List of all Thing Type UIDs
+ public static final ThingTypeUID THING_TYPE_WLED = new ThingTypeUID(BINDING_ID, "wled");
+ public static final Set SUPPORTED_THING_TYPES = Set.of(THING_TYPE_WLED);
+
+ // Configs
+ public static final String CONFIG_ADDRESS = "address";
+ public static final String CONFIG_POLL_TIME = "pollTime";
+ public static final String CONFIG_SEGMENT_INDEX = "segmentIndex";
+ public static final String CONFIG_SAT_THRESHOLD = "saturationThreshold";
+
+ // Channels
+ public static final String CHANNEL_MASTER_CONTROLS = "masterControls";
+ public static final String CHANNEL_PRIMARY_COLOR = "primaryColor";
+ public static final String CHANNEL_SECONDARY_COLOR = "secondaryColor";
+ public static final String CHANNEL_PRIMARY_WHITE = "primaryWhite";
+ public static final String CHANNEL_SECONDARY_WHITE = "secondaryWhite";
+ public static final String CHANNEL_PALETTES = "palettes";
+ public static final String CHANNEL_PRESETS = "presets";
+ public static final String CHANNEL_PRESET_DURATION = "presetDuration";
+ public static final String CHANNEL_TRANS_TIME = "transformTime";
+ public static final String CHANNEL_PRESET_CYCLE = "presetCycle";
+ public static final String CHANNEL_FX = "fx";
+ public static final String CHANNEL_SPEED = "speed";
+ public static final String CHANNEL_INTENSITY = "intensity";
+ public static final String CHANNEL_SLEEP = "sleep";
+ public static final String CHANNEL_SYNC_SEND = "syncSend";
+ public static final String CHANNEL_SYNC_RECEIVE = "syncReceive";
+}
diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedConfiguration.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedConfiguration.java
new file mode 100644
index 00000000000..e2f2c52094b
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedConfiguration.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2010-2020 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 WLedConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Matthew Skinner - Initial contribution
+ */
+@NonNullByDefault
+public class WLedConfiguration {
+ public String address = "";
+ public int pollTime;
+ public int segmentIndex;
+ public int saturationThreshold;
+}
diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedDiscoveryService.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedDiscoveryService.java
new file mode 100644
index 00000000000..2897bf514f5
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedDiscoveryService.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2010-2020 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.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import javax.jmdns.ServiceInfo;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpMethod;
+import org.openhab.core.config.discovery.DiscoveryResult;
+import org.openhab.core.config.discovery.DiscoveryResultBuilder;
+import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant;
+import org.openhab.core.io.net.http.HttpClientFactory;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.ThingUID;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link WLedDiscoveryService} Discovers and adds any Wled devices found.
+ *
+ * @author Matthew Skinner - Initial contribution
+ */
+@NonNullByDefault
+@Component(service = MDNSDiscoveryParticipant.class)
+public class WLedDiscoveryService implements MDNSDiscoveryParticipant {
+ private final Logger logger = LoggerFactory.getLogger(WLedDiscoveryService.class);
+ private final HttpClient httpClient;
+
+ @Activate
+ public WLedDiscoveryService(@Reference HttpClientFactory httpClientFactory) {
+ this.httpClient = httpClientFactory.getCommonHttpClient();
+ }
+
+ private String sendGetRequest(String address, String url) {
+ Request request = httpClient.newRequest(address + url);
+ request.timeout(3, TimeUnit.SECONDS);
+ request.method(HttpMethod.GET);
+ request.header(HttpHeader.ACCEPT_ENCODING, "gzip");
+ logger.trace("Sending WLED GET:{}", url);
+ try {
+ ContentResponse contentResponse = request.send();
+ if (contentResponse.getStatus() == 200) {
+ return contentResponse.getContentAsString();
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ } catch (TimeoutException | ExecutionException e) {
+ logger.debug(
+ "WLED discovery hit a TimeoutException | ExecutionException which may have blocked a device from getting discovered:{}",
+ e.getMessage());
+ }
+ return "";
+ }
+
+ @Override
+ public @Nullable DiscoveryResult createResult(ServiceInfo service) {
+ String name = service.getName().toLowerCase();
+ if (!name.contains("wled")) {
+ return null;
+ }
+ String address[] = service.getURLs();
+ if ((address == null) || address.length < 1) {
+ logger.debug("WLED discovered with empty IP address-{}", service);
+ return null;
+ }
+ String response = sendGetRequest(address[0], "/json");
+ // LinkedList 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 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, -1).withLabel(label).withProperties(properties)
+ .withRepresentationProperty(Thing.PROPERTY_MAC_ADDRESS).build();
+ }
+
+ @Override
+ public @Nullable ThingUID getThingUID(ServiceInfo service) {
+ return null;
+ }
+
+ @Override
+ public Set getSupportedThingTypeUIDs() {
+ return SUPPORTED_THING_TYPES;
+ }
+
+ @Override
+ public String getServiceType() {
+ return "_http._tcp.local.";
+ }
+}
diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java
new file mode 100644
index 00000000000..9d6253ef6f7
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java
@@ -0,0 +1,451 @@
+/**
+ * Copyright (c) 2010-2020 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.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpMethod;
+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.types.StringType;
+import org.openhab.core.library.unit.SmartHomeUnits;
+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.types.Command;
+import org.openhab.core.types.RefreshType;
+import org.openhab.core.types.State;
+import org.openhab.core.types.StateOption;
+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.
+ *
+ * @author Matthew Skinner - Initial contribution
+ */
+
+@NonNullByDefault
+public class WLedHandler extends BaseThingHandler {
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+ private final HttpClient httpClient;
+ private final WledDynamicStateDescriptionProvider stateDescriptionProvider;
+ private @Nullable ScheduledFuture> pollingFuture = null;
+ private BigDecimal masterBrightness255 = BigDecimal.ZERO;
+ private HSBType primaryColor = new HSBType();
+ private BigDecimal primaryWhite = BigDecimal.ZERO;
+ private HSBType secondaryColor = new HSBType();
+ private BigDecimal secondaryWhite = BigDecimal.ZERO;
+ private boolean hasWhite = false;
+ private WLedConfiguration config = new WLedConfiguration();
+
+ public WLedHandler(Thing thing, HttpClient httpClient,
+ WledDynamicStateDescriptionProvider stateDescriptionProvider) {
+ super(thing);
+ this.httpClient = httpClient;
+ this.stateDescriptionProvider = stateDescriptionProvider;
+ }
+
+ private void sendGetRequest(String url) {
+ Request request;
+ if (url.contains("json") || config.segmentIndex == -1) {
+ request = httpClient.newRequest(config.address + url);
+ } else {
+ request = httpClient.newRequest(config.address + url + "&SM=" + config.segmentIndex);
+ }
+ request.timeout(3, TimeUnit.SECONDS);
+ request.method(HttpMethod.GET);
+ request.header(HttpHeader.ACCEPT_ENCODING, "gzip");
+ logger.trace("Sending WLED GET:{}", url);
+ String errorReason = "";
+ try {
+ ContentResponse contentResponse = request.send();
+ if (contentResponse.getStatus() == 200) {
+ processState(contentResponse.getContentAsString());
+ return;
+ } else {
+ errorReason = String.format("WLED request failed with %d: %s", contentResponse.getStatus(),
+ contentResponse.getReason());
+ }
+ } catch (TimeoutException e) {
+ errorReason = "TimeoutException: WLED was not reachable on your network";
+ } catch (ExecutionException e) {
+ errorReason = String.format("ExecutionException: %s", e.getMessage());
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ errorReason = String.format("InterruptedException: %s", e.getMessage());
+ }
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, errorReason);
+ }
+
+ private HSBType parseToHSBType(String message, String element) {
+ int startIndex = message.indexOf(element);
+ if (startIndex == -1) {
+ return new HSBType();
+ }
+ int endIndex = message.indexOf("<", startIndex + element.length());
+ int r = 0, g = 0, b = 0;
+ try {
+ r = Integer.parseInt(message.substring(startIndex + element.length(), endIndex));
+ // look for second element
+ startIndex = message.indexOf(element, endIndex);
+ if (startIndex == -1) {
+ return new HSBType();
+ }
+ endIndex = message.indexOf("<", startIndex + element.length());
+ g = Integer.parseInt(message.substring(startIndex + element.length(), endIndex));
+ // look for third element called
+ startIndex = message.indexOf(element, endIndex);
+ if (startIndex == -1) {
+ return new HSBType();
+ }
+ endIndex = message.indexOf("<", startIndex + element.length());
+ b = Integer.parseInt(message.substring(startIndex + element.length(), endIndex));
+ } catch (NumberFormatException e) {
+ logger.warn("NumberFormatException when parsing the WLED color fields:{}", e.getMessage());
+ }
+ return HSBType.fromRGB(r, g, b);
+ }
+
+ private void parseColours(String message) {
+ primaryColor = parseToHSBType(message, "");
+ updateState(CHANNEL_PRIMARY_COLOR, primaryColor);
+ secondaryColor = parseToHSBType(message, "");
+ updateState(CHANNEL_SECONDARY_COLOR, secondaryColor);
+ try {
+ primaryWhite = new BigDecimal(WLedHelper.getValue(message, "", "<"));
+ if (primaryWhite.intValue() > -1) {
+ hasWhite = true;
+ updateState(CHANNEL_PRIMARY_WHITE,
+ new PercentType(primaryWhite.divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP)));
+ secondaryWhite = new BigDecimal(WLedHelper.getValue(message, "", "<"));
+ updateState(CHANNEL_SECONDARY_WHITE,
+ new PercentType(secondaryWhite.divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP)));
+ }
+ } catch (NumberFormatException e) {
+ logger.warn("NumberFormatException when parsing the WLED colour and white fields:{}", e.getMessage());
+ }
+ }
+
+ /**
+ *
+ * This function should prevent the need to keep updating the binding as more FX and Palettes are added to the
+ * firmware.
+ */
+ private void scrapeChannelOptions(String message) {
+ List fxOptions = new ArrayList<>();
+ List palleteOptions = new ArrayList<>();
+ int counter = 0;
+ for (String value : WLedHelper.getValue(message, "\"effects\":[", "]").replace("\"", "").split(",")) {
+ fxOptions.add(new StateOption(Integer.toString(counter++), value));
+ }
+ stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_FX), fxOptions);
+ counter = 0;
+ for (String value : (WLedHelper.getValue(message, "\"palettes\":[", "]").replace("\"", "")).split(",")) {
+ palleteOptions.add(new StateOption(Integer.toString(counter++), value));
+ }
+ stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_PALETTES), palleteOptions);
+ }
+
+ private void processState(String message) {
+ logger.trace("WLED states are:{}", message);
+ if (thing.getStatus() != ThingStatus.ONLINE) {
+ updateStatus(ThingStatus.ONLINE);
+ sendGetRequest("/json"); // fetch FX and Pallete names
+ }
+ if (message.contains("\"effects\":[")) {// JSON API reply
+ scrapeChannelOptions(message);
+ return;
+ }
+ if (message.contains("0")) {
+ updateState(CHANNEL_MASTER_CONTROLS, OnOffType.OFF);
+ } else {
+ masterBrightness255 = new BigDecimal(WLedHelper.getValue(message, "", "<"));
+ updateState(CHANNEL_MASTER_CONTROLS,
+ new PercentType(masterBrightness255.divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP)));
+ }
+ if (message.contains("0")) {
+ updateState(CHANNEL_INTENSITY, OnOffType.OFF);
+ } else {
+ BigDecimal bigTemp = new BigDecimal(WLedHelper.getValue(message, "", "<")).divide(BIG_DECIMAL_2_55,
+ RoundingMode.HALF_UP);
+ updateState(CHANNEL_INTENSITY, new PercentType(bigTemp));
+ }
+ if (message.contains("1")) {
+ updateState(CHANNEL_PRESET_CYCLE, OnOffType.ON);
+ } else {
+ updateState(CHANNEL_PRESET_CYCLE, OnOffType.OFF);
+ }
+ if (message.contains("1")) {
+ updateState(CHANNEL_SLEEP, OnOffType.ON);
+ } else {
+ updateState(CHANNEL_SLEEP, OnOffType.OFF);
+ }
+ if (message.contains("1")) {
+ updateState(CHANNEL_SYNC_SEND, OnOffType.ON);
+ } else {
+ updateState(CHANNEL_SYNC_SEND, OnOffType.OFF);
+ }
+ if (message.contains("1")) {
+ updateState(CHANNEL_SYNC_RECEIVE, OnOffType.ON);
+ } else {
+ updateState(CHANNEL_SYNC_RECEIVE, OnOffType.OFF);
+ }
+ if (message.contains("")) {
+ updateState(CHANNEL_FX, new StringType(WLedHelper.getValue(message, "", "<")));
+ }
+ if (message.contains("")) {
+ BigDecimal bigTemp = new BigDecimal(WLedHelper.getValue(message, "", "<")).divide(BIG_DECIMAL_2_55,
+ RoundingMode.HALF_UP);
+ updateState(CHANNEL_SPEED, new PercentType(bigTemp));
+ }
+ if (message.contains("")) {
+ updateState(CHANNEL_PALETTES, new StringType(WLedHelper.getValue(message, "", "<")));
+ }
+ parseColours(message);
+ }
+
+ private void sendWhite() {
+ if (hasWhite) {
+ sendGetRequest("/win&TT=1000&FX=0&CY=0&CL=hFF000000" + "&A=" + masterBrightness255);
+ } else {
+ sendGetRequest("/win&TT=1000&FX=0&CY=0&CL=hFFFFFF" + "&A=" + masterBrightness255);
+ }
+ }
+
+ /**
+ *
+ * @param hsb
+ * @return WLED needs the letter h followed by 2 digit HEX code for RRGGBB
+ */
+ private String createColorHex(HSBType hsb) {
+ return String.format("h%06X", hsb.getRGB());
+ }
+
+ @Override
+ public void handleCommand(ChannelUID channelUID, Command command) {
+ BigDecimal bigTemp;
+ PercentType localPercentType;
+ if (command instanceof RefreshType) {
+ switch (channelUID.getId()) {
+ case CHANNEL_MASTER_CONTROLS:
+ sendGetRequest("/win");
+ }
+ return;// no need to check for refresh below
+ }
+ logger.debug("command {} sent to {}", command, channelUID.getId());
+ switch (channelUID.getId()) {
+ case CHANNEL_SYNC_SEND:
+ if (OnOffType.OFF.equals(command)) {
+ sendGetRequest("/win&NS=0");
+ } else {
+ sendGetRequest("/win&NS=1");
+ }
+ break;
+ case CHANNEL_SYNC_RECEIVE:
+ if (OnOffType.OFF.equals(command)) {
+ sendGetRequest("/win&NR=0");
+ } else {
+ sendGetRequest("/win&NR=1");
+ }
+ break;
+ case CHANNEL_PRIMARY_WHITE:
+ if (command instanceof PercentType) {
+ sendGetRequest("/win&W=" + ((PercentType) command).toBigDecimal().multiply(BIG_DECIMAL_2_55));
+ }
+ break;
+ case CHANNEL_SECONDARY_WHITE:
+ if (command instanceof PercentType) {
+ sendGetRequest("/win&W2=" + ((PercentType) command).toBigDecimal().multiply(BIG_DECIMAL_2_55));
+ }
+ break;
+ case CHANNEL_MASTER_CONTROLS:
+ if (command instanceof OnOffType) {
+ if (OnOffType.OFF.equals(command)) {
+ sendGetRequest("/win&TT=250&T=0");
+ } else {
+ sendGetRequest("/win&TT=1000&T=1");
+ }
+ } else if (command instanceof IncreaseDecreaseType) {
+ if (IncreaseDecreaseType.INCREASE.equals(command)) {
+ if (masterBrightness255.intValue() < 240) {
+ sendGetRequest("/win&TT=1000&A=~15"); // 255 divided by 15 = 17 different levels
+ } else {
+ sendGetRequest("/win&TT=1000&A=255");
+ }
+ } else {
+ if (masterBrightness255.intValue() > 15) {
+ sendGetRequest("/win&TT=1000&A=~-15");
+ } else {
+ sendGetRequest("/win&TT=1000&A=0");
+ }
+ }
+ } else if (command instanceof HSBType) {
+ if ((((HSBType) command).getBrightness()) == PercentType.ZERO) {
+ sendGetRequest("/win&TT=500&T=0");
+ }
+ primaryColor = (HSBType) command;
+ masterBrightness255 = primaryColor.getBrightness().toBigDecimal().multiply(BIG_DECIMAL_2_55);
+ if (primaryColor.getSaturation().intValue() < config.saturationThreshold) {
+ sendWhite();
+ } else if (primaryColor.getSaturation().intValue() == 32 && primaryColor.getHue().intValue() == 36
+ && hasWhite) {
+ // Google sends this when it wants white
+ sendWhite();
+ } else {
+ sendGetRequest("/win&TT=1000&FX=0&CY=0&CL=" + createColorHex(primaryColor) + "&A="
+ + masterBrightness255);
+ }
+ } else if (command instanceof PercentType) {
+ masterBrightness255 = ((PercentType) command).toBigDecimal().multiply(BIG_DECIMAL_2_55);
+ sendGetRequest("/win&TT=1000&A=" + masterBrightness255);
+ }
+ return;
+ case CHANNEL_PRIMARY_COLOR:
+ if (command instanceof HSBType) {
+ primaryColor = (HSBType) command;
+ sendGetRequest("/win&CL=" + createColorHex(primaryColor));
+ } else if (command instanceof PercentType) {
+ primaryColor = new HSBType(primaryColor.getHue(), primaryColor.getSaturation(),
+ ((PercentType) command));
+ sendGetRequest("/win&CL=" + createColorHex(primaryColor));
+ }
+ return;
+ case CHANNEL_SECONDARY_COLOR:
+ if (command instanceof HSBType) {
+ secondaryColor = (HSBType) command;
+ sendGetRequest("/win&C2=" + createColorHex(secondaryColor));
+ } else if (command instanceof PercentType) {
+ secondaryColor = new HSBType(secondaryColor.getHue(), secondaryColor.getSaturation(),
+ ((PercentType) command));
+ sendGetRequest("/win&C2=" + createColorHex(secondaryColor));
+ }
+ return;
+ case CHANNEL_PALETTES:
+ sendGetRequest("/win&FP=" + command);
+ break;
+ case CHANNEL_FX:
+ sendGetRequest("/win&FX=" + command);
+ break;
+ case CHANNEL_SPEED:
+ localPercentType = ((State) command).as(PercentType.class);
+ if (localPercentType != null) {
+ bigTemp = localPercentType.toBigDecimal().multiply(BIG_DECIMAL_2_55);
+ sendGetRequest("/win&SX=" + bigTemp);
+ }
+ break;
+ case CHANNEL_INTENSITY:
+ localPercentType = ((State) command).as(PercentType.class);
+ if (localPercentType != null) {
+ bigTemp = localPercentType.toBigDecimal().multiply(BIG_DECIMAL_2_55);
+ sendGetRequest("/win&IX=" + bigTemp);
+ }
+ break;
+ case CHANNEL_SLEEP:
+ if (OnOffType.ON.equals(command)) {
+ sendGetRequest("/win&NL=1");
+ } else {
+ sendGetRequest("/win&NL=0");
+ }
+ break;
+ case CHANNEL_PRESETS:
+ sendGetRequest("/win&PL=" + command);
+ break;
+ case CHANNEL_PRESET_DURATION:
+ if (command instanceof QuantityType) {
+ QuantityType> seconds = ((QuantityType>) command).toUnit(SmartHomeUnits.SECOND);
+ if (seconds != null) {
+ bigTemp = new BigDecimal(seconds.intValue()).multiply(new BigDecimal(1000));
+ sendGetRequest("/win&PT=" + bigTemp.intValue());
+ }
+ }
+ break;
+ case CHANNEL_TRANS_TIME:
+ if (command instanceof QuantityType) {
+ QuantityType> seconds = ((QuantityType>) command).toUnit(SmartHomeUnits.SECOND);
+ if (seconds != null) {
+ bigTemp = new BigDecimal(seconds.intValue()).multiply(new BigDecimal(1000));
+ sendGetRequest("/win&TT=" + bigTemp.intValue());
+ }
+ }
+ break;
+ case CHANNEL_PRESET_CYCLE:
+ if (OnOffType.ON.equals(command)) {
+ sendGetRequest("/win&CY=1");
+ } else {
+ sendGetRequest("/win&CY=0");
+ }
+ break;
+ }
+ }
+
+ public void savePreset(int presetIndex) {
+ if (presetIndex > 16) {
+ logger.warn("Presets above 16 do not exist, and the action sent {}", presetIndex);
+ return;
+ }
+ sendGetRequest("/win&PS=" + presetIndex);
+ }
+
+ private void pollLED() {
+ sendGetRequest("/win");
+ }
+
+ @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::pollLED, 1, config.pollTime, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void dispose() {
+ Future> future = pollingFuture;
+ if (future != null) {
+ future.cancel(true);
+ }
+ }
+
+ @Override
+ public Collection> getServices() {
+ return Collections.singleton(WLedActions.class);
+ }
+}
diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandlerFactory.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandlerFactory.java
new file mode 100644
index 00000000000..e5cced3b8ac
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandlerFactory.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2010-2020 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.SUPPORTED_THING_TYPES;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.openhab.core.io.net.http.HttpClientFactory;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.binding.BaseThingHandlerFactory;
+import org.openhab.core.thing.binding.ThingHandler;
+import org.openhab.core.thing.binding.ThingHandlerFactory;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+/**
+ * The {@link WLedHandlerFactory} is responsible for creating things and thing
+ * handlers.
+ *
+ * @author Matthew Skinner - Initial contribution
+ */
+@NonNullByDefault
+@Component(configurationPid = "binding.wled", service = ThingHandlerFactory.class)
+public class WLedHandlerFactory extends BaseThingHandlerFactory {
+ private final HttpClient httpClient;
+ private final WledDynamicStateDescriptionProvider stateDescriptionProvider;
+
+ @Activate
+ public WLedHandlerFactory(@Reference HttpClientFactory httpClientFactory,
+ final @Reference WledDynamicStateDescriptionProvider stateDescriptionProvider) {
+ this.httpClient = httpClientFactory.getCommonHttpClient();
+ this.stateDescriptionProvider = stateDescriptionProvider;
+ }
+
+ @Override
+ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
+ if (SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected @Nullable ThingHandler createHandler(Thing thing) {
+ ThingTypeUID thingTypeUID = thing.getThingTypeUID();
+ if (SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
+ return new WLedHandler(thing, httpClient, stateDescriptionProvider);
+ }
+ return null;
+ }
+}
diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHelper.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHelper.java
new file mode 100644
index 00000000000..9e720a3743b
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHelper.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2010-2020 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 java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link WLedHelper} Provides helper classes that are used from multiple classes in the binding.
+ *
+ * @author Matthew Skinner - Initial contribution
+ */
+@NonNullByDefault
+public class WLedHelper {
+
+ /**
+ * @return A string that starts after finding the element and terminates when it finds the first occurrence of the
+ * end string after the element.
+ */
+ static String getValue(String message, String element, String end) {
+ int startIndex = message.indexOf(element);
+ if (startIndex != -1) // -1 means "not found"
+ {
+ int endIndex = message.indexOf(end, startIndex + element.length());
+ if (endIndex != -1) {
+ return message.substring(startIndex + element.length(), endIndex);
+ }
+ }
+ return "";
+ }
+
+ /**
+ * @return A List that holds the values from a heading/element that re-occurs in a message multiple times.
+ *
+ */
+ static List listOfResults(String message, String element, String end) {
+ List results = new LinkedList<>();
+ String temp = "";
+ for (int startLookingFromIndex = 0; startLookingFromIndex != -1;) {
+ startLookingFromIndex = message.indexOf(element, startLookingFromIndex);
+ if (startLookingFromIndex >= 0) {
+ temp = getValue(message.substring(startLookingFromIndex), element, end);
+ if (!temp.isEmpty()) {
+ results.add(temp);
+ } else {
+ return results;// end string must not exist so stop looking.
+ }
+ startLookingFromIndex += temp.length();
+ }
+ }
+ return results;
+ }
+}
diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WledDynamicStateDescriptionProvider.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WledDynamicStateDescriptionProvider.java
new file mode 100644
index 00000000000..1dff192e404
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WledDynamicStateDescriptionProvider.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2010-2020 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;
+import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider;
+import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
+import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+/**
+ * The {@link WledDynamicStateDescriptionProvider} Allows the dynamic updating of the FX and Palletes that WLED keep
+ * changing between firmware versions.
+ *
+ * @author Matthew Skinner - Initial contribution
+ */
+@Component(service = { DynamicStateDescriptionProvider.class, WledDynamicStateDescriptionProvider.class })
+@NonNullByDefault
+public class WledDynamicStateDescriptionProvider extends BaseDynamicStateDescriptionProvider {
+ @Activate
+ public WledDynamicStateDescriptionProvider(
+ final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
+ this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService;
+ }
+}
diff --git a/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/binding/binding.xml
new file mode 100644
index 00000000000..bb0be8665b2
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/binding/binding.xml
@@ -0,0 +1,10 @@
+
+
+
+ WLED Binding
+ This is the binding for WLED
+ Matthew Skinner
+
+
diff --git a/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/thing/thing-types.xml
new file mode 100644
index 00000000000..fc2eb47d4f1
--- /dev/null
+++ b/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/thing/thing-types.xml
@@ -0,0 +1,183 @@
+
+
+
+
+
+ A WLED string of LEDs
+ ColorLight
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use this format http://192.168.1.2:80
+
+
+
+ Time in seconds of how often to fetch the state of the LEDs.
+ 10
+
+
+
+ Leave this as -1 if you are not using segments, otherwise set this to the segment index number that you
+ wish to control.
+ -1
+
+
+
+ This feature allows you to specify a number that if the saturation drops below, will trigger white.
+
+ 0
+
+
+
+
+
+ Color
+
+ Allows you to exit FX mode and use the LEDS like a normal light
+ ColorLight
+
+ Lighting
+
+
+
+
+ Color
+
+ Allows you to change the primary color used in FX
+ ColorLight
+
+
+
+ Dimmer
+
+ Changes the brightness of the primary white LED
+ DimmableLight
+
+
+
+ Color
+
+ Allows you to change the secondary color used in FX
+ ColorLight
+
+
+
+ Dimmer
+
+ Changes the brightness of the secondary white LED
+ DimmableLight
+
+
+
+ String
+
+ Change the colours used by the FX
+
+
+
+ String
+
+ Use the built in FX
+
+
+
+ String
+
+ Auto rotate or change to a saved preset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Number:Time
+
+ Time for how long to show each preset for before moving to the next
+ Time
+
+
+
+
+ Number:Time
+
+ Time it takes to change/fade from one look to the next.
+ Time
+
+
+
+
+ Dimmer
+
+ Change the speed of the FX
+
+
+
+ Dimmer
+
+ Change the intensity of the FX
+
+
+
+ Switch
+
+ Fade the level of light and turn off after set time
+ Time
+
+
+
+ Switch
+
+ Cycle through the saved presets
+
+
+
+ Switch
+
+ Sends UDP packets that tell other WLED lights to follow this one.
+
+
+
+ Switch
+
+ Allows UDP packets from other WLED lights to control this one.
+
+
+
diff --git a/bundles/pom.xml b/bundles/pom.xml
index 73be0d30af3..ce230537d8a 100644
--- a/bundles/pom.xml
+++ b/bundles/pom.xml
@@ -299,6 +299,7 @@
org.openhab.binding.wifiledorg.openhab.binding.windcentraleorg.openhab.binding.wlanthermo
+ org.openhab.binding.wledorg.openhab.binding.xmltvorg.openhab.binding.xmppclientorg.openhab.binding.yamahareceiver