Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

import javafx.stage.Stage;
import javafx.stage.WindowEvent;

import org.apache.commons.lang3.StringUtils;
import org.kabieror.elwasys.common.*;
import org.kabieror.elwasys.raspiclient.configuration.LocationManager;
import org.kabieror.elwasys.raspiclient.configuration.WashguardConfiguration;
import org.kabieror.elwasys.raspiclient.devices.deconz.DeconzDevicePowerManager;
import org.kabieror.elwasys.raspiclient.devices.FhemDevicePowerManager;
import org.kabieror.elwasys.raspiclient.devices.IDevicePowerManager;
import org.kabieror.elwasys.raspiclient.devices.IDeviceRegistrationService;
import org.kabieror.elwasys.raspiclient.devices.deconz.DeconzApiAdapter;
import org.kabieror.elwasys.raspiclient.devices.deconz.DeconzDevicePowerManager;
import org.kabieror.elwasys.raspiclient.devices.deconz.DeconzEventListener;
import org.kabieror.elwasys.raspiclient.devices.deconz.DeconzRegistrationService;
import org.kabieror.elwasys.raspiclient.executions.ExecutionManager;
import org.kabieror.elwasys.raspiclient.executions.FhemException;
import org.kabieror.elwasys.raspiclient.io.CardReader;
Expand Down Expand Up @@ -67,6 +70,8 @@ public class ElwaManager {
*/
private IDevicePowerManager devicePowerManager;

private IDeviceRegistrationService deviceRegistrationService;

/**
* Der Manager für die Registrierung auf einen Ort.
*/
Expand Down Expand Up @@ -129,34 +134,45 @@ private ElwaManager() {
public void initiate()
throws ClassNotFoundException, SQLException, IOException, InterruptedException,
LocationOccupiedException, FhemException, NoDataFoundException, AlreadyRunningException {
this.logger.info("Starting up managers");
SingleInstanceManager.instance.start(this.configurationManager.getSingleInstancePort());
this.dataManager = new DataManager(this.configurationManager);
this.locationManager = new LocationManager(this.configurationManager);

// Lade Ort
this.thisLocation = this.dataManager.getLocation(this.configurationManager.getLocationName());

if (StringUtils.isNotBlank(this.configurationManager.getDeconzServer())) {
this.logger.info("Using Deconz as gateway.");
this.devicePowerManager = new DeconzDevicePowerManager(this.configurationManager);
} else if (StringUtils.isNotBlank(this.configurationManager.getFhemConnectionString())) {
this.logger.info("Using fhem as gateway.");
this.devicePowerManager = new FhemDevicePowerManager(this.configurationManager);
} else {
this.logger.error("Application configuration is invalid. Could not find any device power gateway to use. " +
"You must either provide a value for deconz.server or fhem.server");
System.exit(1);
}
this.executionManager = new ExecutionManager(this.devicePowerManager);
this.mainFormController.initiate();

// Setze unterbrochene Ausführungen fort
for (Device d : this.dataManager.getDevices()) {
Execution e = this.dataManager.getRunningExecution(d);
if (e != null) {
// Unterbrochene Ausführung gefunden
this.executionManager.startExecution(e);
DeconzEventListener deconzEventListener = null;
try {
this.logger.info("Starting up managers");
SingleInstanceManager.instance.start(this.configurationManager.getSingleInstancePort());
this.dataManager = new DataManager(this.configurationManager);
this.locationManager = new LocationManager(this.configurationManager);

// Lade Ort
this.thisLocation = this.dataManager.getLocation(this.configurationManager.getLocationName());

if (StringUtils.isNotBlank(this.configurationManager.getDeconzServer())) {
this.logger.info("Using deCONZ as gateway.");
var apiAdapter = new DeconzApiAdapter(this.configurationManager);
deconzEventListener = new DeconzEventListener(this.configurationManager, apiAdapter);
deconzEventListener.start();
deviceRegistrationService = new DeconzRegistrationService(apiAdapter, deconzEventListener);
this.devicePowerManager = new DeconzDevicePowerManager(apiAdapter, deconzEventListener);
} else if (StringUtils.isNotBlank(this.configurationManager.getFhemConnectionString())) {
this.logger.info("Using fhem as gateway.");
this.devicePowerManager = new FhemDevicePowerManager(this.configurationManager);
} else {
this.logger.error("Application configuration is invalid. Could not find any device power gateway to use. " +
"You must either provide a value for deconz.server or fhem.server");
System.exit(1);
}
this.executionManager = new ExecutionManager(this.devicePowerManager);
this.mainFormController.initiate();

// Setze unterbrochene Ausführungen fort
for (Device d : this.dataManager.getDevices()) {
Execution e = this.dataManager.getRunningExecution(d);
if (e != null) {
// Unterbrochene Ausführung gefunden
this.executionManager.startExecution(e);
}
}
} catch (Exception e) {
if (deconzEventListener != null) {
deconzEventListener.stop();
}
}
}
Expand Down Expand Up @@ -215,6 +231,10 @@ public ExecutionManager getExecutionManager() {
return this.executionManager;
}

public IDeviceRegistrationService getDeviceRegistrationService() {
return this.deviceRegistrationService;
}

/**
* Gibt die Utilities-Instanz zurück.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package org.kabieror.elwasys.raspiclient.devices;

import java.io.IOException;

import org.kabieror.elwasys.common.Device;
import org.kabieror.elwasys.raspiclient.executions.FhemException;

import java.io.IOException;

public interface IDevicePowerManager {

void addPowerMeasurementListener(IDevicePowerMeasurementHandler handler);

/**
* Switches the power of a device on.
*
Expand All @@ -24,5 +26,6 @@ void setDevicePowerState(Device device, DevicePowerState newState)
*/
DevicePowerState getState(Device device) throws InterruptedException, FhemException, IOException;

void addPowerMeasurementListener(IDevicePowerMeasurementHandler handler);
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.kabieror.elwasys.raspiclient.devices;

import org.kabieror.elwasys.common.Device;

import java.util.concurrent.CompletableFuture;

public interface IDeviceRegistrationService {
/**
* Checks whether a device can be controlled.
*/
boolean isDeviceRegistered(Device device);

/**
* Tries to find a new remote socket for the given device.
*/
CompletableFuture<Boolean> registerDevice(Device device);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
package org.kabieror.elwasys.raspiclient.devices.deconz;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import org.kabieror.elwasys.raspiclient.configuration.WashguardConfiguration;
import org.kabieror.elwasys.raspiclient.devices.deconz.model.DeconzAuthenticationSuccessEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;

import java.io.IOException;
import java.net.ConnectException;
import java.net.URI;
Expand All @@ -9,17 +19,7 @@
import java.util.Base64;
import java.util.function.Consumer;

import org.kabieror.elwasys.raspiclient.devices.deconz.model.DeconzAuthenticationSuccessEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;

class DeconzApiAdapter {
public class DeconzApiAdapter {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Gson gson = new Gson();
private String token;
Expand All @@ -29,10 +29,10 @@ class DeconzApiAdapter {
private final String username;
private final String password;

public DeconzApiAdapter(URI apiBase, String username, String password) {
this.apiBase = apiBase.resolve("api/");
this.username = username;
this.password = password;
public DeconzApiAdapter(WashguardConfiguration configuration) {
this.apiBase = URI.create(configuration.getDeconzServer()).resolve("api/");
this.username = configuration.getDeconzUser();
this.password = configuration.getDeconzPassword();
}

public HttpResponse<String> request(String apiPath, Consumer<HttpRequest.Builder> requestConfigureAction) throws IOException, InterruptedException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,35 @@

import org.kabieror.elwasys.common.Device;
import org.kabieror.elwasys.raspiclient.application.ElwaManager;
import org.kabieror.elwasys.raspiclient.configuration.WashguardConfiguration;
import org.kabieror.elwasys.raspiclient.devices.DevicePowerState;
import org.kabieror.elwasys.raspiclient.devices.IDevicePowerManager;
import org.kabieror.elwasys.raspiclient.devices.IDevicePowerMeasurementHandler;
import org.kabieror.elwasys.raspiclient.devices.deconz.model.DeconzConfig;
import org.kabieror.elwasys.raspiclient.devices.deconz.model.DeconzEvent;
import org.kabieror.elwasys.raspiclient.executions.FhemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

public class DeconzDevicePowerManager implements IDevicePowerManager {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final DeconzApiAdapter apiAdapter;
private final DeconzService deconzService;

private final DeconzEventListener eventListener;
private final DeconzService deconzService;
private final List<IDevicePowerMeasurementHandler> powerMeasurementListeners = new ArrayList<>();

public DeconzDevicePowerManager(WashguardConfiguration configurationManager) throws IOException, InterruptedException {
public DeconzDevicePowerManager(DeconzApiAdapter apiAdapter, DeconzEventListener eventListener) throws IOException, InterruptedException {
this.eventListener = eventListener;
ElwaManager.instance.listenToCloseEvent(restart -> onClosing());

var deconzUri = URI.create(configurationManager.getDeconzServer());
apiAdapter = new DeconzApiAdapter(
deconzUri,
configurationManager.getDeconzUser(),
configurationManager.getDeconzPassword());

var deconzConfig = apiAdapter.parseResponse(
apiAdapter.request("config", r -> r.GET()),
DeconzConfig.class);

eventListener = new DeconzEventListener(deconzUri.getHost(), deconzConfig.websocketport());
eventListener.listenToPowerMeasurementReceived(this::onPowerMeasurementReceived);
eventListener.start();

deconzService = new DeconzService(apiAdapter, eventListener);
}

private void onPowerMeasurementReceived(DeconzEvent e) {
this.logger.info("Received: " + e.toString());
this.logger.debug("Received: " + e.toString());

var execution = ElwaManager.instance.getExecutionManager()
.getRunningExecutions().stream()
Expand All @@ -70,6 +54,10 @@ public void setDevicePowerState(Device device, DevicePowerState newState)

@Override
public DevicePowerState getState(Device device) throws InterruptedException, FhemException, IOException {
if (device.getDeconzUuid() == null) {
logger.warn("No deCONZ device registered for device %s".formatted(device.getId()));
return DevicePowerState.UNKNOWN;
}
var isOn = deconzService.getDeviceState(device.getDeconzUuid()).on();
return isOn ? DevicePowerState.ON : DevicePowerState.OFF;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import org.kabieror.elwasys.raspiclient.configuration.WashguardConfiguration;
import org.kabieror.elwasys.raspiclient.devices.deconz.model.DeconzChangeType;
import org.kabieror.elwasys.raspiclient.devices.deconz.model.DeconzConfig;
import org.kabieror.elwasys.raspiclient.devices.deconz.model.DeconzEvent;
import org.kabieror.elwasys.raspiclient.devices.deconz.model.DeconzResourceType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
Expand All @@ -13,6 +17,7 @@
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -21,11 +26,12 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

class DeconzEventListener extends TextWebSocketHandler {
public class DeconzEventListener extends TextWebSocketHandler {
private static final Integer INITIAL_RECONNECT_DELAY_SECONDS = 5;
private final Logger logger = LoggerFactory.getLogger(getClass());
private final List<IDeconzPowerMeasurementEventListener> powerMeasurementEventListeners = new ArrayList<>();
private final List<IDeconzDeviceStateEventListener> deviceStateEventListeners = new ArrayList<>();
private final List<IDeconzDeviceRegisteredListener> deviceRegisteredListeners = new ArrayList<>();
private Integer reconnectDelaySeconds = INITIAL_RECONNECT_DELAY_SECONDS;
private final AtomicBoolean isReconnectRunning = new AtomicBoolean(false);
private final ScheduledExecutorService reconnectScheduler = Executors.newSingleThreadScheduledExecutor();
Expand All @@ -36,9 +42,13 @@ class DeconzEventListener extends TextWebSocketHandler {
private String host;
private int port;

public DeconzEventListener(String host, int port) {
this.host = host;
this.port = port;
public DeconzEventListener(WashguardConfiguration configuration, DeconzApiAdapter apiAdapter) throws IOException, InterruptedException {
var deconzUri = URI.create(configuration.getDeconzServer());
this.host = deconzUri.getHost();
var deconzConfig = apiAdapter.parseResponse(
apiAdapter.request("config", r -> r.GET()),
DeconzConfig.class);
this.port = deconzConfig.websocketport();
}

public void listenToPowerMeasurementReceived(IDeconzPowerMeasurementEventListener listener) {
Expand Down Expand Up @@ -87,12 +97,24 @@ protected void handleTextMessage(WebSocketSession session, TextMessage message)
byte[] rawBytes = message.getPayload().getBytes(StandardCharsets.UTF_8);
try {
DeconzEvent event = gson.fromJson(new String(rawBytes), DeconzEvent.class);
if (event.r().equals("sensors") && event.state() != null && event.state().power() != null) {

if (event.r() == DeconzResourceType.sensors
&& event.state() != null
&& event.state().power() != null) {
this.powerMeasurementEventListeners.forEach(
l -> l.onPowerMeasurementReceived(event));
} else if (event.r().equals("lights") && event.state() != null && event.state().on() != null) {

} else if (event.e() == DeconzChangeType.added
&& event.r() == DeconzResourceType.lights) {
this.deviceRegisteredListeners.forEach(
l -> l.onDeviceRegistered(event.uniqueid()));

} else if (event.r() == DeconzResourceType.lights
&& event.state() != null
&& event.state().on() != null) {
this.deviceStateEventListeners.forEach(
l -> l.onDeviceStateChanged(event.uniqueid(), event.state().on()));

}
} catch (JsonSyntaxException e) {
this.logger.error("Failed to read event data.", e);
Expand Down Expand Up @@ -128,5 +150,8 @@ private void openConnection() {
});
}

public void listenToDeviceRegisteredEvent(IDeconzDeviceRegisteredListener listener) {
deviceRegisteredListeners.add(listener);
}
}

Loading