Skip to content

Commit

Permalink
merge develop
Browse files Browse the repository at this point in the history
  • Loading branch information
dvdgeisler committed Nov 25, 2022
2 parents 7d0dc9e + 738e26f commit 638f9f4
Show file tree
Hide file tree
Showing 56 changed files with 479 additions and 238 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,17 @@ jobs:

steps:
- uses: actions/checkout@v3

- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: maven

- name: Build with Maven
run: mvn -B package --file pom.xml
run: mvn -B package --file pom.xml
- uses: actions/upload-artifact@v3
with:
name: dirigera-client
path: ./**/*.jar
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ barely tested, and some are known as inoperable.
* Remote Control N2
* TRADFRI on/off switch
* TRADFRI remote control
* LEPTITER Recessed spot light
* Sound-Controller
* SYMFONISK Sound Controller
* Blinds-Controller
Expand Down Expand Up @@ -113,18 +114,17 @@ java -jar ./dirigera-client-dump/target/dirigera-client-dump-0.0.1-SNAPSHOT.jar
## Integration to Home Assistant

Lights and sockets can be integrated into Home Assistant via MQTT (more devices will follow).
Therefore, the application [dirigera-client-mqtt](dirigera-client-mqtt/src/main/java/de/dvdgeisler/iot/dirigera/client/mqtt/DirigeraClientMqttApplication.java)
is started as a service giving the hostnames of the Dirigera, and the MQTT broker, e.g.:
```bash
./mvnw package
java -jar dirigera-client-mqtt/target/dirigera-client-mqtt-0.0.1-SNAPSHOT.jar \
--dirigera.hostname=<DIRIGERA-IP-ADDRESS> \
--dirigera.mqtt.hostname=<MQTT-IP-ADDRESS (Default: localhost)> \
--dirigera.mqtt.port=<MQTT-PORT (Default: 1883)>
```
Home Assistant will create entities for supported devices, based on its MQTT auto discovery approach.

![](./img/hass-integration.png)
Add https://github.com/TheMrBooyah/hassio-repository to your home assistant.
Update the configuration to your setup.

In order to get your 'Token', run the [Dump Application](dirigera-client-dump/src/main/java/de/dvdgeisler/iot/dirigera/client/dump/DumpApplication.java). This will ask you to pair your gateway. After successfully pairing the gateway a file 'dirigera_access_token' will be created. Open the file with your favourite text editor and copy everything into the 'Token' field.

Start the addon, watch the logs for any errors and if everything went as expected, home assistant should have some new devices/entities from your IKEA Smart Hub.


![](img/hass-integration.png)

## Other repos to dig in

Expand Down
4 changes: 4 additions & 0 deletions dirigera-client-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,8 @@
<scope>test</scope>
</dependency>
</dependencies>

<build>
<finalName>dirigera-client-api</finalName>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@
import de.dvdgeisler.iot.dirigera.client.api.http.ClientApi;
import de.dvdgeisler.iot.dirigera.client.api.model.device.Device;
import de.dvdgeisler.iot.dirigera.client.api.model.device.airpurifier.*;
import de.dvdgeisler.iot.dirigera.client.api.model.device.light.*;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.List;

public class AirPurifierDeviceApi extends DefaultDeviceApi<
AirPurifierStateAttributes,
AirPurifierAttributes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
import de.dvdgeisler.iot.dirigera.client.api.http.ClientDeviceSetApi;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.DeviceSet;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.DeviceSetAttributes;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.Room;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.RoomAttributes;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package de.dvdgeisler.iot.dirigera.client.api;

import de.dvdgeisler.iot.dirigera.client.api.http.ClientApi;
import de.dvdgeisler.iot.dirigera.client.api.http.ClientRoomApi;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.Room;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.RoomAttributes;
import reactor.core.publisher.Mono;
import reactor.util.retry.Retry;

import java.time.Duration;
import java.util.List;

