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

[hue] Add hue gateway as thing to activate predefined scenes #6043 #7540

Closed
wants to merge 4 commits into from
Closed
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
17 changes: 16 additions & 1 deletion bundles/org.openhab.binding.hue/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ The devices support some of the following channels:
| status | Number | This channel save status state for a CLIP sensor. | 0840 |
| last_updated | DateTime | This channel the date and time when the sensor was last updated. | 0820, 0830, 0840, 0850, 0106, 0107, 0302|
| battery_level | Number | This channel shows the battery level. | 0820, 0106, 0107, 0302 |
| battery_low | Switch | This channel indicates whether the battery is low or not. | 0820, 0106, 0107, 0302 |
| battery_low | Switch | This channel indicates whether the battery is low or not. | 0820, 0106, 0107, 0302 |

### Trigger Channels

Expand Down Expand Up @@ -224,6 +224,15 @@ The `tap_switch_event` can trigger one of the following events:
| Button 3 | Button 3 | 17 |
| Button 4 | Button 4 | 18 |

### Scene Channel

The bridge itself supports a channel to activate scenes:

| Channel Type ID | Item Type | Description |
| --------------- | --------- | ----------- |
| scene | String | This channel activates the scene with the given ID String. |

The scenes are identified by an ID String that is assigned by the Hue bridge.

## Rule Actions

