lampUpdateType, T... t);
+
+ /**
+ * This returns you if the Lamp is enabled or disabled.
+ * But the Bridge handels that stuff a litte bit buggy
+ * so i dont recommend to use it while it wasnt fixed by Phillips.
+ *
+ * @return on/off
+ */
+ @Deprecated(since = "hue-api-bride-buggy")
+ boolean isOn();
+
+ /**
+ * This returns you the {@link UUID} of the Lamp in the v2 HueAPI Version.
+ * Note that this UUID is only Single when you are using one {@link HueBridge}.
+ * With 2 or more {@link HueBridge} the Id can be duplicated.
+ *
+ * @return you the id
+ */
+ UUID getId();
+
+ /**
+ * This returns you the Id of the Lamp.
+ * Its the HueAPI v1 Id (example: /light/1)
+ *
+ * @return you the old id
+ */
+ @Deprecated(since = "hue-api-v2-release")
+ String getId_v1();
+
+ /**
+ * Returns you the Simple Name of the Lamp.
+ *
+ * @return you the Name of the Lamp
+ */
+ String getName();
+
+ /**
+ *
Returns you you the alert Effets.
+ *
+ * @return the {@link Alert}
+ */
+ Alert getAlert();
+
+ /**
+ *
Returns you the Color from the Lamp.
+ *
The Color format is CIE.
+ *
+ * @return you the {@link Color}
+ */
+ Color getColor() throws NullPointerException;
+
+ /**
+ * Returns you the current {@link LampMode} of the Lamp.
+ * It Returns {@link LampMode}.STREAMING when the Lamp is listening to Something
+ * like Spotify, Desktop or something else.
+ *
+ * @return you the LampMode
+ */
+ LampMode getLampMode();
+
+ Dimming getDimming();
+
+ /**
+ * This returns you which type of Lamp this {@link HueLamp} is.
+ * When it can diplay Colors, it is a {@link LampType} COLOR
+ *
+ * @return you the LampType
+ */
+ LampType getLampType();
+
+ /**
+ * Returns you the MetaData from the {@link HueLamp}.
+ * It contains the {@link LampArchetype}. At this time, the api is basically maintained for the {@link LampType}
+ * but other types works to.
+ * The second thing in the {@link MetaData} is the name of the Lamp which you can get with the
+ * {@code getName()} Method.
+ *
+ * @return you the {@link MetaData}
+ */
+ MetaData getMetaData();
+
+ HueBridge getHueBridge();
+
+ /**
+ *
This are the Sub Classes for the {@link HueLamp}
+ */
+ @Data
+ @AllArgsConstructor
+ class MetaData {
+ private LampArchetype archetype;
+ private String name;
+ }
+
+ @Data
+ class Alert {
+ private List action_values;
+ }
+
+ @Data
+ class Dimming {
+ private final Number brightness;
+ }
+
+ @Data
+ class Color {
+ private Map gamut;
+ private String gamut_type;
+ private ColorEntry xy;
+
+ @Data
+ public static class ColorEntry {
+ private double x;
+ private double y;
+ }
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/api/HueLampDiscovery.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/api/HueLampDiscovery.java
new file mode 100644
index 0000000..92d644e
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/api/HueLampDiscovery.java
@@ -0,0 +1,18 @@
+package de.maxizink.lightcontroller.discovery.lamp.api;
+
+import com.google.gson.JsonObject;
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridge;
+import de.maxizink.lightcontroller.injection.Service;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+public interface HueLampDiscovery extends Service {
+
+ List discoverAllLamps(final HueBridge hueBridge);
+
+ CompletableFuture> discoverAllLampsAsync(final HueBridge hueBridge);
+
+ JsonObject getLampObject(final HueLamp hueLamp);
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/api/LampUpdate.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/api/LampUpdate.java
new file mode 100644
index 0000000..d160f4c
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/api/LampUpdate.java
@@ -0,0 +1,9 @@
+package de.maxizink.lightcontroller.discovery.lamp.api;
+
+import de.maxizink.lightcontroller.body.HueRequestBody;
+
+public interface LampUpdate {
+
+ HueRequestBody getRequestBody(final T... param);
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/body/HueColorBody.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/body/HueColorBody.java
new file mode 100644
index 0000000..8d503fd
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/body/HueColorBody.java
@@ -0,0 +1,33 @@
+package de.maxizink.lightcontroller.discovery.lamp.body;
+
+import de.maxizink.lightcontroller.body.HueRequestBody;
+import lombok.Data;
+
+public class HueColorBody implements HueRequestBody {
+
+ private CustomColor color;
+
+ public HueColorBody(double x, double y) {
+ this.color = new CustomColor(x, y);
+ }
+
+ @Data
+ public static class CustomColor {
+
+ private final ColorEntry xy;
+
+ public CustomColor(double x, double y) {
+ this.xy = new ColorEntry(x, y);
+ }
+
+ @Data
+ private static class ColorEntry {
+
+ private final double x;
+ private final double y;
+
+ }
+
+ }
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/body/HueColorTemperatureBody.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/body/HueColorTemperatureBody.java
new file mode 100644
index 0000000..1314c27
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/body/HueColorTemperatureBody.java
@@ -0,0 +1,26 @@
+package de.maxizink.lightcontroller.discovery.lamp.body;
+
+import de.maxizink.lightcontroller.body.HueRequestBody;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLamp;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+public class HueColorTemperatureBody implements HueRequestBody {
+
+ private ColorTemperature color_temperature;
+
+ public HueColorTemperatureBody(final int mirek) {
+ if (mirek < 135 || mirek > 500) {
+ throw new IllegalArgumentException("int is not between 135 and 500");
+ }
+ this.color_temperature = new ColorTemperature(mirek);
+ }
+
+ @Data
+ public static class ColorTemperature {
+ private final int mirek;
+ }
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/body/HueLampBrightnessBody.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/body/HueLampBrightnessBody.java
new file mode 100644
index 0000000..4359d94
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/body/HueLampBrightnessBody.java
@@ -0,0 +1,26 @@
+package de.maxizink.lightcontroller.discovery.lamp.body;
+
+import de.maxizink.lightcontroller.body.HueRequestBody;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class HueLampBrightnessBody implements HueRequestBody {
+
+ private Dimming dimming;
+
+ public HueLampBrightnessBody(final Number brightness) {
+ this.dimming = new Dimming(brightness);
+ }
+
+ @Data
+ public static class Dimming {
+
+ private final Number brightness;
+
+ }
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/body/HueLampEnabledBody.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/body/HueLampEnabledBody.java
new file mode 100644
index 0000000..1ef2602
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/body/HueLampEnabledBody.java
@@ -0,0 +1,23 @@
+package de.maxizink.lightcontroller.discovery.lamp.body;
+
+import de.maxizink.lightcontroller.body.HueRequestBody;
+import lombok.Data;
+
+@Data
+public class HueLampEnabledBody implements HueRequestBody {
+
+ private EnabledStatus on;
+
+ public HueLampEnabledBody(final boolean enabled) {
+ this.on = new EnabledStatus(enabled);
+ }
+
+ @Data
+ public static class EnabledStatus {
+
+ //Real Data
+ private final boolean on;
+
+ }
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/exception/HueLampDiscoveryException.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/exception/HueLampDiscoveryException.java
new file mode 100644
index 0000000..b5f3e6c
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/exception/HueLampDiscoveryException.java
@@ -0,0 +1,9 @@
+package de.maxizink.lightcontroller.discovery.lamp.exception;
+
+public class HueLampDiscoveryException extends RuntimeException {
+
+ public HueLampDiscoveryException(final String message) {
+ super(message);
+ }
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/HueColor.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/HueColor.java
new file mode 100644
index 0000000..e75ff54
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/HueColor.java
@@ -0,0 +1,20 @@
+package de.maxizink.lightcontroller.discovery.lamp.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum HueColor {
+
+ RED(0.675, 0.322),
+ GREEN(0.24, 0.42),
+ YELLOW(0.45, 0.5),
+ VIOLET(0.08, 0.2),
+ ORANGE(0.5, 0.42),
+ BLUE(00.18, 0.15);
+
+ private double x;
+ private double y;
+
+ }
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/HueLampImpl.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/HueLampImpl.java
new file mode 100644
index 0000000..2a6da8f
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/HueLampImpl.java
@@ -0,0 +1,118 @@
+package de.maxizink.lightcontroller.discovery.lamp.model;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.JsonObject;
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridge;
+import de.maxizink.lightcontroller.discovery.bridge.models.HueBridgeCredentials;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLamp;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLampDiscovery;
+import de.maxizink.lightcontroller.discovery.lamp.api.LampUpdate;
+import de.maxizink.lightcontroller.mapper.CustomObjectMapper;
+import de.maxizink.lightcontroller.injection.ServiceAccessor;
+import de.maxizink.lightcontroller.utils.HttpUtils;
+import de.maxizink.lightcontroller.utils.URLFormatter;
+import lombok.Getter;
+import lombok.SneakyThrows;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.jetbrains.annotations.Nullable;
+
+import java.lang.reflect.Constructor;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+
+import static de.maxizink.lightcontroller.utils.HttpUtils.createCredentialHeader;
+import static de.maxizink.lightcontroller.utils.HttpUtils.executeJson;
+
+@Getter
+public class HueLampImpl implements HueLamp {
+
+ private static final ObjectMapper OBJECT_MAPPER = CustomObjectMapper.create();
+
+ private UUID id;
+ private String id_v1;
+ private Alert alert;
+ private @Nullable Color color;
+ private LampMode lampMode;
+ private Dimming dimming;
+ private LampType lampType;
+ private MetaData metaData;
+ @Deprecated(since = "hue-api-bride-buggy")
+ private boolean on;
+
+ private final HueBridge hueBridge;
+
+ @SneakyThrows
+ public HueLampImpl(final JsonObject dataObject, final HueBridge hueBridge) {
+ this.hueBridge = hueBridge;
+
+ this.id = UUID.fromString(dataObject.get("id").getAsString());
+ this.id_v1 = dataObject.get("id_v1").getAsString();
+ this.on = dataObject.getAsJsonObject("on").get("on").getAsBoolean();
+ this.alert = OBJECT_MAPPER.readValue(dataObject.getAsJsonObject("alert").toString(), Alert.class);
+ this.lampMode = LampMode.getMode(dataObject.get("mode").getAsString());
+ this.dimming = new Dimming(dataObject.getAsJsonObject("dimming").get("brightness").getAsNumber());
+
+ if (dataObject.has("color")) {
+ this.color = OBJECT_MAPPER.readValue(dataObject.getAsJsonObject("color").toString(), Color.class);
+ this.lampType = LampType.COLOR;
+ } else {
+ this.lampType = LampType.NO_COLOR;
+ }
+
+ JsonObject metaDataObject = dataObject.getAsJsonObject("metadata");
+ this.metaData = new MetaData(LampArchetype.getArchetype(metaDataObject.get("archetype").getAsString()),
+ metaDataObject.get("name").getAsString());
+ }
+
+ @Override
+ public void refreshLampState() {
+ HueLampDiscovery hueLampDiscovery = ServiceAccessor.accessService(HueLampDiscovery.class);
+ JsonObject jsonObject = hueLampDiscovery.getLampObject(this);
+
+ HueLamp hueLamp = new HueLampImpl(jsonObject, hueBridge);
+ if (jsonObject.has("color")) {
+ this.color = hueLamp.getColor();
+ }
+
+ this.on = hueLamp.isOn();
+ this.lampMode = hueLamp.getLampMode();
+ this.alert = hueLamp.getAlert();
+ this.metaData = hueLamp.getMetaData();
+ this.dimming = new Dimming(jsonObject.getAsJsonObject("dimming").get("brightness").getAsNumber());
+ }
+
+ @SneakyThrows
+ @Override
+ public void updateSync(final LampUpdateType lampUpdateType, final T... t) {
+ HueLampDiscovery hueLampDiscovery = ServiceAccessor.accessService(HueLampDiscovery.class);
+
+ Constructor> constructor = lampUpdateType.getUpdateClazz().getConstructor(HueLamp.class);
+ LampUpdate lampUpdate = (LampUpdate) constructor.newInstance(this);
+
+ HueBridgeCredentials hueBridgeCredentials = getHueBridge().getHueBridgeCredentials();
+ HttpClient httpClient = HttpUtils.createClient();
+ HttpUriRequest httpRequest = HttpUtils.createPutRequest(
+ URLFormatter.getLamp(hueBridgeCredentials.getIpAddress(), this.getId()),
+ lampUpdate.getRequestBody(t),
+ createCredentialHeader(hueBridgeCredentials)
+ );
+ executeJson(httpClient, httpRequest);
+ refreshLampState();
+ }
+
+ @Override
+ public CompletableFuture updateAsync(final LampUpdateType lampUpdateType, final T... t) {
+ return CompletableFuture.runAsync(() -> updateSync(lampUpdateType, t));
+ }
+
+ @Override
+ public String getName() {
+ return this.metaData.getName();
+ }
+
+ @Override
+ public HueBridge getHueBridge() {
+ return hueBridge;
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/LampArchetype.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/LampArchetype.java
new file mode 100644
index 0000000..df6812d
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/LampArchetype.java
@@ -0,0 +1,51 @@
+package de.maxizink.lightcontroller.discovery.lamp.model;
+
+public enum LampArchetype {
+
+ UNKNOWN_ARCHETYPE,
+ CLASSIC_BULB,
+ SULTAN_BULB,
+ FLOOD_BULB,
+ /**
+ * Implemented {@link de.maxizink.lightcontroller.discovery.lamp.api.HueLamp}
+ */
+ SPOT_BULB,
+ CANDLE_BULB,
+ LUSTER_BULB,
+ PENDANT_ROUND,
+ PENDANT_LONG,
+ CEILING_ROUND,
+ CEILING_SQUARE,
+ FLOOR_SHADE,
+ FLOOR_LANTERN,
+ TABLE_SHADE,
+ RECESSED_CEILING,
+ RECESSED_FLOOR,
+ SINGLE_SPOT,
+ DOUBLE_SPOT,
+ TABLE_WASH,
+ WALL_LANTERN,
+ WALL_SHADE,
+ FLEXIBLE_LAMP,
+ GROUND_SPOT,
+ WALL_SPOT,
+ PLUG,
+ HUE_GO,
+ HUE_LIGHTSTRIP,
+ HUE_IRIS,
+ HUE_BLOOM,
+ BOLLARD,
+ WALL_WASHER,
+ HUE_PLAY,
+ VINTAGE_BULB,
+ CHRISTMAS_TREE,
+ HUE_CENTRIS,
+ HUE_LIGHTSTRIP_TV,
+ HUE_TUBE,
+ HUE_SIGNE;
+
+ public static LampArchetype getArchetype(final String value) {
+ return LampArchetype.valueOf(value.toUpperCase());
+ }
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/LampMode.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/LampMode.java
new file mode 100644
index 0000000..13a6c56
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/LampMode.java
@@ -0,0 +1,21 @@
+package de.maxizink.lightcontroller.discovery.lamp.model;
+
+public enum LampMode {
+
+ NORMAL,
+ STREAMING;
+
+ static LampMode getMode(final String mode) {
+ switch (mode.toLowerCase()) {
+ case "normal" -> {
+ return NORMAL;
+ }
+ case "streaming" -> {
+ return STREAMING;
+ }
+ }
+ return null;
+ }
+
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/LampType.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/LampType.java
new file mode 100644
index 0000000..7276237
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/LampType.java
@@ -0,0 +1,8 @@
+package de.maxizink.lightcontroller.discovery.lamp.model;
+
+public enum LampType {
+
+ COLOR,
+ NO_COLOR
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/LampUpdateType.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/LampUpdateType.java
new file mode 100644
index 0000000..9471dba
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/model/LampUpdateType.java
@@ -0,0 +1,25 @@
+package de.maxizink.lightcontroller.discovery.lamp.model;
+
+import de.maxizink.lightcontroller.discovery.lamp.api.LampUpdate;
+import de.maxizink.lightcontroller.discovery.lamp.update.BrightnessLampUpdate;
+import de.maxizink.lightcontroller.discovery.lamp.update.ColorLampUpdate;
+import de.maxizink.lightcontroller.discovery.lamp.update.ColorTemperatureLampUpdate;
+import de.maxizink.lightcontroller.discovery.lamp.update.EnabledLampUpdate;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.awt.*;
+
+@AllArgsConstructor
+@Getter
+public final class LampUpdateType {
+
+ public static final LampUpdateType COLOR = new LampUpdateType<>(ColorLampUpdate.class, Color.class);
+ public static final LampUpdateType COLOR_TEMPERATURE = new LampUpdateType<>(ColorTemperatureLampUpdate.class, Integer.class);
+ public static final LampUpdateType ENABLE = new LampUpdateType<>(EnabledLampUpdate.class, Boolean.class);
+ public static final LampUpdateType BRIGHTNESS = new LampUpdateType<>(BrightnessLampUpdate.class, Number.class);
+
+ private Class extends LampUpdate>> updateClazz;
+ private Class> type;
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/service/HueLampDiscoveryService.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/service/HueLampDiscoveryService.java
new file mode 100644
index 0000000..b7cad2c
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/service/HueLampDiscoveryService.java
@@ -0,0 +1,75 @@
+package de.maxizink.lightcontroller.discovery.lamp.service;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridge;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLamp;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLampDiscovery;
+import de.maxizink.lightcontroller.discovery.lamp.exception.HueLampDiscoveryException;
+import de.maxizink.lightcontroller.discovery.lamp.model.HueLampImpl;
+import de.maxizink.lightcontroller.utils.HttpUtils;
+import de.maxizink.lightcontroller.utils.HueResponseValidator;
+import de.maxizink.lightcontroller.utils.JsonUtils;
+import de.maxizink.lightcontroller.utils.URLFormatter;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpUriRequest;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import static de.maxizink.lightcontroller.utils.HttpUtils.*;
+
+public class HueLampDiscoveryService implements HueLampDiscovery {
+
+ @Override
+ public List discoverAllLamps(final HueBridge hueBridge) {
+ HttpClient httpClient = createClient();
+ HttpUriRequest httpRequest = createRequest(URLFormatter.getAllLamps(hueBridge.getHueBridgeCredentials().getIpAddress()),
+ HttpUtils.createCredentialHeader(hueBridge.getHueBridgeCredentials()));
+
+ String json = executeJson(httpClient, httpRequest);
+ JsonObject jsonObject = JsonUtils.fromJson(json);
+ if (HueResponseValidator.hasErrors(jsonObject)) {
+ throw new HueLampDiscoveryException("Error while fetching HueLamps");
+ }
+
+ List hueLamps = new ArrayList<>();
+ JsonArray jsonLampArray = jsonObject.getAsJsonArray("data");
+ for (JsonElement jsonElement : jsonLampArray) {
+ HueLamp hueLamp = new HueLampImpl(jsonElement.getAsJsonObject(), hueBridge);
+ hueLamps.add(hueLamp);
+ }
+
+ return hueLamps;
+ }
+
+ @Override
+ public CompletableFuture> discoverAllLampsAsync(final HueBridge hueBridge) {
+ return CompletableFuture.supplyAsync(() -> discoverAllLamps(hueBridge));
+ }
+
+ @Override
+ public JsonObject getLampObject(final HueLamp hueLamp) {
+ HueBridge hueBridge = hueLamp.getHueBridge();
+ HttpClient httpClient = createClient();
+ HttpUriRequest httpRequest = createRequest(URLFormatter.getAllLamps(hueBridge.getHueBridgeCredentials().getIpAddress()),
+ HttpUtils.createCredentialHeader(hueBridge.getHueBridgeCredentials()));
+
+ String json = executeJson(httpClient, httpRequest);
+ JsonObject jsonObject = JsonUtils.fromJson(json);
+ if (HueResponseValidator.hasErrors(jsonObject)) {
+ throw new HueLampDiscoveryException("Error while fetching HueLamps");
+ }
+
+ JsonArray jsonLampArray = jsonObject.getAsJsonArray("data");
+ for (JsonElement jsonElement : jsonLampArray) {
+ HueLamp lampImpl = new HueLampImpl(jsonElement.getAsJsonObject(), hueBridge);
+ if (lampImpl.getId().equals(hueLamp.getId())) {
+ return jsonElement.getAsJsonObject();
+ }
+ }
+ throw new IllegalArgumentException("Unknown Lamp");
+ }
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/update/BrightnessLampUpdate.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/update/BrightnessLampUpdate.java
new file mode 100644
index 0000000..308afe0
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/update/BrightnessLampUpdate.java
@@ -0,0 +1,19 @@
+package de.maxizink.lightcontroller.discovery.lamp.update;
+
+import de.maxizink.lightcontroller.body.HueRequestBody;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLamp;
+import de.maxizink.lightcontroller.discovery.lamp.api.LampUpdate;
+import de.maxizink.lightcontroller.discovery.lamp.body.HueLampBrightnessBody;
+import lombok.AllArgsConstructor;
+
+@AllArgsConstructor
+public class BrightnessLampUpdate implements LampUpdate {
+
+ private final HueLamp hueLamp;
+
+ @Override
+ public HueRequestBody getRequestBody(final Number... param) {
+ return new HueLampBrightnessBody(param[0]);
+ }
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/update/ColorLampUpdate.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/update/ColorLampUpdate.java
new file mode 100644
index 0000000..0a05b04
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/update/ColorLampUpdate.java
@@ -0,0 +1,22 @@
+package de.maxizink.lightcontroller.discovery.lamp.update;
+
+import de.maxizink.lightcontroller.body.HueRequestBody;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLamp;
+import de.maxizink.lightcontroller.discovery.lamp.api.LampUpdate;
+import de.maxizink.lightcontroller.discovery.lamp.body.HueColorBody;
+import de.maxizink.lightcontroller.utils.CIEColor;
+import lombok.AllArgsConstructor;
+
+import java.awt.*;
+
+@AllArgsConstructor
+public class ColorLampUpdate implements LampUpdate {
+
+ private final HueLamp hueLamp;
+
+ @Override
+ public HueRequestBody getRequestBody(Color... param) {
+ CIEColor color = CIEColor.converterColorToCIE(param[0]);
+ return new HueColorBody(color.getX(), color.getY());
+ }
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/update/ColorTemperatureLampUpdate.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/update/ColorTemperatureLampUpdate.java
new file mode 100644
index 0000000..a4183b6
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/update/ColorTemperatureLampUpdate.java
@@ -0,0 +1,18 @@
+package de.maxizink.lightcontroller.discovery.lamp.update;
+
+import de.maxizink.lightcontroller.body.HueRequestBody;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLamp;
+import de.maxizink.lightcontroller.discovery.lamp.api.LampUpdate;
+import de.maxizink.lightcontroller.discovery.lamp.body.HueColorTemperatureBody;
+import lombok.AllArgsConstructor;
+
+@AllArgsConstructor
+public class ColorTemperatureLampUpdate implements LampUpdate {
+
+ private final HueLamp hueLamp;
+
+ @Override
+ public HueRequestBody getRequestBody(Integer... param) {
+ return new HueColorTemperatureBody(param[0]);
+ }
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/update/EnabledLampUpdate.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/update/EnabledLampUpdate.java
new file mode 100644
index 0000000..ebfa2f2
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/lamp/update/EnabledLampUpdate.java
@@ -0,0 +1,19 @@
+package de.maxizink.lightcontroller.discovery.lamp.update;
+
+import de.maxizink.lightcontroller.body.HueRequestBody;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLamp;
+import de.maxizink.lightcontroller.discovery.lamp.api.LampUpdate;
+import de.maxizink.lightcontroller.discovery.lamp.body.HueLampEnabledBody;
+import lombok.AllArgsConstructor;
+
+@AllArgsConstructor
+public class EnabledLampUpdate implements LampUpdate {
+
+ public HueLamp hueLamp;
+
+ @Override
+ public HueRequestBody getRequestBody(final Boolean... param) {
+ return new HueLampEnabledBody(param[0]);
+ }
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/room/api/HueRoom.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/room/api/HueRoom.java
new file mode 100644
index 0000000..53a5b03
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/room/api/HueRoom.java
@@ -0,0 +1,29 @@
+package de.maxizink.lightcontroller.discovery.room.api;
+
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridge;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLamp;
+import de.maxizink.lightcontroller.discovery.lamp.model.LampUpdateType;
+import de.maxizink.lightcontroller.discovery.room.model.RoomArchetype;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface HueRoom {
+
+ void updateRoomLamps(final LampUpdateType lampUpdateType, final T... value);
+
+ void turnOn();
+
+ void turnOff();
+
+ String getName();
+
+ UUID getId();
+
+ RoomArchetype getRoomArchetype();
+
+ HueBridge getHueBridge();
+
+ List getLamps();
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/room/api/HueRoomDiscovery.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/room/api/HueRoomDiscovery.java
new file mode 100644
index 0000000..01d3241
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/room/api/HueRoomDiscovery.java
@@ -0,0 +1,18 @@
+package de.maxizink.lightcontroller.discovery.room.api;
+
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridge;
+import de.maxizink.lightcontroller.injection.Service;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+public interface HueRoomDiscovery extends Service {
+
+ Optional getHueRoomById(final HueBridge hueBridge, final UUID uniqueId);
+
+ Optional getHueRoomByName(final HueBridge hueBridge, final String name);
+
+ List discoverAllRooms(final HueBridge hueBridge);
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/room/exception/HueRoomDiscoveryException.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/room/exception/HueRoomDiscoveryException.java
new file mode 100644
index 0000000..4714e43
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/room/exception/HueRoomDiscoveryException.java
@@ -0,0 +1,9 @@
+package de.maxizink.lightcontroller.discovery.room.exception;
+
+public class HueRoomDiscoveryException extends RuntimeException {
+
+ public HueRoomDiscoveryException(final String message) {
+ super(message);
+ }
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/room/model/HueRoomImpl.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/room/model/HueRoomImpl.java
new file mode 100644
index 0000000..3f09b86
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/room/model/HueRoomImpl.java
@@ -0,0 +1,102 @@
+package de.maxizink.lightcontroller.discovery.room.model;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import de.maxizink.lightcontroller.discovery.ResourceType;
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridge;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLamp;
+import de.maxizink.lightcontroller.discovery.lamp.model.LampUpdateType;
+import de.maxizink.lightcontroller.discovery.room.api.HueRoom;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+public class HueRoomImpl implements HueRoom {
+
+ private final HueBridge hueBridge;
+ private final String roomName;
+ private final RoomArchetype roomArchetype;
+ private final UUID id;
+
+ private final List lampIDs = new ArrayList<>();
+
+ public HueRoomImpl(final JsonObject dataObject, final HueBridge hueBridge) {
+ this.hueBridge = hueBridge;
+
+ JsonObject metaDataObject = dataObject.getAsJsonObject("metadata");
+ this.roomName = metaDataObject.get("name").getAsString();
+ this.roomArchetype = RoomArchetype.getRoomArchetype(metaDataObject.get("archetype").getAsString());
+
+ this.id = UUID.fromString(dataObject.get("id").getAsString());
+
+ JsonArray jsonArray = dataObject.getAsJsonArray("services");
+ for (JsonElement jsonElement : jsonArray) {
+ JsonObject object = jsonElement.getAsJsonObject();
+ ResourceType resourceType = ResourceType.getResourceType(object.get("rtype").getAsString());
+ if (resourceType.equals(ResourceType.LIGHT)) {
+ this.lampIDs.add(UUID.fromString(object.get("rid").getAsString()));
+ }
+ }
+ }
+
+ @Override
+ public void turnOn() {
+ changeRoomStates(true);
+ }
+
+ @Override
+ public void turnOff() {
+ changeRoomStates(false);
+ }
+
+ @Override
+ public void updateRoomLamps(final LampUpdateType lampUpdateType, final T... value) {
+ getLamps().forEach(hueLamp -> hueLamp.updateSync(lampUpdateType, value));
+ }
+
+ @Override
+ public String getName() {
+ return this.roomName;
+ }
+
+ @Override
+ public UUID getId() {
+ return this.id;
+ }
+
+ @Override
+ public RoomArchetype getRoomArchetype() {
+ return this.roomArchetype;
+ }
+
+ @Override
+ public HueBridge getHueBridge() {
+ return this.hueBridge;
+ }
+
+ /**
+ * This class does not cache the HueLamps because the data of the lamps can be old
+ * when caching the lamps.
+ *
+ * @return a list of {@link HueLamp} from the {@link HueRoom}
+ */
+ @Override
+ public List getLamps() {
+ return this.lampIDs.stream()
+ .map(this.hueBridge::getLampById)
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .collect(Collectors.toList());
+ }
+
+ private void changeRoomStates(final boolean enabled) {
+ for (HueLamp lamp : getLamps()) {
+ lamp.updateSync(LampUpdateType.ENABLE, enabled);
+ }
+ }
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/room/model/RoomArchetype.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/room/model/RoomArchetype.java
new file mode 100644
index 0000000..a898246
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/room/model/RoomArchetype.java
@@ -0,0 +1,50 @@
+package de.maxizink.lightcontroller.discovery.room.model;
+
+public enum RoomArchetype {
+
+ LIVING_ROOM,
+ KITCHEN,
+ DINING,
+ BEDROOM,
+ KIDS_BEDROOM,
+ BATHROOM,
+ NURSERY,
+ RECREATION,
+ OFFICE,
+ GYM,
+ HALLWAY,
+ TOILET,
+ FRONT_DOOR,
+ GARAGE,
+ TERRACE,
+ GARDEN,
+ DRIVEWAY,
+ CARPORT,
+ HOME,
+ DOWNSTAIRS,
+ UPSTAIRS,
+ TOP_FLOOR,
+ ATTIC,
+ GUEST_ROOM,
+ STAIRCASE,
+ LOUNGE,
+ MAN_CAVE,
+ COMPUTER,
+ STUDIO,
+ MUSIC,
+ TV,
+ READING,
+ CLOSET,
+ STORAGE,
+ LAUNDRY_ROOM,
+ BALCONY,
+ PORCH,
+ BARBECUE,
+ POOL,
+ OTHER;
+
+ public static RoomArchetype getRoomArchetype(final String string) {
+ return valueOf(string.toUpperCase());
+ }
+
+ }
diff --git a/api/src/main/java/de/maxizink/lightcontroller/discovery/room/service/HueRoomDiscoveryService.java b/api/src/main/java/de/maxizink/lightcontroller/discovery/room/service/HueRoomDiscoveryService.java
new file mode 100644
index 0000000..f68caf2
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/discovery/room/service/HueRoomDiscoveryService.java
@@ -0,0 +1,60 @@
+package de.maxizink.lightcontroller.discovery.room.service;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridge;
+import de.maxizink.lightcontroller.discovery.room.api.HueRoom;
+import de.maxizink.lightcontroller.discovery.room.api.HueRoomDiscovery;
+import de.maxizink.lightcontroller.discovery.room.exception.HueRoomDiscoveryException;
+import de.maxizink.lightcontroller.discovery.room.model.HueRoomImpl;
+import de.maxizink.lightcontroller.utils.HueResponseValidator;
+import de.maxizink.lightcontroller.utils.JsonUtils;
+import de.maxizink.lightcontroller.utils.URLFormatter;
+import org.apache.http.client.methods.HttpUriRequest;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+import static de.maxizink.lightcontroller.utils.HttpUtils.*;
+
+public class HueRoomDiscoveryService implements HueRoomDiscovery {
+
+ @Override
+ public Optional getHueRoomById(final HueBridge hueBridge, final UUID uniqueId) {
+ return discoverAllRooms(hueBridge).stream()
+ .filter(hueRoom -> hueRoom.getId().equals(uniqueId))
+ .findFirst();
+ }
+
+ @Override
+ public Optional getHueRoomByName(final HueBridge hueBridge, final String name) {
+ return discoverAllRooms(hueBridge).stream()
+ .filter(hueRoom -> hueRoom.getName().equals(name))
+ .findFirst();
+ }
+
+ @Override
+ public List discoverAllRooms(final HueBridge hueBridge) {
+ HttpUriRequest httpRequest = createRequest(URLFormatter.getAllRooms(hueBridge.getHueBridgeCredentials().getIpAddress()),
+ createCredentialHeader(hueBridge.getHueBridgeCredentials()));
+
+ String json = executeJson(httpRequest);
+
+ JsonObject dataObject = JsonUtils.fromJson(executeJson(httpRequest));
+ if (HueResponseValidator.hasErrors(dataObject)) {
+ throw new HueRoomDiscoveryException("Error while discover Rooms");
+ }
+
+ List hueRooms = new ArrayList<>();
+ JsonArray jsonLampArray = dataObject.getAsJsonArray("data");
+ for (JsonElement jsonElement : jsonLampArray) {
+ HueRoom hueRoom = new HueRoomImpl(jsonElement.getAsJsonObject(), hueBridge);
+ hueRooms.add(hueRoom);
+ }
+
+ return hueRooms;
+ }
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/injection/Service.java b/api/src/main/java/de/maxizink/lightcontroller/injection/Service.java
new file mode 100644
index 0000000..7631427
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/injection/Service.java
@@ -0,0 +1,4 @@
+package de.maxizink.lightcontroller.injection;
+
+public interface Service {
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/injection/ServiceAccessor.java b/api/src/main/java/de/maxizink/lightcontroller/injection/ServiceAccessor.java
new file mode 100644
index 0000000..9d49870
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/injection/ServiceAccessor.java
@@ -0,0 +1,36 @@
+package de.maxizink.lightcontroller.injection;
+
+import de.maxizink.lightcontroller.discovery.bridge.api.BridgeCredentialsDiscovery;
+import de.maxizink.lightcontroller.discovery.bridge.api.BridgeIpDiscovery;
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridgeDiscovery;
+import de.maxizink.lightcontroller.discovery.bridge.service.BridgeCredentialsDiscoveryService;
+import de.maxizink.lightcontroller.discovery.bridge.service.BridgeIpDiscoveryService;
+import de.maxizink.lightcontroller.discovery.bridge.service.HueBridgeDiscoveryService;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLampDiscovery;
+import de.maxizink.lightcontroller.discovery.lamp.service.HueLampDiscoveryService;
+import de.maxizink.lightcontroller.discovery.room.api.HueRoomDiscovery;
+import de.maxizink.lightcontroller.discovery.room.service.HueRoomDiscoveryService;
+import de.maxizink.lightcontroller.utils.TrustEverythingUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ServiceAccessor {
+
+ private static final Map, Service> SERVICES = new HashMap<>();
+
+ static {
+ TrustEverythingUtil.trustAllSslConnectionsByDisablingCertificateVerification();
+
+ SERVICES.put(BridgeIpDiscovery.class, new BridgeIpDiscoveryService());
+ SERVICES.put(BridgeCredentialsDiscovery.class, new BridgeCredentialsDiscoveryService());
+ SERVICES.put(HueBridgeDiscovery.class, new HueBridgeDiscoveryService());
+ SERVICES.put(HueLampDiscovery.class, new HueLampDiscoveryService());
+ SERVICES.put(HueRoomDiscovery.class, new HueRoomDiscoveryService());
+ }
+
+ public static T accessService(final Class clazz) {
+ return (T) SERVICES.get(clazz);
+ }
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/mapper/CustomObjectMapper.java b/api/src/main/java/de/maxizink/lightcontroller/mapper/CustomObjectMapper.java
new file mode 100644
index 0000000..0899419
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/mapper/CustomObjectMapper.java
@@ -0,0 +1,30 @@
+package de.maxizink.lightcontroller.mapper;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class CustomObjectMapper {
+
+ public static ObjectMapper create() {
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+
+ objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
+ objectMapper.setDefaultTyping(createCustomTypeResolver());
+
+ return objectMapper;
+ }
+
+ private static CustomTypeResolver createCustomTypeResolver() {
+ CustomTypeResolver customTypeResolver = new CustomTypeResolver();
+ customTypeResolver.init(JsonTypeInfo.Id.CLASS, null);
+ customTypeResolver.inclusion(JsonTypeInfo.As.PROPERTY);
+ return customTypeResolver;
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/de/maxizink/lightcontroller/mapper/CustomTypeResolver.java b/api/src/main/java/de/maxizink/lightcontroller/mapper/CustomTypeResolver.java
new file mode 100644
index 0000000..a15c311
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/mapper/CustomTypeResolver.java
@@ -0,0 +1,17 @@
+package de.maxizink.lightcontroller.mapper;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+
+public class CustomTypeResolver extends ObjectMapper.DefaultTypeResolverBuilder {
+
+ public CustomTypeResolver() {
+ super(ObjectMapper.DefaultTyping.NON_FINAL, LaissezFaireSubTypeValidator.instance);
+ }
+
+ @Override
+ public boolean useForType(JavaType t) {
+ return !t.isContainerType() && (t.isInterface() || t.isAbstract() || t.hasGenericTypes());
+ }
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/utils/CIEColor.java b/api/src/main/java/de/maxizink/lightcontroller/utils/CIEColor.java
new file mode 100644
index 0000000..d293698
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/utils/CIEColor.java
@@ -0,0 +1,36 @@
+package de.maxizink.lightcontroller.utils;
+
+import lombok.Data;
+
+import java.awt.*;
+
+@Data
+public class CIEColor {
+
+ private final float x;
+ private final float y;
+ private final int brightness;
+
+ public static CIEColor converterColorToCIE(final Color color) {
+ float red = color.getRed();
+ float green = color.getGreen();
+ float blue = color.getBlue();
+
+ double redGamma = gamma(red);
+ double greenGama = gamma(green);
+ double blueGama = gamma(blue);
+
+ double rgbX = redGamma * 0.664511f + greenGama * 0.154324f + blueGama * 0.162028f;
+ double rgbY = redGamma * 0.283881f + greenGama * 0.668433f + blueGama * 0.047685f;
+ double rgbZ = redGamma * 0.000088f + greenGama * 0.072310f + blueGama * 0.986039f;
+
+ float x = (float) (rgbX / (rgbX + rgbY + rgbZ));
+ float y = (float) (rgbY / (rgbX + rgbY + rgbZ));
+ return new CIEColor(x, y, (int) (rgbY * 255f));
+ }
+
+ private static double gamma(float component) {
+ return (component > 0.04045f) ? Math.pow((component + 0.055f) / (1.0f + 0.055f), 2.4f) : (component / 12.92f);
+ }
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/utils/HttpUtils.java b/api/src/main/java/de/maxizink/lightcontroller/utils/HttpUtils.java
new file mode 100644
index 0000000..ac11bfb
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/utils/HttpUtils.java
@@ -0,0 +1,98 @@
+package de.maxizink.lightcontroller.utils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.maxizink.lightcontroller.body.HueRequestBody;
+import de.maxizink.lightcontroller.discovery.bridge.models.HueBridgeCredentials;
+import de.maxizink.lightcontroller.mapper.CustomObjectMapper;
+import lombok.SneakyThrows;
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.util.EntityUtils;
+
+import java.net.URI;
+
+public class HttpUtils {
+
+ private static final ObjectMapper OBJECT_MAPPER = CustomObjectMapper.create();
+
+ public static Header createCredentialHeader(final HueBridgeCredentials hueBridgeCredentials) {
+ return new BasicHeader("hue-application-key", hueBridgeCredentials.getUserName());
+ }
+
+ @SneakyThrows
+ public static String executeJson(final HttpUriRequest httpRequest) {
+ return executeJson(createClient(), httpRequest);
+ }
+
+ @SneakyThrows
+ public static String executeJson(final HttpClient httpClient, final HttpUriRequest httpRequest) {
+ HttpResponse httpResponse = httpClient.execute(httpRequest);
+ return EntityUtils.toString(httpResponse.getEntity());
+ }
+
+ public static HttpClient createClient() {
+ return HttpClients.custom()
+ .setSSLSocketFactory(new SSLConnectionSocketFactory(TrustEverythingUtil.getContext(), (hostname, session) -> true))
+ .setSSLHostnameVerifier((hostname, session) -> true)
+ .build();
+ }
+
+ public static HttpUriRequest createRequest(final URI uri) {
+ return RequestBuilder.get()
+ .setUri(uri)
+ .build();
+ }
+
+ public static HttpUriRequest createRequest(final URI uri, final Header... headers) {
+ RequestBuilder requestBuilder = RequestBuilder.get();
+ requestBuilder.setUri(uri);
+ for (Header header : headers) {
+ requestBuilder.addHeader(header);
+ }
+ return requestBuilder.build();
+ }
+
+
+ @SneakyThrows
+ public static HttpUriRequest createPostRequest(final URI uri, final HueRequestBody hueRequestBody) {
+ return RequestBuilder.post()
+ .setUri(uri)
+ .setEntity(new StringEntity(OBJECT_MAPPER.writeValueAsString(hueRequestBody)))
+ .build();
+ }
+
+ @SneakyThrows
+ public static HttpUriRequest createPostRequest(final URI uri, final HueRequestBody hueRequestBody,
+ final Header... headers) {
+ RequestBuilder requestBuilder = RequestBuilder.post()
+ .setUri(uri)
+ .setEntity(new StringEntity(OBJECT_MAPPER.writeValueAsString(hueRequestBody)));
+
+ for (Header header : headers) {
+ requestBuilder.addHeader(header);
+ }
+
+ return requestBuilder.build();
+ }
+
+ @SneakyThrows
+ public static HttpUriRequest createPutRequest(final URI uri, final HueRequestBody hueRequestBody,
+ final Header... headers) {
+ RequestBuilder requestBuilder = RequestBuilder.put()
+ .setUri(uri)
+ .setEntity(new StringEntity(OBJECT_MAPPER.writeValueAsString(hueRequestBody)));
+
+ for (Header header : headers) {
+ requestBuilder.addHeader(header);
+ }
+
+ return requestBuilder.build();
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/de/maxizink/lightcontroller/utils/HueResponseValidator.java b/api/src/main/java/de/maxizink/lightcontroller/utils/HueResponseValidator.java
new file mode 100644
index 0000000..04f5a65
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/utils/HueResponseValidator.java
@@ -0,0 +1,15 @@
+package de.maxizink.lightcontroller.utils;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+
+public class HueResponseValidator {
+
+ public static boolean hasErrors(final JsonObject jsonObject) {
+ if (!jsonObject.has("errors")) {
+ return false;
+ }
+ JsonArray errorArray = jsonObject.getAsJsonArray("errors");
+ return errorArray.size() >= 1;
+ }
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/utils/JsonUtils.java b/api/src/main/java/de/maxizink/lightcontroller/utils/JsonUtils.java
new file mode 100644
index 0000000..ada45aa
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/utils/JsonUtils.java
@@ -0,0 +1,18 @@
+package de.maxizink.lightcontroller.utils;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class JsonUtils {
+
+ public static JsonObject fromJsonArray(final String responseBody) {
+ JsonArray jsonArray = JsonParser.parseString(responseBody).getAsJsonArray();
+ return jsonArray.get(0).getAsJsonObject();
+ }
+
+ public static JsonObject fromJson(final String responseBody) {
+ return JsonParser.parseString(responseBody).getAsJsonObject();
+ }
+
+}
diff --git a/api/src/main/java/de/maxizink/lightcontroller/utils/TrustEverythingUtil.java b/api/src/main/java/de/maxizink/lightcontroller/utils/TrustEverythingUtil.java
new file mode 100644
index 0000000..efbba7f
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/utils/TrustEverythingUtil.java
@@ -0,0 +1,48 @@
+package de.maxizink.lightcontroller.utils;
+
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+
+@Slf4j
+public class TrustEverythingUtil implements X509TrustManager {
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {
+
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType) {
+
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[]{};
+ }
+
+ @SneakyThrows
+ public static void trustAllSslConnectionsByDisablingCertificateVerification() {
+ log.info("Turning off certificate verification...");
+ SSLContext sslContext = SSLContext.getInstance("SSL");
+ sslContext.init(null, new TrustManager[]{new TrustEverythingUtil()}, new SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
+ HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
+ log.info("Certificate verification has been turned off, all certificates are now accepted.");
+ }
+
+ @SneakyThrows
+ public static SSLContext getContext() {
+ SSLContext sslContext = SSLContext.getInstance("SSL");
+ sslContext.init(null, new TrustManager[]{new TrustEverythingUtil()}, new SecureRandom());
+ return sslContext;
+ }
+
+}
\ No newline at end of file
diff --git a/api/src/main/java/de/maxizink/lightcontroller/utils/URLFormatter.java b/api/src/main/java/de/maxizink/lightcontroller/utils/URLFormatter.java
new file mode 100644
index 0000000..73463b3
--- /dev/null
+++ b/api/src/main/java/de/maxizink/lightcontroller/utils/URLFormatter.java
@@ -0,0 +1,34 @@
+package de.maxizink.lightcontroller.utils;
+
+import lombok.SneakyThrows;
+
+import java.net.URI;
+import java.util.UUID;
+
+public class URLFormatter {
+
+ @SneakyThrows
+ public static URI getBridgeAPIKey(final String bridgeIp) {
+ return new URI("https://" + bridgeIp + "/api");
+ }
+
+ @SneakyThrows
+ public static URI getBridgeConfig(final String bridgeIp) {
+ return new URI("https://" + bridgeIp + "/api/config");
+ }
+
+ @SneakyThrows
+ public static URI getAllLamps(final String bridgeIp) {
+ return new URI("https://" + bridgeIp + "/clip/v2/resource/light");
+ }
+
+ @SneakyThrows
+ public static URI getLamp(final String bridgeIp, final UUID id) {
+ return new URI("https://" + bridgeIp + "/clip/v2/resource/light/" + id.toString());
+ }
+
+ @SneakyThrows
+ public static URI getAllRooms(final String bridgeIp) {
+ return new URI("https://" + bridgeIp + "/clip/v2/resource/room");
+ }
+}
diff --git a/api/src/test/java/de/maxizink/lightcontroller/SecondModuleTest.java b/api/src/test/java/de/maxizink/lightcontroller/SecondModuleTest.java
new file mode 100644
index 0000000..c4a76ed
--- /dev/null
+++ b/api/src/test/java/de/maxizink/lightcontroller/SecondModuleTest.java
@@ -0,0 +1,4 @@
+package de.maxizink.lightcontroller;
+
+public class SecondModuleTest {
+}
diff --git a/assets/light-api.png b/assets/light-api.png
new file mode 100644
index 0000000..97f6c1e
Binary files /dev/null and b/assets/light-api.png differ
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..e22f50b
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,32 @@
+plugins {
+ `java-library`
+ id("org.sonarqube") version "3.3"
+}
+
+group = "de.maxizink"
+version = "1.0-SNAPSHOT"
+
+subprojects {
+
+ apply(plugin="java")
+
+ repositories {
+ mavenCentral()
+ }
+
+ dependencies {
+ compileOnly("org.projectlombok:lombok:1.18.22")
+ annotationProcessor("org.projectlombok:lombok:1.18.20")
+ implementation("org.jetbrains:annotations:23.0.0")
+ testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
+ }
+}
+
+sonarqube {
+ properties {
+ property("sonar.projectKey", "IBims1ckoky_LightControllerAPI")
+ property("sonar.organization", "ibims1ckoky")
+ property("sonar.host.url", "https://sonarcloud.io")
+ }
+}
\ No newline at end of file
diff --git a/example/build.gradle.kts b/example/build.gradle.kts
new file mode 100644
index 0000000..9cafaab
--- /dev/null
+++ b/example/build.gradle.kts
@@ -0,0 +1,17 @@
+group = "de.maxizink"
+version = "1.0-SNAPSHOT"
+
+description = "LightController-example"
+
+plugins {
+ `java-library`
+}
+
+repositories {
+ maven("https://jitpack.io")
+}
+
+dependencies {
+ api(project(":LightControllerAPI-api"))
+ //implementation("com.github.IBims1ckoky:LightControllerAPI:master-SNAPSHOT");
+}
diff --git a/example/src/main/java/de/maxizink/lightcontroller/LightControllerExample.java b/example/src/main/java/de/maxizink/lightcontroller/LightControllerExample.java
new file mode 100644
index 0000000..db6a5f2
--- /dev/null
+++ b/example/src/main/java/de/maxizink/lightcontroller/LightControllerExample.java
@@ -0,0 +1,28 @@
+package de.maxizink.lightcontroller;
+
+import de.maxizink.lightcontroller.discovery.RoomDiscoveryExample;
+import de.maxizink.lightcontroller.discovery.bridge.api.BridgeCredentialsDiscovery;
+import de.maxizink.lightcontroller.discovery.bridge.api.BridgeIpDiscovery;
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridgeDiscovery;
+import de.maxizink.lightcontroller.injection.ServiceAccessor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class LightControllerExample {
+
+ @SneakyThrows
+ public static void main(final String[] args) {
+ //With that you can load all Services
+ BridgeIpDiscovery bridgeIpDiscovery = ServiceAccessor.accessService(BridgeIpDiscovery.class);
+ BridgeCredentialsDiscovery bridgeCredentialsDiscovery = ServiceAccessor.accessService(BridgeCredentialsDiscovery.class);
+ HueBridgeDiscovery hueBridgeDiscovery = ServiceAccessor.accessService(HueBridgeDiscovery.class);
+
+ //Run all Examples
+ //new BridgeDiscoveryExample();
+ //new LampDiscoveryExample();
+ new RoomDiscoveryExample();
+
+ //new LightControllerUsageExample();
+ }
+}
diff --git a/example/src/main/java/de/maxizink/lightcontroller/LightControllerUsageExample.java b/example/src/main/java/de/maxizink/lightcontroller/LightControllerUsageExample.java
new file mode 100644
index 0000000..0c1e452
--- /dev/null
+++ b/example/src/main/java/de/maxizink/lightcontroller/LightControllerUsageExample.java
@@ -0,0 +1,67 @@
+package de.maxizink.lightcontroller;
+
+import de.maxizink.lightcontroller.discovery.bridge.api.BridgeCredentialsDiscovery;
+import de.maxizink.lightcontroller.discovery.bridge.api.BridgeIpDiscovery;
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridge;
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridgeDiscovery;
+import de.maxizink.lightcontroller.discovery.bridge.models.HueBridgeCredentials;
+import de.maxizink.lightcontroller.discovery.bridge.response.HueBridgeCredentialsResponse;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLamp;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLampDiscovery;
+import de.maxizink.lightcontroller.discovery.lamp.model.LampUpdateType;
+import de.maxizink.lightcontroller.discovery.room.api.HueRoom;
+import de.maxizink.lightcontroller.injection.ServiceAccessor;
+
+import java.util.List;
+
+public class LightControllerUsageExample {
+
+ public LightControllerUsageExample() {
+ BridgeIpDiscovery bridgeIpDiscovery = ServiceAccessor.accessService(BridgeIpDiscovery.class);
+ BridgeCredentialsDiscovery bridgeCredentialsDiscovery = ServiceAccessor.accessService(BridgeCredentialsDiscovery.class);
+ HueBridgeDiscovery hueBridgeDiscovery = ServiceAccessor.accessService(HueBridgeDiscovery.class);
+ HueLampDiscovery hueLampDiscovery = ServiceAccessor.accessService(HueLampDiscovery.class);
+
+
+ String bridgeIp = bridgeIpDiscovery.discoverBridgeIP();
+ HueBridgeCredentials hueBridgeCredentials = getCredentials(bridgeIp);
+ HueBridge hueBridge = hueBridgeDiscovery.discoverHueBridge(hueBridgeCredentials);
+
+ List allHueLampsFromBridge = hueBridge.getLamps();
+ //or
+ List allHueLampsFromService = hueLampDiscovery.discoverAllLamps(hueBridge);
+
+ hueBridge.getLampByName("Max Bett").ifPresent(hueLamp -> {
+ hueLamp.updateSync(LampUpdateType.ENABLE, true); //Set Enabled to true
+ hueLamp.updateSync(LampUpdateType.BRIGHTNESS, 50); //Set the Brightness to 50%
+ });
+
+ List allRooms = hueBridge.getRooms();
+
+ hueBridge.getHueRoomByName("Max Zimmer").ifPresent(hueRoom -> {
+
+ });
+ }
+
+ private HueBridgeCredentials getCredentials(final String bridgeIp) {
+ BridgeCredentialsDiscovery bridgeCredentialsDiscovery = ServiceAccessor.accessService(BridgeCredentialsDiscovery.class);
+
+
+
+
+
+
+ HueBridgeCredentials hueBridgeCredentials = new HueBridgeCredentials(
+ "", // This is for testing hard coded
+ "", // This for testing hard coded
+ bridgeIp
+ );
+
+ HueBridgeCredentialsResponse other = bridgeCredentialsDiscovery.generateHueBridgeCredentials(bridgeIp);
+ if (other.getRespone().equals(HueBridgeCredentialsResponse.Respone.GENERATED)) {
+ return other.getHueBridgeCredentials();
+ }
+ return hueBridgeCredentials;
+ }
+
+}
diff --git a/example/src/main/java/de/maxizink/lightcontroller/discovery/BridgeDiscoveryExample.java b/example/src/main/java/de/maxizink/lightcontroller/discovery/BridgeDiscoveryExample.java
new file mode 100644
index 0000000..275c280
--- /dev/null
+++ b/example/src/main/java/de/maxizink/lightcontroller/discovery/BridgeDiscoveryExample.java
@@ -0,0 +1,84 @@
+package de.maxizink.lightcontroller.discovery;
+
+import de.maxizink.lightcontroller.discovery.bridge.api.BridgeCredentialsDiscovery;
+import de.maxizink.lightcontroller.discovery.bridge.api.BridgeIpDiscovery;
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridge;
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridgeDiscovery;
+import de.maxizink.lightcontroller.discovery.bridge.models.BridgeInfo;
+import de.maxizink.lightcontroller.discovery.bridge.models.HueBridgeCredentials;
+import de.maxizink.lightcontroller.discovery.bridge.response.HueBridgeCredentialsResponse;
+import de.maxizink.lightcontroller.injection.ServiceAccessor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+
+@Slf4j
+public class BridgeDiscoveryExample {
+
+
+ public BridgeDiscoveryExample() {
+ //discoverBridgeIP(); //This shows all Methods to get the BridgeIP
+ //createHueBridgeCredentials(); //This should create an API Key
+ //getHueBridgeFromExistingKey(); //This should create a HueBridge Class
+ }
+
+ /**
+ * This shows the Methods from the {@link BridgeIpDiscovery} to get the BridgeIP(s).
+ */
+ @SneakyThrows
+ private void discoverBridgeIP() {
+ BridgeIpDiscovery bridgeIpDiscovery = ServiceAccessor.accessService(BridgeIpDiscovery.class);
+
+ String bridgeIp = bridgeIpDiscovery.discoverBridgeIP(); //Sync
+ List bridgeIps = bridgeIpDiscovery.discoverAllBridgeIPs(); //Sync
+
+ String asyncBridgeIp = bridgeIpDiscovery.discoveryBridgeIPAsync().get(); //Async
+ List asyncBridgeIps = bridgeIpDiscovery.discoverAllBridgeIPsAsync().get(); //Async
+ }
+
+ /**
+ * This shows the Methods from the {@link BridgeCredentialsDiscovery} to generate{@link HueBridgeCredentials} for a BridgeIP.
+ */
+ @SneakyThrows
+ private void createHueBridgeCredentials() {
+ BridgeIpDiscovery bridgeIpDiscovery = ServiceAccessor.accessService(BridgeIpDiscovery.class);
+ BridgeCredentialsDiscovery bridgeCredentialsDiscovery = ServiceAccessor.accessService(BridgeCredentialsDiscovery.class);
+ String bridgeIp = bridgeIpDiscovery.discoverBridgeIP();
+
+ HueBridgeCredentialsResponse keyGenerateResponse = bridgeCredentialsDiscovery.generateHueBridgeCredentials(bridgeIp);
+ if (keyGenerateResponse.getRespone().equals(HueBridgeCredentialsResponse.Respone.LINK_BUTTON_NOT_PRESSED)) {
+ //Handle here what should happen if the link button was not pressed
+ //INFO: The getCredentials() Method returns null and throws an error!
+ log.info("No Credentials generated! Press the Link Button");
+ }
+
+ if (keyGenerateResponse.getRespone().equals(HueBridgeCredentialsResponse.Respone.GENERATED)) {
+ HueBridgeCredentials hueBridgeCredentials = keyGenerateResponse.getHueBridgeCredentials();
+ //Do Stuff here you want if the Credentials were generated!
+ log.info("Credentials were generated:");
+ log.info(" - UserName -> " + hueBridgeCredentials.getUserName());
+ log.info(" - ClientKey -> " + hueBridgeCredentials.getClientKey());
+ }
+ }
+
+
+ @SneakyThrows
+ private void getHueBridgeFromExistingKey() {
+ BridgeIpDiscovery bridgeIpDiscovery = ServiceAccessor.accessService(BridgeIpDiscovery.class);
+ BridgeCredentialsDiscovery bridgeCredentialsDiscovery = ServiceAccessor.accessService(BridgeCredentialsDiscovery.class);
+ HueBridgeDiscovery hueBridgeDiscovery = ServiceAccessor.accessService(HueBridgeDiscovery.class);
+
+ String bridgeIp = bridgeIpDiscovery.discoverBridgeIP();
+ HueBridgeCredentialsResponse hueBridgeCredentials = bridgeCredentialsDiscovery.generateHueBridgeCredentials(bridgeIp);
+ if (hueBridgeCredentials.getRespone().equals(HueBridgeCredentialsResponse.Respone.LINK_BUTTON_NOT_PRESSED)) {
+ // Credentials could not created
+ return;
+ }
+
+ HueBridge hueBridge = hueBridgeDiscovery.discoverHueBridge(hueBridgeCredentials.getHueBridgeCredentials());
+ BridgeInfo bridgeInfo = hueBridge.getBridgeInfo();
+ log.info("Bridge MAC-Adress: " + bridgeInfo.getMac());
+ }
+
+}
diff --git a/example/src/main/java/de/maxizink/lightcontroller/discovery/LampDiscoveryExample.java b/example/src/main/java/de/maxizink/lightcontroller/discovery/LampDiscoveryExample.java
new file mode 100644
index 0000000..362f72f
--- /dev/null
+++ b/example/src/main/java/de/maxizink/lightcontroller/discovery/LampDiscoveryExample.java
@@ -0,0 +1,80 @@
+package de.maxizink.lightcontroller.discovery;
+
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridge;
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridgeDiscovery;
+import de.maxizink.lightcontroller.discovery.bridge.models.HueBridgeCredentials;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLamp;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLampDiscovery;
+import de.maxizink.lightcontroller.discovery.lamp.model.HueColor;
+import de.maxizink.lightcontroller.discovery.lamp.model.LampUpdateType;
+import de.maxizink.lightcontroller.injection.ServiceAccessor;
+import lombok.SneakyThrows;
+
+import java.awt.*;
+import java.util.List;
+import java.util.Optional;
+
+public class LampDiscoveryExample {
+
+ public LampDiscoveryExample() {
+ doLightInfo();
+ }
+
+ private void doLightInfo() {
+ HueBridgeDiscovery hueBridgeDiscovery = ServiceAccessor.accessService(HueBridgeDiscovery.class);
+ HueLampDiscovery hueLampDiscovery = ServiceAccessor.accessService(HueLampDiscovery.class);
+
+ HueBridgeCredentials hueBridgeCredentials = new HueBridgeCredentials(
+ "name",
+ "key",
+ ""
+ );
+
+ HueBridge hueBridge = hueBridgeDiscovery.discoverHueBridge(hueBridgeCredentials);
+ //syncLamps(hueBridge);
+ //asyncLamps(hueBridge);
+ //updateLamp(hueBridge);
+ byName(hueBridge);
+ }
+
+ private void byName(HueBridge hueBridge) {
+ Optional optionalHueLamp = hueBridge.getLampByName("My Lamp");
+ optionalHueLamp.ifPresent(hueLamp -> {
+ hueLamp.getId();
+ hueLamp.getName();
+ });
+ }
+
+ private void updateLamp(final HueBridge hueBridge) {
+ HueLamp hueLamp = hueBridge.getLampByName("Max Bett").get();
+ hueLamp.updateSync(LampUpdateType.COLOR, Color.ORANGE);
+ hueLamp.updateSync(LampUpdateType.BRIGHTNESS, 100);
+ hueLamp.updateSync(LampUpdateType.COLOR_TEMPERATURE, 500);
+ hueLamp.updateAsync(LampUpdateType.ENABLE, true).join();
+ }
+
+ private void syncLamps(final HueBridge hueBridge) {
+ Optional optionalHueLamp = hueBridge.getLampByName("My Lamp");
+ List hueLamps = hueBridge.getLamps();
+
+ hueLamps.forEach(hueLamp -> {
+ //Sync Lamps
+ hueLamp.getId();
+ hueLamp.getName();
+ });
+ }
+
+ @SneakyThrows
+ private void asyncLamps(final HueBridge hueBridge) {
+ HueLampDiscovery hueLampDiscovery = ServiceAccessor.accessService(HueLampDiscovery.class);
+ List hueLamps = hueLampDiscovery.discoverAllLampsAsync(hueBridge).get();
+
+ hueLamps.forEach(hueLamp -> {
+ //Sync Lamps
+ hueLamp.getId();
+ hueLamp.getName();
+ });
+ }
+
+
+}
diff --git a/example/src/main/java/de/maxizink/lightcontroller/discovery/RoomDiscoveryExample.java b/example/src/main/java/de/maxizink/lightcontroller/discovery/RoomDiscoveryExample.java
new file mode 100644
index 0000000..1a34328
--- /dev/null
+++ b/example/src/main/java/de/maxizink/lightcontroller/discovery/RoomDiscoveryExample.java
@@ -0,0 +1,50 @@
+package de.maxizink.lightcontroller.discovery;
+
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridge;
+import de.maxizink.lightcontroller.discovery.bridge.api.HueBridgeDiscovery;
+import de.maxizink.lightcontroller.discovery.bridge.models.HueBridgeCredentials;
+import de.maxizink.lightcontroller.discovery.lamp.api.HueLamp;
+import de.maxizink.lightcontroller.discovery.lamp.model.LampUpdateType;
+import de.maxizink.lightcontroller.discovery.room.api.HueRoom;
+import de.maxizink.lightcontroller.discovery.room.api.HueRoomDiscovery;
+import de.maxizink.lightcontroller.injection.ServiceAccessor;
+
+import java.awt.*;
+import java.util.List;
+
+public class RoomDiscoveryExample {
+
+ public RoomDiscoveryExample() {
+ discoverAllRooms();
+ }
+
+ private void discoverAllRooms() {
+ HueBridgeDiscovery hueBridgeDiscovery = ServiceAccessor.accessService(HueBridgeDiscovery.class);
+ HueRoomDiscovery hueRoomDiscovery = ServiceAccessor.accessService(HueRoomDiscovery.class);
+
+ HueBridgeCredentials hueBridgeCredentials = new HueBridgeCredentials(
+ "", // This is for testing hard coded
+ "", // This for testing hard coded
+ ""
+ );
+
+ HueBridge hueBridge = hueBridgeDiscovery.discoverHueBridge(hueBridgeCredentials);
+ List hueRooms = hueRoomDiscovery.discoverAllRooms(hueBridge); //get all rooms by service
+
+ //get room by
+ hueRoomDiscovery.getHueRoomByName(hueBridge, "Max Zimmer").ifPresent(hueRoom -> {
+ hueRoom.getName();
+ hueRoom.getRoomArchetype();
+ hueRoom.turnOff();
+
+ hueRoom.updateRoomLamps(LampUpdateType.COLOR, Color.GREEN);
+ hueRoom.updateRoomLamps(LampUpdateType.BRIGHTNESS, 10);
+
+ for (HueLamp lamp : hueRoom.getLamps()) {
+ lamp.getName();
+ lamp.getId();
+ }
+ });
+ }
+
+}
diff --git a/example/src/test/java/de/maxizink/lightcontroller/SecondModuleTest.java b/example/src/test/java/de/maxizink/lightcontroller/SecondModuleTest.java
new file mode 100644
index 0000000..c4a76ed
--- /dev/null
+++ b/example/src/test/java/de/maxizink/lightcontroller/SecondModuleTest.java
@@ -0,0 +1,4 @@
+package de.maxizink.lightcontroller;
+
+public class SecondModuleTest {
+}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..2e6e589
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..4f906e0
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..3e8833f
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,7 @@
+rootProject.name = "LightControllerAPI"
+
+include("LightControllerAPI-example")
+project(":LightControllerAPI-example").projectDir = file("example")
+
+include("LightControllerAPI-api")
+project(":LightControllerAPI-api").projectDir = file("api")