-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #57 from dvdgeisler/develop
Develop
- Loading branch information
Showing
27 changed files
with
1,066 additions
and
976 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletions
2
...pi/src/main/java/de/dvdgeisler/iot/dirigera/client/api/model/device/DeviceAttributes.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
154 changes: 98 additions & 56 deletions
154
...t/src/main/java/de/dvdgeisler/iot/dirigera/client/mqtt/DirigeraClientMqttApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,80 +1,122 @@ | ||
package de.dvdgeisler.iot.dirigera.client.mqtt; | ||
|
||
import de.dvdgeisler.iot.dirigera.client.api.DirigeraApi; | ||
import de.dvdgeisler.iot.dirigera.client.api.model.device.Device; | ||
import de.dvdgeisler.iot.dirigera.client.api.model.device.light.LightDevice; | ||
import de.dvdgeisler.iot.dirigera.client.api.model.device.motionsensor.MotionSensorDevice; | ||
import de.dvdgeisler.iot.dirigera.client.api.model.device.outlet.OutletDevice; | ||
import de.dvdgeisler.iot.dirigera.client.mqtt.hass.LightEventHandler; | ||
import de.dvdgeisler.iot.dirigera.client.mqtt.hass.MotionSensorEventHandler; | ||
import de.dvdgeisler.iot.dirigera.client.mqtt.hass.OutletEventHandler; | ||
import de.dvdgeisler.iot.dirigera.client.mqtt.hass.HassLightDeviceEventHandler; | ||
import de.dvdgeisler.iot.dirigera.client.mqtt.hass.HassMotionSensorDeviceEventHandler; | ||
import de.dvdgeisler.iot.dirigera.client.mqtt.hass.HassOutletDeviceEventHandler; | ||
import org.eclipse.paho.client.mqttv3.*; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.boot.CommandLineRunner; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
import org.springframework.context.ConfigurableApplicationContext; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.ComponentScan; | ||
import reactor.core.publisher.Flux; | ||
|
||
import java.time.Duration; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
@SpringBootApplication | ||
@ComponentScan(basePackageClasses = {DirigeraApi.class, MqttBridge.class}) | ||
@ComponentScan(basePackageClasses = { | ||
DirigeraApi.class, | ||
HassLightDeviceEventHandler.class, | ||
HassMotionSensorDeviceEventHandler.class, | ||
HassOutletDeviceEventHandler.class}) | ||
public class DirigeraClientMqttApplication { | ||
private final static Logger log = LoggerFactory.getLogger(DirigeraClientMqttApplication.class); | ||
|
||
final MqttBridge mqttBridge; | ||
final HashMap<String, Device> devices; | ||
private final static int EXIT_SUCCESS = 0; | ||
private final static int EXIT_ERROR = 1; | ||
private final DirigeraApi api; | ||
private final ConfigurableApplicationContext context; | ||
|
||
public DirigeraClientMqttApplication(final MqttBridge mqttBridge) { | ||
this.mqttBridge = mqttBridge; | ||
this.devices = new HashMap<>(); | ||
public DirigeraClientMqttApplication( | ||
final DirigeraApi api, | ||
final ConfigurableApplicationContext context) { | ||
this.api = api; | ||
this.context = context; | ||
} | ||
|
||
@Bean | ||
public CommandLineRunner run( | ||
final DirigeraApi api, | ||
final LightEventHandler lightEventHandler, | ||
final OutletEventHandler outletEventHandler, | ||
final MotionSensorEventHandler motionSensorEventHandler) { | ||
return (String... args) -> { | ||
|
||
api.pairIfRequired().block(); | ||
|
||
this.mqttBridge.registerEventHandler(LightDevice.class, lightEventHandler); | ||
this.mqttBridge.registerEventHandler(OutletDevice.class, outletEventHandler); | ||
this.mqttBridge.registerEventHandler(MotionSensorDevice.class, motionSensorEventHandler); | ||
|
||
api.device.all() | ||
.flatMapMany(Flux::fromIterable) | ||
.doOnNext(device -> { | ||
if(!this.devices.containsKey(device.id)) | ||
this.mqttBridge.addDevice(device); | ||
}) | ||
.doOnNext(this.mqttBridge::updateDevice) | ||
.doOnNext(device -> this.devices.put(device.id, device)) | ||
.collectMap(device -> device.id) | ||
.map(devices -> this.devices | ||
.entrySet() | ||
.stream() | ||
.filter(deviceEntry -> !devices.containsKey(deviceEntry.getKey())) | ||
.map(Map.Entry::getValue) | ||
.toList()) | ||
.flatMapMany(Flux::fromIterable) | ||
.doOnNext(this.mqttBridge::removeDevice) | ||
.doOnNext(device -> this.devices.remove(device.id)) | ||
.collectList() | ||
.delayElement(Duration.ofMillis(100)) | ||
.repeat() | ||
.blockLast(); | ||
}; | ||
public MqttClient getMqttClient(@Value("${dirigera.mqtt.hostname:localhost}") final String host, | ||
@Value("${dirigera.mqtt.port:1883}") final Short port, | ||
@Value("${dirigera.mqtt.username:}") final String username, | ||
@Value("${dirigera.mqtt.password:}") final String password, | ||
@Value("${dirigera.mqtt.reconnect:true}") final Boolean reconnect, | ||
@Value("${dirigera.mqtt.timeout:0}") final Integer timeout, | ||
@Value("${dirigera.mqtt.keep-alive:2}") final Integer keepAliveInterval, | ||
@Value("${dirigera.mqtt.reconnect-delay:1}") final Integer reconnectDelay, | ||
final DirigeraApi api) throws MqttException { | ||
final MqttConnectOptions options; | ||
final MqttClient client; | ||
final String publisherId; | ||
final String uri; | ||
|
||
api.pairIfRequired().block(); | ||
publisherId = api.status().map(s -> s.id).block(); | ||
uri = String.format("tcp://%s:%d", host, port); | ||
client = new MqttClient(uri, publisherId); | ||
|
||
log.info("Connect to MQTT broker: host={}, port={}, publisherId={}, reconnect={}, timeout={}", | ||
host, port, publisherId, reconnect, timeout); | ||
|
||
options = new MqttConnectOptions(); | ||
options.setKeepAliveInterval(keepAliveInterval); | ||
options.setMaxReconnectDelay(reconnectDelay); | ||
options.setAutomaticReconnect(reconnect); | ||
//options.setCleanSession(true); | ||
options.setConnectionTimeout(timeout); | ||
|
||
if (!username.isEmpty() && !password.isEmpty()) { | ||
options.setUserName(username); | ||
options.setPassword(password.toCharArray()); | ||
} | ||
client.setCallback(new MqttCallback() { | ||
@Override | ||
public void connectionLost(final Throwable cause) { | ||
log.error("Connection lost to MQTT broker: {}", cause.getMessage()); | ||
exit(EXIT_ERROR); | ||
} | ||
|
||
@Override | ||
public void messageArrived(final String topic, final MqttMessage message) { | ||
} | ||
|
||
@Override | ||
public void deliveryComplete(final IMqttDeliveryToken token) { | ||
} | ||
}); | ||
|
||
try { | ||
client.connect(options); | ||
} catch (MqttException e) { | ||
log.error("Error while connecting to MQTT broker: {}", e.getMessage()); | ||
this.exit(EXIT_ERROR); | ||
} | ||
|
||
log.info("Connection to MQTT broker successfully established"); | ||
|
||
return client; | ||
} | ||
|
||
public static void main(String[] args) { | ||
SpringApplication.run(DirigeraClientMqttApplication.class, args).close(); | ||
SpringApplication.run(DirigeraClientMqttApplication.class, args); | ||
} | ||
|
||
public void exit(int status) { | ||
|
||
try { | ||
log.info("Close WebSocket"); | ||
this.api.websocket.stop(); | ||
} catch (InterruptedException e) { | ||
log.error(e.getMessage()); | ||
} | ||
|
||
if (context != null) { | ||
log.info("Close Spring Boot context"); | ||
this.context.close(); | ||
} | ||
|
||
log.info("Exit application"); | ||
Runtime.getRuntime().halt(status); | ||
} | ||
|
||
} |
Oops, something went wrong.