public class RoomApi {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import de.dvdgeisler.iot.dirigera.client.api.model.scene.Scene;
import de.dvdgeisler.iot.dirigera.client.api.model.scene.SceneAttributes;
import de.dvdgeisler.iot.dirigera.client.api.model.scene.SceneInfo;
import de.dvdgeisler.iot.dirigera.client.api.model.scene.SceneTrigger;
import reactor.core.publisher.Mono;

import java.util.List;
Expand All @@ -26,7 +27,7 @@ public Mono<Scene> refresh(final Scene scene) {
public Mono<Scene> create(final String name, final String icon) {
return this.clientApi.scene.createScene(new SceneAttributes(
new SceneInfo(name, icon), List.of(), List.of()))
.flatMap(id -> this.clientApi.scene.getScene(id.id));
.flatMap(id -> this.clientApi.scene.getScene(id.id).retry(10));
}

public Mono<Void> delete(final Scene scene) {
Expand All @@ -38,4 +39,10 @@ public Mono<Scene> update(final Scene scene, final String name, final String ico
.thenReturn(scene)
.flatMap(this::refresh);
}

public Mono<Scene> setTrigger(final Scene scene, final List<SceneTrigger> triggers) {
return this.clientApi.scene.updateScene(scene.id, new SceneAttributes(scene.attributes.info, triggers, List.of()))
.thenReturn(scene)
.flatMap(this::refresh);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,30 @@
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.socket.client.WebSocketClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;

import javax.net.ssl.SSLException;

public abstract class AbstractClientApi {

protected final SslContext sslContext;
protected final HttpClient httpClient;
protected final WebClient webClient;
protected final TokenStore tokenStore;

public AbstractClientApi(final String baseUrl, final TokenStore tokenStore) throws SSLException {
final SslContext sslContext;
final HttpClient httpClient;

sslContext = SslContextBuilder
this.sslContext = SslContextBuilder
.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.build();
httpClient = HttpClient.create().secure(t -> t.sslContext(sslContext));
this.httpClient = HttpClient.create().secure(t -> t.sslContext(this.sslContext));

this.webClient = WebClient
.builder()
.baseUrl(baseUrl)
.clientConnector(new ReactorClientHttpConnector(httpClient))
.clientConnector(new ReactorClientHttpConnector(this.httpClient))
.build();
this.tokenStore = tokenStore;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,27 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient;
import org.springframework.web.reactive.socket.client.WebSocketClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;

import javax.net.ssl.SSLException;
import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.function.Consumer;

@Component
public class ClientApi extends AbstractClientApi {
private final static Logger log = LoggerFactory.getLogger(ClientApi.class);
private final String hostname;
private final short port;

public final ClientDeviceApi device;
public final ClientDeviceSetApi deviceSet;
Expand Down Expand Up @@ -43,6 +53,8 @@ public ClientApi(
final ClientUserApi user
) throws SSLException {
super(String.format("https://%s:%d/v1/", hostname, port), tokenStore);
this.hostname = hostname;
this.port = port;
this.device = device;
this.deviceSet = deviceSet;
this.gateway = gateway;
Expand Down Expand Up @@ -77,4 +89,32 @@ public Mono<Map> dump() {
.bodyToMono(Map.class);
}

public Mono<Void> websocket(final Consumer<String> consumer) {
final String token;
final String authorizationHeader;
final HttpClient httpClient;
final WebSocketClient client;



try {
token = this.tokenStore.getAccessToken();
authorizationHeader = String.format("Bearer %s", token);
httpClient = this.httpClient
.headers(headers -> headers.add(HttpHeaders.AUTHORIZATION, authorizationHeader))
.keepAlive(true);
client = new ReactorNettyWebSocketClient(httpClient);
return client.execute(URI.create(String.format("https://%s:%d/v1/", this.hostname, this.port)), session ->
session.receive()
.map(WebSocketMessage::getPayloadAsText)
.doOnNext(consumer)
.repeat()
.then()
);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}


Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package de.dvdgeisler.iot.dirigera.client.api.model.device;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonUnwrapped;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class DeviceStateCommand<_Attributes extends DeviceStateAttributes> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.fasterxml.jackson.annotation.JsonUnwrapped;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceAttributes;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceStartupMode;
import de.dvdgeisler.iot.dirigera.client.api.model.device.ota.OtaAttributes;

import java.time.LocalDateTime;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package de.dvdgeisler.iot.dirigera.client.api.model.device.gateway;

import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCapabilities;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.DeviceSet;
import de.dvdgeisler.iot.dirigera.client.api.model.device.Device;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCategory;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

@JsonInclude(JsonInclude.Include.NON_NULL)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,18 @@ public class LightColorAttributes {
public Float saturation;
@JsonProperty("colorTemperature")
public Integer temperature;

/**
* The minimal color temperature in Kelvin.
* @implNote higher Kelvin indicates lower color temperature
*/
@JsonProperty("colorTemperatureMin")
public Integer temperatureMin;

/**
* The maximal color temperature in Kelvin.
* @implNote lower Kelvin indicates higher color temperature
*/
@JsonProperty("colorTemperatureMax")
public Integer temperatureMax;
@JsonProperty("colorMode")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package de.dvdgeisler.iot.dirigera.client.api.model.device.light;

import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceConfigurationAttributes;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceConfigurationDefaultAttributes;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.DeviceSet;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.Room;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package de.dvdgeisler.iot.dirigera.client.api.model.device.light;

import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCapabilities;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.DeviceSet;
import de.dvdgeisler.iot.dirigera.client.api.model.device.Device;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCategory;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import de.dvdgeisler.iot.dirigera.client.api.model.device.Device;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCapabilities;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.DeviceSet;

import java.time.LocalDateTime;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package de.dvdgeisler.iot.dirigera.client.api.model.device.motionsensor;

import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceConfigurationCommand;
import de.dvdgeisler.iot.dirigera.client.api.model.device.light.LightConfigurationAttributes;

public class MotionSensorConfigurationCommand extends DeviceConfigurationCommand<MotionSensorConfigurationAttributes> {
public MotionSensorConfigurationCommand(final MotionSensorConfigurationAttributes attributes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@

import de.dvdgeisler.iot.dirigera.client.api.model.device.Device;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCapabilities;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCategory;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceType;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.DeviceSet;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.Room;

import java.time.LocalDateTime;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceAttributes;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceStartupMode;
import de.dvdgeisler.iot.dirigera.client.api.model.device.ota.OtaAttributes;
import de.dvdgeisler.iot.dirigera.client.api.model.device.soundcontroller.SoundControllerStateAttributes;

import java.time.LocalDateTime;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCapabilities;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCategory;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceType;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.DeviceSet;

import java.time.LocalDateTime;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package de.dvdgeisler.iot.dirigera.client.api.model.device.outlet;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceStateAttributes;
import de.dvdgeisler.iot.dirigera.client.api.model.device.light.LightColorAttributes;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class OutletStateAttributes extends DeviceStateAttributes {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCapabilities;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCategory;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceType;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.DeviceSet;

import java.time.LocalDateTime;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import de.dvdgeisler.iot.dirigera.client.api.model.device.Device;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCapabilities;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.DeviceSet;

import java.time.LocalDateTime;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@

import de.dvdgeisler.iot.dirigera.client.api.model.device.Device;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCapabilities;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceCategory;
import de.dvdgeisler.iot.dirigera.client.api.model.device.DeviceType;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.DeviceSet;
import de.dvdgeisler.iot.dirigera.client.api.model.deviceset.Room;

import java.time.LocalDateTime;
import java.util.List;
Expand Down
Loading

0 comments on commit 638f9f4

Please sign in to comment.