2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.hue.internal.factory;
15 import static org.openhab.binding.hue.internal.HueBindingConstants.*;
18 import java.util.stream.Collectors;
19 import java.util.stream.Stream;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.hue.internal.HueBindingConstants;
24 import org.openhab.binding.hue.internal.handler.Clip2BridgeHandler;
25 import org.openhab.binding.hue.internal.handler.Clip2StateDescriptionProvider;
26 import org.openhab.binding.hue.internal.handler.Clip2ThingHandler;
27 import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
28 import org.openhab.binding.hue.internal.handler.HueGroupHandler;
29 import org.openhab.binding.hue.internal.handler.HueLightHandler;
30 import org.openhab.binding.hue.internal.handler.HueStateDescriptionProvider;
31 import org.openhab.binding.hue.internal.handler.sensors.ClipHandler;
32 import org.openhab.binding.hue.internal.handler.sensors.DimmerSwitchHandler;
33 import org.openhab.binding.hue.internal.handler.sensors.GeofencePresenceHandler;
34 import org.openhab.binding.hue.internal.handler.sensors.LightLevelHandler;
35 import org.openhab.binding.hue.internal.handler.sensors.PresenceHandler;
36 import org.openhab.binding.hue.internal.handler.sensors.TapSwitchHandler;
37 import org.openhab.binding.hue.internal.handler.sensors.TemperatureHandler;
38 import org.openhab.core.config.core.Configuration;
39 import org.openhab.core.i18n.LocaleProvider;
40 import org.openhab.core.i18n.TimeZoneProvider;
41 import org.openhab.core.i18n.TranslationProvider;
42 import org.openhab.core.io.net.http.HttpClientFactory;
43 import org.openhab.core.thing.Bridge;
44 import org.openhab.core.thing.Thing;
45 import org.openhab.core.thing.ThingRegistry;
46 import org.openhab.core.thing.ThingTypeUID;
47 import org.openhab.core.thing.ThingUID;
48 import org.openhab.core.thing.binding.BaseThingHandlerFactory;
49 import org.openhab.core.thing.binding.ThingHandler;
50 import org.openhab.core.thing.binding.ThingHandlerFactory;
51 import org.openhab.core.thing.link.ItemChannelLinkRegistry;
52 import org.osgi.service.component.annotations.Activate;
53 import org.osgi.service.component.annotations.Component;
54 import org.osgi.service.component.annotations.Reference;
57 * The factory for all varieties of Hue thing handlers.
59 * @author Dennis Nobel - Initial contribution of hue binding
60 * @author Kai Kreuzer - added supportsThingType method
61 * @author Andre Fuechsel - implemented to use one discovery service per bridge
62 * @author Samuel Leisering - Added support for sensor API
63 * @author Christoph Weitkamp - Added support for sensor API
64 * @author Laurent Garnier - Added support for groups
65 * @author Andrew Fiddian-Green - Added support for CLIP 2 things
68 @Component(service = ThingHandlerFactory.class, configurationPid = "binding.hue")
69 public class HueThingHandlerFactory extends BaseThingHandlerFactory {
71 public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Stream
72 .of(Clip2BridgeHandler.SUPPORTED_THING_TYPES.stream(), Clip2ThingHandler.SUPPORTED_THING_TYPES.stream(),
73 HueBridgeHandler.SUPPORTED_THING_TYPES.stream(), HueLightHandler.SUPPORTED_THING_TYPES.stream(),
74 DimmerSwitchHandler.SUPPORTED_THING_TYPES.stream(), TapSwitchHandler.SUPPORTED_THING_TYPES.stream(),
75 PresenceHandler.SUPPORTED_THING_TYPES.stream(),
76 GeofencePresenceHandler.SUPPORTED_THING_TYPES.stream(),
77 TemperatureHandler.SUPPORTED_THING_TYPES.stream(), LightLevelHandler.SUPPORTED_THING_TYPES.stream(),
78 ClipHandler.SUPPORTED_THING_TYPES.stream(), HueGroupHandler.SUPPORTED_THING_TYPES.stream())
79 .flatMap(i -> i).collect(Collectors.toUnmodifiableSet());
81 private final HttpClientFactory httpClientFactory;
82 private final HueStateDescriptionProvider stateDescriptionProvider;
83 private final Clip2StateDescriptionProvider clip2StateDescriptionProvider;
84 private final TranslationProvider i18nProvider;
85 private final LocaleProvider localeProvider;
86 private final TimeZoneProvider timeZoneProvider;
87 private final ThingRegistry thingRegistry;
88 private final ItemChannelLinkRegistry itemChannelLinkRegistry;
91 public HueThingHandlerFactory(final @Reference HttpClientFactory httpClientFactory,
92 final @Reference HueStateDescriptionProvider stateDescriptionProvider,
93 final @Reference Clip2StateDescriptionProvider clip2StateDescriptionProvider,
94 final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider,
95 final @Reference TimeZoneProvider timeZoneProvider, final @Reference ThingRegistry thingRegistry,
96 final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry) {
97 this.httpClientFactory = httpClientFactory;
98 this.stateDescriptionProvider = stateDescriptionProvider;
99 this.clip2StateDescriptionProvider = clip2StateDescriptionProvider;
100 this.i18nProvider = i18nProvider;
101 this.localeProvider = localeProvider;
102 this.timeZoneProvider = timeZoneProvider;
103 this.thingRegistry = thingRegistry;
104 this.itemChannelLinkRegistry = itemChannelLinkRegistry;
108 public @Nullable Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration,
109 @Nullable ThingUID thingUID, @Nullable ThingUID bridgeUID) {
110 if (HueBindingConstants.THING_TYPE_BRIDGE_API2.equals(thingTypeUID)) {
111 return super.createThing(thingTypeUID, configuration, thingUID, null);
112 } else if (Clip2ThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
113 ThingUID clip2ThingUID = getClip2ThingUID(thingTypeUID, thingUID, configuration, bridgeUID);
114 return super.createThing(thingTypeUID, configuration, clip2ThingUID, bridgeUID);
115 } else if (HueBridgeHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
116 return super.createThing(thingTypeUID, configuration, thingUID, null);
117 } else if (HueLightHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
118 ThingUID hueLightUID = getLightUID(thingTypeUID, thingUID, configuration, bridgeUID);
119 return super.createThing(thingTypeUID, configuration, hueLightUID, bridgeUID);
120 } else if (DimmerSwitchHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
121 || TapSwitchHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
122 || PresenceHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
123 || GeofencePresenceHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
124 || TemperatureHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
125 || LightLevelHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
126 || ClipHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
127 ThingUID hueSensorUID = getSensorUID(thingTypeUID, thingUID, configuration, bridgeUID);
128 return super.createThing(thingTypeUID, configuration, hueSensorUID, bridgeUID);
129 } else if (HueGroupHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
130 ThingUID hueGroupUID = getGroupUID(thingTypeUID, thingUID, configuration, bridgeUID);
131 return super.createThing(thingTypeUID, configuration, hueGroupUID, bridgeUID);
134 throw new IllegalArgumentException("The thing type " + thingTypeUID + " is not supported by the Hue binding.");
138 public boolean supportsThingType(ThingTypeUID thingTypeUID) {
139 return SUPPORTED_THING_TYPES.contains(thingTypeUID);
142 private ThingUID getClip2ThingUID(ThingTypeUID thingTypeUID, @Nullable ThingUID thingUID,
143 Configuration configuration, @Nullable ThingUID bridgeUID) {
144 return thingUID != null ? thingUID
145 : getThingUID(thingTypeUID, configuration.get(PROPERTY_RESOURCE_ID).toString(), bridgeUID);
148 private ThingUID getLightUID(ThingTypeUID thingTypeUID, @Nullable ThingUID thingUID, Configuration configuration,
149 @Nullable ThingUID bridgeUID) {
150 if (thingUID != null) {
153 return getThingUID(thingTypeUID, configuration.get(LIGHT_ID).toString(), bridgeUID);
157 private ThingUID getSensorUID(ThingTypeUID thingTypeUID, @Nullable ThingUID thingUID, Configuration configuration,
158 @Nullable ThingUID bridgeUID) {
159 if (thingUID != null) {
162 return getThingUID(thingTypeUID, configuration.get(SENSOR_ID).toString(), bridgeUID);
166 private ThingUID getGroupUID(ThingTypeUID thingTypeUID, @Nullable ThingUID thingUID, Configuration configuration,
167 @Nullable ThingUID bridgeUID) {
168 if (thingUID != null) {
171 return getThingUID(thingTypeUID, configuration.get(GROUP_ID).toString(), bridgeUID);
175 private ThingUID getThingUID(ThingTypeUID thingTypeUID, String id, @Nullable ThingUID bridgeUID) {
176 if (bridgeUID != null) {
177 return new ThingUID(thingTypeUID, id, bridgeUID.getId());
179 return new ThingUID(thingTypeUID, id);
184 protected @Nullable ThingHandler createHandler(Thing thing) {
185 ThingTypeUID thingTypeUID = thing.getThingTypeUID();
186 if (HueBindingConstants.THING_TYPE_BRIDGE_API2.equals(thingTypeUID)) {
187 return new Clip2BridgeHandler((Bridge) thing, httpClientFactory, thingRegistry, localeProvider,
189 } else if (Clip2ThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
190 return new Clip2ThingHandler(thing, clip2StateDescriptionProvider, timeZoneProvider, thingRegistry,
191 itemChannelLinkRegistry);
192 } else if (HueBridgeHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
193 return new HueBridgeHandler((Bridge) thing, httpClientFactory.getCommonHttpClient(),
194 stateDescriptionProvider, i18nProvider, localeProvider);
195 } else if (HueLightHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
196 return new HueLightHandler(thing, stateDescriptionProvider);
197 } else if (DimmerSwitchHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
198 return new DimmerSwitchHandler(thing);
199 } else if (TapSwitchHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
200 return new TapSwitchHandler(thing);
201 } else if (PresenceHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
202 return new PresenceHandler(thing);
203 } else if (GeofencePresenceHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
204 return new GeofencePresenceHandler(thing);
205 } else if (TemperatureHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
206 return new TemperatureHandler(thing);
207 } else if (LightLevelHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
208 return new LightLevelHandler(thing);
209 } else if (ClipHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
210 return new ClipHandler(thing);
211 } else if (HueGroupHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
212 return new HueGroupHandler(thing, stateDescriptionProvider);