fix(18062): 🛠️ work in progress ...
Signed-off-by: Patrik Gfeller <patrik.gfeller@proton.me>pull/18100/head
parent
116e8ce37f
commit
6e66e114cc
|
@ -18,6 +18,7 @@ import java.net.URISyntaxException;
|
|||
import java.security.cert.CertificateException;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
@ -26,8 +27,6 @@ import org.eclipse.jetty.client.HttpClient;
|
|||
import org.eclipse.jetty.client.HttpResponseException;
|
||||
import org.eclipse.jetty.client.api.AuthenticationStore;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
|
@ -55,8 +54,10 @@ public class HueSyncConnection {
|
|||
public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
|
||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
/**
|
||||
* Request format: The Sync Box API can be accessed locally via HTTPS on root level (port 443,
|
||||
* /api/v1), resource level /api/v1/<resource> and in some cases sub-resource level
|
||||
* Request format: The Sync Box API can be accessed locally via HTTPS on root
|
||||
* level (port 443,
|
||||
* /api/v1), resource level /api/v1/<resource> and in some cases sub-resource
|
||||
* level
|
||||
* /api/v1/<resource>/<sub-resource>.
|
||||
*/
|
||||
private static final String REQUEST_FORMAT = "https://%s:%s/%s/%s";
|
||||
|
@ -72,6 +73,41 @@ public class HueSyncConnection {
|
|||
|
||||
private Optional<HueSyncAuthenticationResult> authentication = Optional.empty();
|
||||
|
||||
private class Request {
|
||||
|
||||
private final String endpoint;
|
||||
|
||||
private HttpMethod method = HttpMethod.GET;
|
||||
private String payload = "";
|
||||
|
||||
private Request(HttpMethod httpMethod, String endpoint, String payload) {
|
||||
this.method = httpMethod;
|
||||
this.endpoint = endpoint;
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
protected Request(String endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
private Request(HttpMethod httpMethod, String endpoint) {
|
||||
this.method = httpMethod;
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
protected ContentResponse execute() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
String uri = String.format(REQUEST_FORMAT, host, port, API, endpoint);
|
||||
|
||||
var request = httpClient.newRequest(uri).method(method).timeout(1, TimeUnit.SECONDS);
|
||||
if (!payload.isBlank()) {
|
||||
request.header(HttpHeader.CONTENT_TYPE, MimeTypes.Type.APPLICATION_JSON_UTF_8.toString())
|
||||
.content(new StringContentProvider(payload));
|
||||
}
|
||||
|
||||
return request.send();
|
||||
}
|
||||
}
|
||||
|
||||
protected String registrationId = "";
|
||||
|
||||
public HueSyncConnection(HttpClient httpClient, String host, Integer port)
|
||||
|
@ -102,42 +138,30 @@ public class HueSyncConnection {
|
|||
|
||||
// #region protected
|
||||
protected @Nullable <T> T executeRequest(HttpMethod method, String endpoint, String payload,
|
||||
@Nullable Class<T> type) throws Exception {
|
||||
try {
|
||||
return this.processedResponse(this.executeRequest(method, endpoint, payload), type);
|
||||
} catch (ExecutionException | InterruptedException | TimeoutException e) {
|
||||
this.handleException(e);
|
||||
}
|
||||
@Nullable Class<T> type) throws HueSyncConnectionException {
|
||||
|
||||
return null;
|
||||
return this.executeRequest(new Request(method, endpoint, payload), type);
|
||||
}
|
||||
|
||||
protected @Nullable <T> T executeGetRequest(String endpoint, Class<T> type) throws Exception {
|
||||
try {
|
||||
return this.processedResponse(this.executeGetRequest(endpoint), type);
|
||||
} catch (ExecutionException | InterruptedException | TimeoutException e) {
|
||||
this.handleException(e);
|
||||
}
|
||||
protected @Nullable <T> T executeRequest(HttpMethod httpMethod, String endpoint, @Nullable Class<T> type)
|
||||
throws HueSyncConnectionException {
|
||||
return this.executeRequest(new Request(httpMethod, endpoint), type);
|
||||
}
|
||||
|
||||
return null;
|
||||
protected @Nullable <T> T executeGetRequest(String endpoint, Class<T> type) throws HueSyncConnectionException {
|
||||
return this.executeRequest(new Request(endpoint), type);
|
||||
}
|
||||
|
||||
protected boolean isRegistered() {
|
||||
return this.authentication.isPresent();
|
||||
}
|
||||
|
||||
protected void unregisterDevice() {
|
||||
protected void unregisterDevice() throws HueSyncConnectionException {
|
||||
if (this.isRegistered()) {
|
||||
try {
|
||||
String endpoint = ENDPOINTS.REGISTRATIONS + "/" + this.registrationId;
|
||||
ContentResponse response = this.executeRequest(HttpMethod.DELETE, endpoint);
|
||||
String endpoint = ENDPOINTS.REGISTRATIONS + "/" + this.registrationId;
|
||||
|
||||
if (response.getStatus() == HttpStatus.OK_200) {
|
||||
this.removeAuthentication();
|
||||
}
|
||||
} catch (InterruptedException | TimeoutException | ExecutionException e) {
|
||||
this.logger.warn("{}", e.getMessage());
|
||||
}
|
||||
this.executeRequest(HttpMethod.DELETE, endpoint, null);
|
||||
this.removeAuthentication();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,96 +171,51 @@ public class HueSyncConnection {
|
|||
// #endregion
|
||||
|
||||
// #region private
|
||||
private @Nullable <T> T processedResponse(Response response, @Nullable Class<T> type)
|
||||
throws HueSyncConnectionException {
|
||||
int status = response.getStatus();
|
||||
String exceptionMessage;
|
||||
/*
|
||||
* 400 Invalid State: Registration in progress
|
||||
*
|
||||
* 401 Authentication failed: If credentials are missing or invalid, errors out. If
|
||||
* credentials are missing, continues on to GET only the Configuration state when
|
||||
* unauthenticated, to allow for device identification.
|
||||
*
|
||||
* 404 Invalid URI Path: Accessing URI path which is not supported
|
||||
*
|
||||
* 500 Internal: Internal errors like out of memory
|
||||
*/
|
||||
switch (status) {
|
||||
case HttpStatus.OK_200 -> {
|
||||
return (type != null && (response instanceof ContentResponse))
|
||||
? this.deserialize(((ContentResponse) response).getContentAsString(), type)
|
||||
: null;
|
||||
}
|
||||
case HttpStatus.BAD_REQUEST_400 -> {
|
||||
this.logger.debug("registration in progress: no token received yet");
|
||||
return null;
|
||||
}
|
||||
case HttpStatus.UNAUTHORIZED_401 -> exceptionMessage = "@text/connection.invalid-login";
|
||||
case HttpStatus.NOT_FOUND_404 -> exceptionMessage = "@text/connection.generic-error";
|
||||
default -> exceptionMessage = "@text/connection.generic-error";
|
||||
}
|
||||
|
||||
var exception = new HueSyncConnectionException(exceptionMessage);
|
||||
private @Nullable <T> T executeRequest(Request request, @Nullable Class<T> type) throws HueSyncConnectionException {
|
||||
String message = "@text/connection.generic-error";
|
||||
|
||||
this.logger.warn("{}", exception.getMessage());
|
||||
throw (exception);
|
||||
}
|
||||
|
||||
private @Nullable <T> T deserialize(String json, Class<T> type) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(json, type);
|
||||
} catch (JsonProcessingException | NoClassDefFoundError e) {
|
||||
this.logger.error("{}", e.getMessage());
|
||||
ContentResponse response = request.execute();
|
||||
|
||||
return null;
|
||||
/*
|
||||
* 400 Invalid State: Registration in progress
|
||||
*
|
||||
* 401 Authentication failed: If credentials are missing or invalid, errors out.
|
||||
* If
|
||||
* credentials are missing, continues on to GET only the Configuration state
|
||||
* when
|
||||
* unauthenticated, to allow for device identification.
|
||||
*
|
||||
* 404 Invalid URI Path: Accessing URI path which is not supported
|
||||
*
|
||||
* 500 Internal: Internal errors like out of memory
|
||||
*/
|
||||
switch (response.getStatus()) {
|
||||
case HttpStatus.OK_200 -> {
|
||||
return this.deserialize(response.getContentAsString(), type);
|
||||
}
|
||||
case HttpStatus.BAD_REQUEST_400 -> {
|
||||
logger.debug("registration in progress: no token received yet");
|
||||
return null;
|
||||
}
|
||||
case HttpStatus.UNAUTHORIZED_401 -> message = "@text/connection.invalid-login";
|
||||
case HttpStatus.NOT_FOUND_404 -> message = "@text/connection.generic-error";
|
||||
}
|
||||
throw new HueSyncConnectionException(message, new HttpResponseException(message, response));
|
||||
} catch (JsonProcessingException | InterruptedException | ExecutionException | TimeoutException e) {
|
||||
throw new HueSyncConnectionException(message, e);
|
||||
}
|
||||
}
|
||||
|
||||
private ContentResponse executeRequest(HttpMethod method, String endpoint)
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
return this.executeRequest(method, endpoint, "");
|
||||
}
|
||||
|
||||
private ContentResponse executeGetRequest(String endpoint)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
String uri = String.format(REQUEST_FORMAT, this.host, this.port, API, endpoint);
|
||||
|
||||
return httpClient.GET(uri);
|
||||
}
|
||||
|
||||
private ContentResponse executeRequest(HttpMethod method, String endpoint, String payload)
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
String uri = String.format(REQUEST_FORMAT, this.host, this.port, API, endpoint);
|
||||
|
||||
Request request = this.httpClient.newRequest(uri).method(method);
|
||||
|
||||
this.logger.trace("uri: {}", uri);
|
||||
this.logger.trace("method: {}", method);
|
||||
this.logger.trace("payload: {}", payload);
|
||||
|
||||
if (!payload.isBlank()) {
|
||||
request.header(HttpHeader.CONTENT_TYPE, MimeTypes.Type.APPLICATION_JSON_UTF_8.toString())
|
||||
.content(new StringContentProvider(payload));
|
||||
}
|
||||
|
||||
return request.send();
|
||||
}
|
||||
|
||||
private void handleException(Exception e) throws Exception {
|
||||
this.logger.warn("Exception: {}, Client State: {}", e.getMessage(), this.httpClient.getState());
|
||||
|
||||
Throwable cause = e.getCause();
|
||||
if (cause != null && cause instanceof HttpResponseException) {
|
||||
this.processedResponse(((HttpResponseException) cause).getResponse(), null);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
private @Nullable <T> T deserialize(String json, @Nullable Class<T> type) throws JsonProcessingException {
|
||||
return type == null ? null : OBJECT_MAPPER.readValue(json, type);
|
||||
}
|
||||
|
||||
private void removeAuthentication() {
|
||||
AuthenticationStore store = this.httpClient.getAuthenticationStore();
|
||||
store.clearAuthenticationResults();
|
||||
|
||||
this.httpClient.setAuthenticationStore(store);
|
||||
|
||||
this.registrationId = "";
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.openhab.binding.huesync.internal.api.dto.hdmi.HueSyncHdmi;
|
|||
import org.openhab.binding.huesync.internal.api.dto.registration.HueSyncRegistration;
|
||||
import org.openhab.binding.huesync.internal.api.dto.registration.HueSyncRegistrationRequest;
|
||||
import org.openhab.binding.huesync.internal.config.HueSyncConfiguration;
|
||||
import org.openhab.binding.huesync.internal.exceptions.HueSyncConnectionException;
|
||||
import org.openhab.binding.huesync.internal.types.HueSyncExceptionHandler;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
|
@ -114,7 +115,7 @@ public class HueSyncDeviceConnection {
|
|||
|
||||
try {
|
||||
this.connection.executeRequest(HttpMethod.PUT, ENDPOINTS.EXECUTION, json, null);
|
||||
} catch (Exception exception) {
|
||||
} catch (HueSyncConnectionException exception) {
|
||||
exceptionHandler.handle(exception);
|
||||
}
|
||||
}
|
||||
|
@ -188,7 +189,11 @@ public class HueSyncDeviceConnection {
|
|||
}
|
||||
|
||||
public void unregisterDevice() {
|
||||
this.connection.unregisterDevice();
|
||||
try {
|
||||
this.connection.unregisterDevice();
|
||||
} catch (HueSyncConnectionException e) {
|
||||
this.logger.warn("{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
package org.openhab.binding.huesync.internal.exceptions;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -21,8 +22,18 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||
@NonNullByDefault
|
||||
public class HueSyncConnectionException extends HueSyncException {
|
||||
private static final long serialVersionUID = 0L;
|
||||
private @Nullable Exception innerException = null;
|
||||
|
||||
public HueSyncConnectionException(String message, Exception exception) {
|
||||
super(message);
|
||||
this.innerException = exception;
|
||||
}
|
||||
|
||||
public HueSyncConnectionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public @Nullable Exception getInnerException() {
|
||||
return this.innerException;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import java.util.concurrent.TimeUnit;
|
|||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpResponseException;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.openhab.binding.huesync.internal.HdmiChannels;
|
||||
import org.openhab.binding.huesync.internal.HueSyncConstants;
|
||||
import org.openhab.binding.huesync.internal.api.dto.device.HueSyncDevice;
|
||||
|
@ -33,6 +35,7 @@ import org.openhab.binding.huesync.internal.api.dto.registration.HueSyncRegistra
|
|||
import org.openhab.binding.huesync.internal.config.HueSyncConfiguration;
|
||||
import org.openhab.binding.huesync.internal.connection.HueSyncDeviceConnection;
|
||||
import org.openhab.binding.huesync.internal.exceptions.HueSyncApiException;
|
||||
import org.openhab.binding.huesync.internal.exceptions.HueSyncConnectionException;
|
||||
import org.openhab.binding.huesync.internal.handler.tasks.HueSyncRegistrationTask;
|
||||
import org.openhab.binding.huesync.internal.handler.tasks.HueSyncUpdateTask;
|
||||
import org.openhab.binding.huesync.internal.handler.tasks.HueSyncUpdateTaskResult;
|
||||
|
@ -69,17 +72,39 @@ public class HueSyncHandler extends BaseThingHandler {
|
|||
* @author Patrik Gfeller - Issue #18062, improve connection exception handling.
|
||||
*/
|
||||
private class ExceptionHandler implements HueSyncExceptionHandler {
|
||||
private final Thing thing;
|
||||
private final HueSyncHandler handler;
|
||||
|
||||
private ExceptionHandler(Thing thing) {
|
||||
this.thing = thing;
|
||||
private ExceptionHandler(HueSyncHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Exception exception) {
|
||||
ThingStatusInfo status = new ThingStatusInfo(ThingStatus.INITIALIZING,
|
||||
ThingStatusDetail.COMMUNICATION_ERROR, exception.getLocalizedMessage());
|
||||
this.thing.setStatusInfo(status);
|
||||
ThingStatusDetail detail = ThingStatusDetail.COMMUNICATION_ERROR;
|
||||
String description;
|
||||
|
||||
if (exception instanceof HueSyncConnectionException connectionException) {
|
||||
if (connectionException.getInnerException() instanceof HttpResponseException innerException) {
|
||||
switch (innerException.getResponse().getStatus()) {
|
||||
case HttpStatus.BAD_REQUEST_400 -> {
|
||||
detail = ThingStatusDetail.CONFIGURATION_PENDING;
|
||||
}
|
||||
case HttpStatus.UNAUTHORIZED_401 -> {
|
||||
detail = ThingStatusDetail.CONFIGURATION_ERROR;
|
||||
}
|
||||
default -> {
|
||||
detail = ThingStatusDetail.COMMUNICATION_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
description = connectionException.getLocalizedMessage();
|
||||
} else {
|
||||
detail = ThingStatusDetail.COMMUNICATION_ERROR;
|
||||
description = exception.getLocalizedMessage();
|
||||
}
|
||||
|
||||
ThingStatusInfo statusInfo = new ThingStatusInfo(ThingStatus.OFFLINE, detail, description);
|
||||
this.handler.thing.setStatusInfo(statusInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +126,9 @@ public class HueSyncHandler extends BaseThingHandler {
|
|||
public HueSyncHandler(Thing thing, HttpClientFactory httpClientFactory) {
|
||||
super(thing);
|
||||
|
||||
this.exceptionHandler = new ExceptionHandler(thing);
|
||||
this.updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
this.exceptionHandler = new ExceptionHandler(this);
|
||||
this.httpClient = httpClientFactory.getCommonHttpClient();
|
||||
}
|
||||
|
||||
|
@ -122,34 +149,39 @@ public class HueSyncHandler extends BaseThingHandler {
|
|||
this.getConfigAs(HueSyncConfiguration.class), this.exceptionHandler);
|
||||
|
||||
this.connection = Optional.of(connectionInstance);
|
||||
|
||||
this.deviceInfo = Optional.ofNullable(connectionInstance.getDeviceInfo());
|
||||
|
||||
this.deviceInfo.ifPresent(info -> {
|
||||
setProperty(Thing.PROPERTY_SERIAL_NUMBER, info.uniqueId != null ? info.uniqueId : "");
|
||||
setProperty(Thing.PROPERTY_MODEL_ID, info.deviceType);
|
||||
setProperty(Thing.PROPERTY_FIRMWARE_VERSION, info.firmwareVersion);
|
||||
|
||||
setProperty(HueSyncHandler.PROPERTY_API_VERSION, String.format("%d", info.apiLevel));
|
||||
|
||||
try {
|
||||
this.checkCompatibility();
|
||||
} catch (HueSyncApiException e) {
|
||||
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
} finally {
|
||||
this.startTasks(connectionInstance);
|
||||
}
|
||||
connect(connectionInstance, info);
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
this.exceptionHandler.handle(ex);
|
||||
|
||||
} catch (Exception e) {
|
||||
this.exceptionHandler.handle(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void connect(HueSyncDeviceConnection connectionInstance, HueSyncDevice info) {
|
||||
setProperty(Thing.PROPERTY_SERIAL_NUMBER, info.uniqueId != null ? info.uniqueId : "");
|
||||
setProperty(Thing.PROPERTY_MODEL_ID, info.deviceType);
|
||||
setProperty(Thing.PROPERTY_FIRMWARE_VERSION, info.firmwareVersion);
|
||||
|
||||
setProperty(HueSyncHandler.PROPERTY_API_VERSION, String.format("%d", info.apiLevel));
|
||||
|
||||
try {
|
||||
this.checkCompatibility();
|
||||
} catch (HueSyncApiException e) {
|
||||
this.exceptionHandler.handle(e);
|
||||
} finally {
|
||||
this.startTasks(connectionInstance);
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable ScheduledFuture<?> executeTask(Runnable task, long initialDelay, long interval) {
|
||||
return scheduler.scheduleWithFixedDelay(task, initialDelay, interval, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void startTasks(HueSyncDeviceConnection connection) {
|
||||
private synchronized void startTasks(HueSyncDeviceConnection connection) {
|
||||
this.stopTasks();
|
||||
|
||||
connection.updateConfiguration(this.getConfigAs(HueSyncConfiguration.class));
|
||||
|
@ -164,13 +196,13 @@ public class HueSyncHandler extends BaseThingHandler {
|
|||
|
||||
switch (id) {
|
||||
case POLL -> {
|
||||
initialDelay = 0;
|
||||
interval = this.getConfigAs(HueSyncConfiguration.class).statusUpdateInterval;
|
||||
|
||||
this.updateStatus(ThingStatus.ONLINE);
|
||||
|
||||
initialDelay = 5;
|
||||
interval = this.getConfigAs(HueSyncConfiguration.class).statusUpdateInterval;
|
||||
task = new HueSyncUpdateTask(connection, this.deviceInfo.get(),
|
||||
deviceStatus -> this.handleUpdate(deviceStatus, connection));
|
||||
deviceStatus -> this.handleUpdate(deviceStatus), this.exceptionHandler);
|
||||
|
||||
}
|
||||
case REGISTER -> {
|
||||
initialDelay = HueSyncConstants.REGISTRATION_INITIAL_DELAY;
|
||||
|
@ -190,7 +222,7 @@ public class HueSyncHandler extends BaseThingHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private void stopTasks() {
|
||||
private synchronized void stopTasks() {
|
||||
logger.debug("Stopping {} task(s): {}", this.tasks.values().size(), String.join(",", this.tasks.keySet()));
|
||||
|
||||
this.tasks.values().forEach(task -> this.stopTask(task));
|
||||
|
@ -200,7 +232,7 @@ public class HueSyncHandler extends BaseThingHandler {
|
|||
"@text/thing.config.huesync.box.registration");
|
||||
}
|
||||
|
||||
private void stopTask(@Nullable ScheduledFuture<?> task) {
|
||||
private synchronized void stopTask(@Nullable ScheduledFuture<?> task) {
|
||||
if (task == null || task.isCancelled() || task.isDone()) {
|
||||
return;
|
||||
}
|
||||
|
@ -208,28 +240,26 @@ public class HueSyncHandler extends BaseThingHandler {
|
|||
task.cancel(true);
|
||||
}
|
||||
|
||||
private void handleUpdate(@Nullable HueSyncUpdateTaskResult dto, HueSyncDeviceConnection connection) {
|
||||
try {
|
||||
HueSyncUpdateTaskResult update = Optional.ofNullable(dto).get();
|
||||
private void handleUpdate(@Nullable HueSyncUpdateTaskResult dto) {
|
||||
synchronized (this) {
|
||||
ThingStatus status = this.thing.getStatus();
|
||||
|
||||
this.updateFirmwareInformation(Optional.ofNullable(update.deviceStatus).get());
|
||||
this.updateHdmiInformation(Optional.ofNullable(update.hdmiStatus).get());
|
||||
this.updateExecutionInformation(Optional.ofNullable(update.execution).get());
|
||||
|
||||
if (this.getThing().getStatus() != ThingStatus.ONLINE) {
|
||||
this.updateStatus(ThingStatus.ONLINE);
|
||||
switch (status) {
|
||||
case ONLINE -> {
|
||||
Optional.ofNullable(dto).ifPresent(taskResult -> {
|
||||
Optional.ofNullable(taskResult.deviceStatus)
|
||||
.ifPresent(payload -> this.updateFirmwareInformation(payload));
|
||||
Optional.ofNullable(taskResult.hdmiStatus)
|
||||
.ifPresent(payload -> this.updateHdmiInformation(payload));
|
||||
Optional.ofNullable(taskResult.execution)
|
||||
.ifPresent(payload -> this.updateExecutionInformation(payload));
|
||||
});
|
||||
}
|
||||
default -> this.logger.debug("Unable to execute update - Status: [{}]", status);
|
||||
}
|
||||
|
||||
} catch (NoSuchElementException e) {
|
||||
this.logMissingUpdateInformation("device");
|
||||
this.startTasks(connection);
|
||||
}
|
||||
}
|
||||
|
||||
private void logMissingUpdateInformation(String api) {
|
||||
this.logger.warn("Device information - {} status missing", api);
|
||||
}
|
||||
|
||||
private void updateHdmiInformation(HueSyncHdmi hdmiStatus) {
|
||||
updateHdmiStatus(HueSyncConstants.CHANNELS.HDMI.IN_1, hdmiStatus.input1);
|
||||
updateHdmiStatus(HueSyncConstants.CHANNELS.HDMI.IN_2, hdmiStatus.input2);
|
||||
|
@ -326,9 +356,8 @@ public class HueSyncHandler extends BaseThingHandler {
|
|||
@Override
|
||||
public void initialize() {
|
||||
try {
|
||||
this.updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
this.stopTasks();
|
||||
this.updateStatus(ThingStatus.OFFLINE);
|
||||
|
||||
scheduler.execute(initializeConnection());
|
||||
} catch (Exception e) {
|
||||
|
@ -358,15 +387,17 @@ public class HueSyncHandler extends BaseThingHandler {
|
|||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
synchronized (this) {
|
||||
super.dispose();
|
||||
|
||||
try {
|
||||
this.stopTasks();
|
||||
this.connection.get().dispose();
|
||||
} catch (Exception e) {
|
||||
this.logger.warn("{}", e.getMessage());
|
||||
} finally {
|
||||
this.logger.debug("Thing {} ({}) disposed.", this.thing.getLabel(), this.thing.getUID());
|
||||
try {
|
||||
this.stopTasks();
|
||||
this.connection.orElseThrow().dispose();
|
||||
} catch (Exception e) {
|
||||
this.logger.warn("{}", e.getMessage());
|
||||
} finally {
|
||||
this.logger.debug("Thing {} ({}) disposed.", this.thing.getLabel(), this.thing.getUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -374,10 +405,8 @@ public class HueSyncHandler extends BaseThingHandler {
|
|||
public void handleRemoval() {
|
||||
super.handleRemoval();
|
||||
|
||||
try {
|
||||
this.connection.orElseThrow().unregisterDevice();
|
||||
} catch (NoSuchElementException e) {
|
||||
|
||||
if (this.connection.isPresent()) {
|
||||
this.connection.get().unregisterDevice();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.huesync.internal.api.dto.device.HueSyncDevice;
|
||||
import org.openhab.binding.huesync.internal.connection.HueSyncDeviceConnection;
|
||||
import org.openhab.binding.huesync.internal.types.HueSyncExceptionHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -34,10 +35,13 @@ public class HueSyncUpdateTask implements Runnable {
|
|||
private final HueSyncDeviceConnection connection;
|
||||
private final HueSyncDevice deviceInfo;
|
||||
|
||||
private final HueSyncExceptionHandler exceptionHandler;
|
||||
private final Consumer<@Nullable HueSyncUpdateTaskResult> action;
|
||||
|
||||
public HueSyncUpdateTask(HueSyncDeviceConnection connection, HueSyncDevice deviceInfo,
|
||||
Consumer<@Nullable HueSyncUpdateTaskResult> action) {
|
||||
Consumer<@Nullable HueSyncUpdateTaskResult> action, HueSyncExceptionHandler exceptionHandler) {
|
||||
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
this.connection = connection;
|
||||
this.deviceInfo = deviceInfo;
|
||||
|
||||
|
@ -46,24 +50,19 @@ public class HueSyncUpdateTask implements Runnable {
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
HueSyncUpdateTaskResult updateInfo = new HueSyncUpdateTaskResult();
|
||||
|
||||
try {
|
||||
this.logger.debug("Status update query for {} {}:{}", this.deviceInfo.name, this.deviceInfo.deviceType,
|
||||
this.deviceInfo.uniqueId);
|
||||
|
||||
if (!this.connection.isRegistered()) {
|
||||
this.action.accept(null);
|
||||
}
|
||||
|
||||
HueSyncUpdateTaskResult updateInfo = new HueSyncUpdateTaskResult();
|
||||
|
||||
updateInfo.deviceStatus = this.connection.getDetailedDeviceInfo();
|
||||
updateInfo.hdmiStatus = this.connection.getHdmiInfo();
|
||||
updateInfo.execution = this.connection.getExecutionInfo();
|
||||
|
||||
this.action.accept(updateInfo);
|
||||
} catch (Exception e) {
|
||||
this.logger.debug("{}", e.getMessage());
|
||||
this.action.accept(null);
|
||||
this.exceptionHandler.handle(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ channel-type.huesync.execution-sync-active.description = <p> <b>OFF</b> in case
|
|||
api.minimal-version = Only devices with API level >= 7 are supported
|
||||
api.communication-problem = Communication problem with the device
|
||||
connection.invalid-login = Invalid or missing credentials
|
||||
connection.generic-error = Unable to communicate with to reach API endpoint.
|
||||
connection.generic-error = Unable to communicate the device.
|
||||
connection.server-error = Device was not able to process the request.
|
||||
|
||||
# registration
|
||||
|
|
Loading…
Reference in New Issue