Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[yeelight] Add support for yeelight 650 with ambient light (Closes #6… #6749

Merged
merged 6 commits into from
Feb 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions bundles/org.openhab.binding.yeelight/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ All devices support some of the following channels:
|`color` | `Color` | This channel supports color control, it is available on `wonder` and `stripe`.|
|`colorTemperature` | `Dimmer` | This channel supports adjusting the color temperature, it is available on `wonder` and `stripe` and `ceiling`.|
|`command` | `String` | This channel sends a command directly to the device, it is available on all Yeelight Things.|
|`backgroundColor` | `Color` or `Dimmer` | This channel supports color control for the ambient light, it is available on `ceiling4`.|
|`nightlight` | `Switch` | This supports switching to nightlight mode, it is available on `ceiling4`.|


## Full Example

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class YeelightBindingConstants {
public static final ThingTypeUID THING_TYPE_CEILING = new ThingTypeUID(BINDING_ID, "ceiling");
public static final ThingTypeUID THING_TYPE_CEILING1 = new ThingTypeUID(BINDING_ID, "ceiling1");
public static final ThingTypeUID THING_TYPE_CEILING3 = new ThingTypeUID(BINDING_ID, "ceiling3");
public static final ThingTypeUID THING_TYPE_CEILING4 = new ThingTypeUID(BINDING_ID, "ceiling4");
public static final ThingTypeUID THING_TYPE_DOLPHIN = new ThingTypeUID(BINDING_ID, "dolphin");
public static final ThingTypeUID THING_TYPE_CTBULB = new ThingTypeUID(BINDING_ID, "ct_bulb");
public static final ThingTypeUID THING_TYPE_WONDER = new ThingTypeUID(BINDING_ID, "wonder");
Expand All @@ -44,6 +45,8 @@ public class YeelightBindingConstants {
public static final String CHANNEL_COLOR = "color";
public static final String CHANNEL_COLOR_TEMPERATURE = "colorTemperature";
public static final String CHANNEL_COMMAND = "command";
public static final String CHANNEL_BACKGROUND_COLOR = "backgroundColor";
public static final String CHANNEL_NIGHTLIGHT = "nightlight";

// Constants used
public static final int COLOR_TEMPERATURE_MINIMUM = 1700;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@
import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory;
import org.eclipse.smarthome.core.thing.binding.ThingHandler;
import org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory;
import org.openhab.binding.yeelight.internal.handler.YeelightCeilingHandler;
import org.openhab.binding.yeelight.internal.handler.YeelightColorHandler;
import org.openhab.binding.yeelight.internal.handler.YeelightStripeHandler;
import org.openhab.binding.yeelight.internal.handler.YeelightWhiteHandler;
import org.openhab.binding.yeelight.internal.handler.*;
import org.osgi.service.component.annotations.Component;

/**
Expand All @@ -36,10 +33,12 @@
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.yeelight")
public class YeelightHandlerFactory extends BaseThingHandlerFactory {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<>();

static {
SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_CEILING);
SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_CEILING1);
SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_CEILING3);
SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_CEILING4);
SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_DOLPHIN);
SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_CTBULB);
SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_WONDER);
Expand All @@ -65,6 +64,8 @@ protected ThingHandler createHandler(Thing thing) {
} else if (thingTypeUID.equals(THING_TYPE_CEILING) || thingTypeUID.equals(THING_TYPE_CEILING1)
|| thingTypeUID.equals(THING_TYPE_CEILING3) || thingTypeUID.equals(THING_TYPE_DESKLAMP)) {
return new YeelightCeilingHandler(thing);
} else if (thingTypeUID.equals(THING_TYPE_CEILING4)) {
return new YeelightCeilingWithAmbientHandler(thing);
} else {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ public void onDeviceLost(DeviceBase device) {
private ThingUID getThingUID(DeviceBase device) {
switch (device.getDeviceType()) {
case ceiling:
return new ThingUID(YeelightBindingConstants.THING_TYPE_CEILING, device.getDeviceId());
case ceiling1:
return new ThingUID(YeelightBindingConstants.THING_TYPE_CEILING, device.getDeviceId());
case ceiling3:
return new ThingUID(YeelightBindingConstants.THING_TYPE_CEILING, device.getDeviceId());
case ceiling4:
return new ThingUID(YeelightBindingConstants.THING_TYPE_CEILING4, device.getDeviceId());
case color:
return new ThingUID(YeelightBindingConstants.THING_TYPE_WONDER, device.getDeviceId());
case mono:
Expand All @@ -113,6 +113,8 @@ private ThingTypeUID getThingTypeUID(DeviceBase device) {
return YeelightBindingConstants.THING_TYPE_CEILING1;
case ceiling3:
return YeelightBindingConstants.THING_TYPE_CEILING3;
case ceiling4:
return YeelightBindingConstants.THING_TYPE_CEILING4;
case color:
return YeelightBindingConstants.THING_TYPE_WONDER;
case mono:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* 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.yeelight.internal.handler;

import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.library.types.HSBType;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.library.types.PercentType;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.types.Command;
import org.openhab.binding.yeelight.internal.YeelightBindingConstants;
import org.openhab.binding.yeelight.internal.lib.device.DeviceStatus;
import org.openhab.binding.yeelight.internal.lib.enums.ActiveMode;

/**
* The {@link YeelightCeilingWithAmbientHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Viktor Koop - Initial contribution
*/
public class YeelightCeilingWithAmbientHandler extends YeelightCeilingHandler {

public YeelightCeilingWithAmbientHandler(Thing thing) {
super(thing);
}

@Override
public void handleCommand(ChannelUID channelUID, Command command) {
handleCommandHelper(channelUID, command, "Handle ceiling ambient light command");
}

@Override
protected void updateUI(DeviceStatus status) {
super.updateUI(status);

if (status.isBackgroundIsPowerOff()) {
updateState(YeelightBindingConstants.CHANNEL_BACKGROUND_COLOR, PercentType.ZERO);
} else {
final HSBType hsbType = new HSBType(new DecimalType(status.getBackgroundHue()),
new PercentType(status.getBackgroundSat()), new PercentType(status.getBackgroundBrightness()));

updateState(YeelightBindingConstants.CHANNEL_BACKGROUND_COLOR, hsbType);
}

updateState(YeelightBindingConstants.CHANNEL_NIGHTLIGHT,
(status.getActiveMode() == ActiveMode.MOONLIGHT_MODE) ? OnOffType.ON : OnOffType.OFF);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,8 @@

import java.util.concurrent.TimeUnit;

import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.library.types.HSBType;
import org.eclipse.smarthome.core.library.types.IncreaseDecreaseType;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.library.types.PercentType;
import org.eclipse.smarthome.core.library.types.StringType;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.thing.ThingStatus;
import org.eclipse.smarthome.core.thing.ThingStatusDetail;
import org.eclipse.smarthome.core.thing.ThingTypeUID;
import org.eclipse.smarthome.core.library.types.*;
import org.eclipse.smarthome.core.thing.*;
import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.RefreshType;
Expand Down Expand Up @@ -84,6 +75,8 @@ private DeviceType getDeviceModel(ThingTypeUID typeUID) {
return DeviceType.ceiling;
} else if (typeUID.equals(THING_TYPE_CEILING3)) {
return DeviceType.ceiling3;
} else if (typeUID.equals(THING_TYPE_CEILING4)) {
return DeviceType.ceiling4;
} else if (typeUID.equals(THING_TYPE_WONDER)) {
return DeviceType.color;
} else if (typeUID.equals(THING_TYPE_DOLPHIN)) {
Expand Down Expand Up @@ -143,19 +136,26 @@ public void handleCommandHelper(ChannelUID channelUID, Command command, String l
DeviceManager.getInstance().startDiscovery(5 * 1000);
}
if (command instanceof RefreshType) {
logger.debug("Refresh channel: {} Command: {}", channelUID, command);

DeviceManager.getInstance().startDiscovery(5 * 1000);
DeviceStatus s = mDevice.getDeviceStatus();

switch (channelUID.getId()) {
case CHANNEL_BRIGHTNESS:
updateState(channelUID, new PercentType(s.getBrightness()));
break;
case CHANNEL_COLOR:
HSBType hsb = new HSBType();
updateState(channelUID, HSBType.fromRGB(s.getR(), s.getG(), s.getB()));
break;
case CHANNEL_COLOR_TEMPERATURE:
updateState(channelUID, new PercentType(s.getCt()));
break;
case CHANNEL_BACKGROUND_COLOR:
final HSBType hsbType = new HSBType(new DecimalType(s.getHue()), new PercentType(s.getSat()),
new PercentType(s.getBackgroundBrightness()));
updateState(channelUID, hsbType);
break;
default:
break;
}
Expand Down Expand Up @@ -194,6 +194,25 @@ public void handleCommandHelper(ChannelUID channelUID, Command command, String l
handleIncreaseDecreaseBrightnessCommand((IncreaseDecreaseType) command);
}
break;

case CHANNEL_BACKGROUND_COLOR:
if (command instanceof HSBType) {
HSBType hsbCommand = (HSBType) command;
handleBackgroundHSBCommand(hsbCommand);
} else if (command instanceof PercentType) {
handleBackgroundBrightnessPercentMessage((PercentType) command);
} else if (command instanceof OnOffType) {
handleBackgroundOnOffCommand((OnOffType) command);
}
break;
case CHANNEL_NIGHTLIGHT:
if (command instanceof OnOffType) {
DeviceAction pAction = command == OnOffType.ON ? DeviceAction.nightlight_on
: DeviceAction.nightlight_off;
pAction.putDuration(getDuration());
DeviceManager.getInstance().doAction(deviceId, pAction);
}
break;
case CHANNEL_COMMAND:
if (!command.toString().isEmpty()) {
String[] tokens = command.toString().split(";");
Expand All @@ -206,6 +225,7 @@ public void handleCommandHelper(ChannelUID channelUID, Command command, String l
handleCustomCommand(methodAction, methodParams);
updateState(channelUID, new StringType(""));
}
break;
default:
break;
}
Expand Down Expand Up @@ -258,6 +278,30 @@ void handleHSBCommand(HSBType color) {
DeviceManager.getInstance().doAction(deviceId, cAction);
}

void handleBackgroundHSBCommand(HSBType color) {
DeviceAction cAction = DeviceAction.background_color;

// TODO: actions seem to be an insufficiant abstraction.
cAction.putValue(color.getHue() + "," + color.getSaturation());
cAction.putDuration(getDuration());
DeviceManager.getInstance().doAction(deviceId, cAction);
}

void handleBackgroundBrightnessPercentMessage(PercentType brightness) {
DeviceAction pAction;

pAction = DeviceAction.background_brightness;
pAction.putValue(brightness.intValue());
pAction.putDuration(getDuration());
DeviceManager.getInstance().doAction(deviceId, pAction);
}

private void handleBackgroundOnOffCommand(OnOffType command) {
DeviceAction pAction = command == OnOffType.ON ? DeviceAction.background_on : DeviceAction.background_off;
pAction.putDuration(getDuration());
DeviceManager.getInstance().doAction(deviceId, pAction);
}

void handleColorTemperatureCommand(PercentType ct) {
DeviceAction ctAction = DeviceAction.colortemperature;
ctAction.putValue(COLOR_TEMPERATURE_STEP * ct.intValue() + COLOR_TEMPERATURE_MINIMUM);
Expand All @@ -270,7 +314,7 @@ void handleCustomCommand(String action, String params) {
}

@Override
public void onStatusChanged(String prop, DeviceStatus status) {
public void onStatusChanged(DeviceStatus status) {
logger.debug("UpdateState->{}", status);
updateUI(status);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ public CeilingDevice(String id) {
public void onNotify(String msg) {
JsonObject result = new JsonParser().parse(msg).getAsJsonObject();
try {
String id = "-1";
if (result.has("id")) {
id = result.get("id").getAsString();
String id = result.get("id").getAsString();
// for cmd transaction.

if (mQueryList.contains(id)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* 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.yeelight.internal.lib.device;

import org.openhab.binding.yeelight.internal.lib.enums.ActiveMode;
import org.openhab.binding.yeelight.internal.lib.enums.DeviceType;
import org.openhab.binding.yeelight.internal.lib.enums.MethodAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

/**
* The {@link CeilingDeviceWithAmbientDevice} contains methods for handling the ceiling device with ambient light.
*
* @author Viktor Koop - Initial contribution
*/
public class CeilingDeviceWithAmbientDevice extends CeilingDevice
implements DeviceWithAmbientLight, DeviceWithNightlight {
private final Logger logger = LoggerFactory.getLogger(CeilingDeviceWithAmbientDevice.class);

public CeilingDeviceWithAmbientDevice(String id) {
super(id);

mDeviceType = DeviceType.ceiling4;
}

@Override
public void onNotify(String msg) {
logger.debug("Got state: {}", msg);

JsonObject result = new JsonParser().parse(msg).getAsJsonObject();

if (result.has("id")) {
String id = result.get("id").getAsString();
// for cmd transaction.

if (mQueryList.contains(id)) {
JsonArray status = result.get("result").getAsJsonArray();

final String backgroundPowerState = status.get(4).toString();
if ("\"off\"".equals(backgroundPowerState)) {
mDeviceStatus.setBackgroundIsPowerOff(true);
} else if ("\"on\"".equals(backgroundPowerState)) {
mDeviceStatus.setBackgroundIsPowerOff(false);
}

final int backgroundBrightness = status.get(5).getAsInt();
mDeviceStatus.setBackgroundBrightness(backgroundBrightness);

final int backgroundHue = status.get(6).getAsInt();
mDeviceStatus.setBackgroundHue(backgroundHue);

final int backgroundSaturation = status.get(7).getAsInt();
mDeviceStatus.setBackgroundSat(backgroundSaturation);

final int activeMode = status.get(8).getAsInt();
mDeviceStatus.setActiveMode(ActiveMode.values()[activeMode]);
}
}

super.onNotify(msg);

}

@Override
public void setBackgroundColor(int hue, int saturation, int duration) {
mConnection
.invoke(MethodFactory.buildBackgroundHSVMethod(hue, saturation, DeviceMethod.EFFECT_SMOOTH, duration));
}

@Override
public void setBackgroundBrightness(int brightness, int duration) {
mConnection
.invoke(MethodFactory.buildBackgroundBrightnessMethd(brightness, DeviceMethod.EFFECT_SMOOTH, duration));
}

@Override
public void setBackgroundPower(boolean on, int duration) {
mConnection.invoke(new DeviceMethod(MethodAction.BG_SWITCH,
new Object[] { on ? "on" : "off", DeviceMethod.EFFECT_SMOOTH, duration }));
}

@Override
public void toggleNightlightMode(boolean turnOn) {
if (turnOn) {
mConnection.invoke(
new DeviceMethod(MethodAction.SCENE, new Object[] { "nightlight", mDeviceStatus.getBrightness() }));
} else {
mConnection.invoke(MethodFactory.buildCTMethod(mDeviceStatus.getCt(), DeviceMethod.EFFECT_SMOOTH, 500));
}
}
}
Loading