Expand Down Expand Up @@ -301,6 +310,9 @@ Switch MotionSensorLowBattery { channel="hue:0107:1:motion-sensor:battery_lo

// Temperature Sensor
Number:Temperature TemperatureSensorTemperature { channel="hue:0302:temperature-sensor:temperature" }

// Scenes
String LightScene { channel="hue:bridge:1:scene"}
```

Note: The bridge ID is in this example **1** but can be different in each system.
Expand Down Expand Up @@ -336,6 +348,9 @@ sitemap demo label="Main Menu"
Text item=MotionSensorLastUpdate
Text item=MotionSensorBatteryLevel
Switch item=MotionSensorLowBattery

// Light Scenes
Switch item=LightScene label="Scene []" mappings=[abcdefgh1234567="Relax", ABCDEFGH1234567="Concentrate"]
}
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ public class FullGroup extends Group {
private State state; // Will not be set by hue API

FullGroup() {
super();
}

/**
* Test constructor
*/
FullGroup(String id, String name, String type, State action, List<String> lights, State state) {
super(id, name, type);
this.action = action;
this.lights = lights;
this.state = state;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ public class Group {
this.type = "LightGroup";
}

/**
* Test constructor
*/
Group(String id, String name, String type) {
this.id = id;
this.name = name;
this.type = type;
}

void setName(String name) {
this.name = name;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public class HueBindingConstants {
public static final String CHANNEL_DAYLIGHT = "daylight";
public static final String CHANNEL_STATUS = "status";
public static final String CHANNEL_FLAG = "flag";
public static final String CHANNEL_SCENE = "scene";

// List all triggers
public static final String EVENT_DIMMER_SWITCH = "dimmer_switch_event";
Expand All @@ -86,7 +87,7 @@ public class HueBindingConstants {
public static final String PROTOCOL = "protocol";
public static final String USER_NAME = "userName";

// Light config properties
// Configuration properties
public static final String LIGHT_ID = "lightId";
public static final String SENSOR_ID = "sensorId";
public static final String PRODUCT_NAME = "productName";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.stream.Collectors;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -114,6 +116,17 @@ public HueBridge(String ip, int port, String protocol, String username, Schedule
authenticate(username);
}

/**
* Test constructor
*/
HueBridge(String ip, String baseUrl, String username, ScheduledExecutorService scheduler, HttpClient http) {
this.ip = ip;
this.baseUrl = baseUrl;
this.username = username;
this.scheduler = scheduler;
this.http = http;
}

/**
* Set the connect and read timeout for HTTP requests.
*
Expand Down Expand Up @@ -851,6 +864,39 @@ public void deleteSchedule(Schedule schedule) throws IOException, ApiException {
handleErrors(result);
}

/**
* Returns the list of scenes that are not recyclable.
*
* @return all scenes that can be activated
*/
public List<Scene> getScenes() throws IOException, ApiException {
requireAuthentication();

Result result = http.get(getRelativeURL("scenes"));
handleErrors(result);

Map<String, Scene> sceneMap = safeFromJson(result.getBody(), Scene.GSON_TYPE);
return sceneMap.entrySet().parallelStream()//
.map(e -> {
e.getValue().setId(e.getKey());
return e.getValue();
})//
.filter(scene -> !scene.isRecycle())//
.sorted(Comparator.comparing(Scene::getGroupId))//
.collect(Collectors.toList());
}

/**
* Activate scene to all lights that belong to the scene.
*
* @param id the scene to be activated
* @throws IOException if the bridge cannot be reached
*/
public CompletableFuture<Result> recallScene(String id) {
Group allLightsGroup = new Group();
return setGroupState(allLightsGroup, new StateUpdate().setScene(id));
}

/**
* Authenticate on the bridge as the specified user.
* This function verifies that the specified username is valid and will use
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import com.google.gson.reflect.TypeToken;

/**
* Basic light information.
* Basic hue object information.
*
* @author Q42 - Initial contribution
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
import org.openhab.binding.hue.internal.handler.HueGroupHandler;
import org.openhab.binding.hue.internal.handler.HueLightHandler;
import org.openhab.binding.hue.internal.handler.HueStateDescriptionOptionProvider;
import org.openhab.binding.hue.internal.handler.sensors.ClipHandler;
import org.openhab.binding.hue.internal.handler.sensors.DimmerSwitchHandler;
import org.openhab.binding.hue.internal.handler.sensors.LightLevelHandler;
Expand All @@ -45,6 +46,7 @@
import org.openhab.binding.hue.internal.handler.sensors.TemperatureHandler;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

/**
* {@link HueThingHandlerFactory} is a factory for {@link HueBridgeHandler}s.
Expand All @@ -59,6 +61,7 @@
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.hue")
public class HueThingHandlerFactory extends BaseThingHandlerFactory {

public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.unmodifiableSet(
Stream.of(HueBridgeHandler.SUPPORTED_THING_TYPES.stream(), HueLightHandler.SUPPORTED_THING_TYPES.stream(),
DimmerSwitchHandler.SUPPORTED_THING_TYPES.stream(), TapSwitchHandler.SUPPORTED_THING_TYPES.stream(),
Expand All @@ -68,6 +71,9 @@ public class HueThingHandlerFactory extends BaseThingHandlerFactory {

private final Map<ThingUID, @Nullable ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();

@NonNullByDefault({})
private HueStateDescriptionOptionProvider stateOptionProvider;

@Override
public @Nullable Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration,
@Nullable ThingUID thingUID, @Nullable ThingUID bridgeUID) {
Expand Down Expand Up @@ -135,7 +141,7 @@ private ThingUID getThingUID(ThingTypeUID thingTypeUID, String id, @Nullable Thi
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
if (HueBridgeHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
HueBridgeHandler handler = new HueBridgeHandler((Bridge) thing);
HueBridgeHandler handler = new HueBridgeHandler((Bridge) thing, stateOptionProvider);
registerLightDiscoveryService(handler);
return handler;
} else if (HueLightHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
Expand All @@ -153,7 +159,7 @@ private ThingUID getThingUID(ThingTypeUID thingTypeUID, String id, @Nullable Thi
} else if (ClipHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
return new ClipHandler(thing);
} else if (HueGroupHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
return new HueGroupHandler(thing);
return new HueGroupHandler(thing, stateOptionProvider);
} else {
return null;
}
Expand Down Expand Up @@ -181,4 +187,13 @@ protected synchronized void removeHandler(ThingHandler thingHandler) {
}
}
}

@Reference
protected void setHueStateDescriptionOptionProvider(HueStateDescriptionOptionProvider stateOptionProvider) {
this.stateOptionProvider = stateOptionProvider;
}

protected void unsetHueStateDescriptionOptionProvider(HueStateDescriptionOptionProvider stateOptionProvider) {
this.stateOptionProvider = null;
}
}
Loading