mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[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:
parent
87023da9e3
commit
7f249872bc
@ -7,27 +7,50 @@ This binding allows you to auto discover and use LED strings based on the WLED p
|
||||
|
||||
| Thing Type ID | Description |
|
||||
|-|-|
|
||||
| `wled` | Use this for RGB and RGBW strings. |
|
||||
| `json` | A bridge to a WLED device using the JSON API. Add this thing first. |
|
||||
| `segment` | A segment is used to turn a LED strip or string, into 1 or more lights. Each segment is like a separate light globe that can have its own color or effect. |
|
||||
|
||||
## 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.
|
||||
openHAB will then discover and auto name your WLED bridge thing to the name provided as the 'Server description'.
|
||||
Segments will be discovered with an Inbox scan after the bridge thing is first showing up as ONLINE.
|
||||
Any segments that have been given a name in the WLED firmware, will be given the same name when discovery adds them to the Inbox.
|
||||
|
||||
## Thing Configuration
|
||||
## Bridge 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 0 if you do not know what a segment is. | Y | 0 |
|
||||
| `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
|
||||
## Bridge Thing Channels
|
||||
|
||||
| Channel | Type | Description |
|
||||
|-|-|-|
|
||||
| `globalBrightness` | Dimmer | Changes the brightness of all segments at the same time. |
|
||||
| `presets` | String | A list of presets that you can select from and will display -1 when no presets are running. |
|
||||
| `playlists` | String | A list of playlists that you can select from and will display -1 when none are running. |
|
||||
| `presetCycle` | Switch | Turns ON/OFF the automatic changing from one preset to the next. Only in V0.12.0 and older firmwares. |
|
||||
| `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. Only in V0.12.0 and older firmwares. |
|
||||
| `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. |
|
||||
| `sleepMode` | String | Timed Light Mode selects how the light will fade or increase when the sleep timer is turned ON. |
|
||||
| `sleepDuration` | Number:Time | Time it takes to change/fade to the target brightness. |
|
||||
| `sleepTargetBrightness` | Dimmer | Sets how bright the light will be after the sleep duration time has expired. |
|
||||
| `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. |
|
||||
| `liveOverride` | String | A value of "0" turns off, "1" will override live data to display what you want, and "2" overrides until you reboot the ESP device. |
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
| Parameter | Description | Required | Default |
|
||||
|-|-|-|-|
|
||||
| `segmentIndex` | The index number to the LED segment you wish these channels to control. Leave on 0 if you do not know what a segment is. | Y | 0 |
|
||||
|
||||
## Thing Channels
|
||||
|
||||
| Channel | Type | Description |
|
||||
|-|-|-|
|
||||
@ -43,17 +66,8 @@ For additional segments, you can add them manually and set the `segmentIndex` co
|
||||
| `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 and will display -1 when no presets are running. |
|
||||
| `playlists` | String | A list of playlists that you can select from and will display -1 when none are running. |
|
||||
| `presetCycle` | Switch | Turns ON/OFF the automatic changing from one preset to the next. Only in V0.12.0 and older firmwares. |
|
||||
| `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. Only in V0.12.0 and older firmwares. |
|
||||
| `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. |
|
||||
| `mirror` | Switch | Mirror the effect for this segment. |
|
||||
| `reverse` | Switch | Reverse the effect for this segment. |
|
||||
| `liveOverride` | String | A value of "0" turns off, "1" will override live data to display what you want, and "2" overrides until you reboot the ESP device. |
|
||||
| `grouping` | Number | The number of LEDs that are grouped together to display as one pixel in FX. Use metadata to display a list widget slider. |
|
||||
| `spacing` | Number | The number of LEDs that will not light up in between FX pixels. Use metadata to display a list widget slider. |
|
||||
|
||||
@ -64,12 +78,12 @@ This binding has two rule Actions `savePreset(int presetNumber)` and `savePreset
|
||||
In Xtend rules, you can use the Actions like this.
|
||||
|
||||
```
|
||||
getActions("wled", "wled:wled:XmasTree").savePreset(5,"Flashy Preset")
|
||||
getActions("wled", "wled:json:XmasTree").savePreset(5,"Flashy Preset")
|
||||
```
|
||||
|
||||
## 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.
|
||||
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 `segment` thing when it was added via the Inbox.
|
||||
|
||||
*.sitemap
|
||||
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user