diff --git a/bundles/org.openhab.binding.ojelectronics/NOTICE b/bundles/org.openhab.binding.ojelectronics/NOTICE
index 38d625e3492..fdb4ac8cc8b 100644
--- a/bundles/org.openhab.binding.ojelectronics/NOTICE
+++ b/bundles/org.openhab.binding.ojelectronics/NOTICE
@@ -11,3 +11,8 @@ https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/openhab/openhab-addons
+
+Signalr4j
+* License: Apache 2.0 License
+* Project: https://github.com/sputnikdev/bluetooth-gatt-parser
+* Source: https://github.com/sputnikdev/bluetooth-gatt-parser
diff --git a/bundles/org.openhab.binding.ojelectronics/README.md b/bundles/org.openhab.binding.ojelectronics/README.md
index b14b6bb6028..b7c4fd42c94 100644
--- a/bundles/org.openhab.binding.ojelectronics/README.md
+++ b/bundles/org.openhab.binding.ojelectronics/README.md
@@ -23,7 +23,6 @@ After the ojcloud bridge is successfully initialized all thermostats will be dis
| password | password from the OJElectronics App (required) |
| apiKey | API key. You get the key from your local distributor. |
| apiUrl | URL of the API endpoint. Optional, the default value should always work. |
-| refreshDelayInSeconds | Refresh interval in seconds. Optional, the default value is 30 seconds. |
| customerId | Customer ID. Optional, the default value should always work. |
| softwareVersion | Software version. Optional, the default value should always work. |
diff --git a/bundles/org.openhab.binding.ojelectronics/pom.xml b/bundles/org.openhab.binding.ojelectronics/pom.xml
index 91278e06e26..347db883432 100644
--- a/bundles/org.openhab.binding.ojelectronics/pom.xml
+++ b/bundles/org.openhab.binding.ojelectronics/pom.xml
@@ -13,4 +13,21 @@
org.openhab.binding.ojelectronics
openHAB Add-ons :: Bundles :: OJElectronics Binding
+
+
+
+
+ com.github.signalr4j
+ signalr4j
+ 2.0.4
+ compile
+
+
+
+ org.java-websocket
+ Java-WebSocket
+ 1.5.3
+ compile
+
+
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/OJCloudHandler.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/OJCloudHandler.java
index 5d4532a958c..7f7798e7b23 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/OJCloudHandler.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/OJCloudHandler.java
@@ -13,7 +13,7 @@
package org.openhab.binding.ojelectronics.internal;
import java.util.Collection;
-import java.util.Collections;
+import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -21,10 +21,12 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.ojelectronics.internal.config.OJElectronicsBridgeConfiguration;
+import org.openhab.binding.ojelectronics.internal.models.SignalRResultModel;
import org.openhab.binding.ojelectronics.internal.models.groups.GroupContentResponseModel;
import org.openhab.binding.ojelectronics.internal.services.OJDiscoveryService;
import org.openhab.binding.ojelectronics.internal.services.RefreshGroupContentService;
import org.openhab.binding.ojelectronics.internal.services.RefreshService;
+import org.openhab.binding.ojelectronics.internal.services.RefreshThermostatsService;
import org.openhab.binding.ojelectronics.internal.services.SignInService;
import org.openhab.binding.ojelectronics.internal.services.UpdateService;
import org.openhab.core.thing.Bridge;
@@ -32,7 +34,6 @@ import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
-import org.openhab.core.thing.binding.BridgeHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
@@ -44,7 +45,7 @@ import org.slf4j.LoggerFactory;
* @author Christian Kittel - Initial Contribution
*/
@NonNullByDefault
-public class OJCloudHandler extends BaseBridgeHandler implements BridgeHandler {
+public class OJCloudHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(OJCloudHandler.class);
private final HttpClient httpClient;
@@ -54,6 +55,7 @@ public class OJCloudHandler extends BaseBridgeHandler implements BridgeHandler {
private @Nullable SignInService signInService;
private OJElectronicsBridgeConfiguration configuration;
private @Nullable ScheduledFuture> signTask;
+ private @Nullable ScheduledFuture> updateTask;
private @Nullable OJDiscoveryService discoveryService;
/**
@@ -82,9 +84,9 @@ public class OJCloudHandler extends BaseBridgeHandler implements BridgeHandler {
*/
@Override
public void dispose() {
- final RefreshService refreshService = this.refreshService;
- if (refreshService != null) {
- refreshService.stop();
+ final RefreshService localRefreshService = this.refreshService;
+ if (localRefreshService != null) {
+ localRefreshService.stop();
}
final ScheduledFuture> signTask = this.signTask;
if (signTask != null) {
@@ -99,64 +101,90 @@ public class OJCloudHandler extends BaseBridgeHandler implements BridgeHandler {
public void handleCommand(ChannelUID channelUID, Command command) {
}
+ public synchronized void updateThinksChannelValuesToCloud() {
+ final UpdateService localUpdateService = this.updateService;
+ if (localUpdateService != null) {
+ final ScheduledFuture> localUpdateTask = this.updateTask;
+ if (localUpdateTask != null) {
+ localUpdateTask.cancel(false);
+ }
+ this.updateTask = scheduler.schedule(() -> {
+ localUpdateService.updateAllThermostats(getThing().getThings());
+ this.updateTask = null;
+ }, 2, TimeUnit.SECONDS);
+ }
+ }
+
private void ensureSignIn() {
if (signInService == null) {
signInService = new SignInService(configuration, httpClient);
}
- final SignInService signInService = this.signInService;
- if (signInService != null) {
- signInService.signIn(this::handleSignInDone, this::handleConnectionLost,
+ final SignInService localSignInService = this.signInService;
+ if (localSignInService != null) {
+ localSignInService.signIn(this::handleSignInDone, this::handleConnectionLost,
this::handleUnauthorizedWhileSignIn);
}
}
- private void handleRefreshDone(@Nullable GroupContentResponseModel groupContentResponse,
+ private void initializationDone(@Nullable GroupContentResponseModel groupContentResponse,
@Nullable String errorMessage) {
- logger.trace("OJElectronicsCloudHandler.handleRefreshDone({})", groupContentResponse);
+ logger.trace("OJElectronicsCloudHandler.initializationDone({})", groupContentResponse);
if (groupContentResponse != null && groupContentResponse.errorCode == 0) {
- internalRefreshDone(groupContentResponse);
+ internalInitializationDone(groupContentResponse);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
(errorMessage == null) ? "Wrong or no result model; Refreshing stoppped" : errorMessage);
- final RefreshService refreshService = this.refreshService;
- if (refreshService != null) {
- refreshService.stop();
+ final RefreshService localRefreshService = this.refreshService;
+ if (localRefreshService != null) {
+ localRefreshService.stop();
}
}
}
- private void internalRefreshDone(GroupContentResponseModel groupContentResponse) {
- new RefreshGroupContentService(groupContentResponse.groupContents, getThing().getThings()).handle();
- final OJDiscoveryService discoveryService = this.discoveryService;
- if (discoveryService != null) {
- discoveryService.setScanResultForDiscovery(groupContentResponse.groupContents);
+ private void refreshDone(@Nullable SignalRResultModel resultModel, @Nullable String errorMessage) {
+ logger.trace("OJElectronicsCloudHandler.refreshDone({})", resultModel);
+ if (resultModel != null) {
+ new RefreshThermostatsService(resultModel.getThermostats(), resultModel.getThermostatRealTimes(),
+ getThing().getThings()).handle();
+ } else {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ (errorMessage == null) ? "Wrong or no result model; Refreshing stoppped" : errorMessage);
+ final RefreshService localRefreshService = this.refreshService;
+ if (localRefreshService != null) {
+ localRefreshService.stop();
+ }
}
- final UpdateService updateService = this.updateService;
- if (updateService != null) {
- updateService.updateAllThermostats(getThing().getThings());
+ }
+
+ private void internalInitializationDone(GroupContentResponseModel groupContentResponse) {
+ new RefreshGroupContentService(groupContentResponse.groupContents, getThing().getThings()).handle();
+ final OJDiscoveryService localDiscoveryService = this.discoveryService;
+ if (localDiscoveryService != null) {
+ localDiscoveryService.setScanResultForDiscovery(groupContentResponse.groupContents);
}
}
private void handleSignInDone(String sessionId) {
logger.trace("OJElectronicsCloudHandler.handleSignInDone({})", sessionId);
if (refreshService == null) {
- refreshService = new RefreshService(configuration, httpClient, scheduler);
+ refreshService = new RefreshService(configuration, httpClient);
}
- final RefreshService refreshService = this.refreshService;
- if (refreshService != null) {
- refreshService.start(sessionId, this::handleRefreshDone, this::handleConnectionLost,
- this::handleUnauthorized);
+ final RefreshService localRefreshService = this.refreshService;
+ if (localRefreshService != null) {
+ localRefreshService.start(sessionId, this::initializationDone, this::refreshDone,
+ this::handleConnectionLost, this::handleUnauthorized);
updateStatus(ThingStatus.ONLINE);
}
- this.updateService = new UpdateService(configuration, httpClient, sessionId);
+ this.updateService = new UpdateService(configuration, httpClient, this::handleConnectionLost,
+ this::handleUnauthorized);
}
private void handleUnauthorized() {
logger.trace("OJElectronicsCloudHandler.handleUnauthorized()");
- final RefreshService refreshService = this.refreshService;
- if (refreshService != null) {
- refreshService.stop();
+ final RefreshService localRefreshService = this.refreshService;
+ if (localRefreshService != null) {
+ localRefreshService.stop();
}
restartRefreshServiceAsync(1);
}
@@ -165,20 +193,29 @@ public class OJCloudHandler extends BaseBridgeHandler implements BridgeHandler {
logger.trace("OJElectronicsCloudHandler.handleUnauthorizedWhileSignIn()");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not sign in. Check user name and password.");
- final RefreshService refreshService = this.refreshService;
- if (refreshService != null) {
- refreshService.stop();
+ final RefreshService localRefreshService = this.refreshService;
+ if (localRefreshService != null) {
+ localRefreshService.stop();
}
}
- private void handleConnectionLost() {
- logger.trace("OJElectronicsCloudHandler.handleConnectionLost()");
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
- final RefreshService refreshService = this.refreshService;
- if (refreshService != null) {
- refreshService.stop();
+ public void reInitialize() {
+ logger.trace("OJElectronicsCloudHandler.reInitialize()");
+ final RefreshService localRefreshService = this.refreshService;
+ if (localRefreshService != null) {
+ localRefreshService.stop();
}
- restartRefreshServiceAsync(configuration.refreshDelayInSeconds);
+ restartRefreshServiceAsync(1);
+ }
+
+ private void handleConnectionLost(@Nullable String message) {
+ logger.trace("OJElectronicsCloudHandler.handleConnectionLost()");
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message);
+ final RefreshService localRefreshService = this.refreshService;
+ if (localRefreshService != null) {
+ localRefreshService.stop();
+ }
+ restartRefreshServiceAsync(30);
}
private void restartRefreshServiceAsync(long delayInSeconds) {
@@ -191,6 +228,6 @@ public class OJCloudHandler extends BaseBridgeHandler implements BridgeHandler {
@Override
public Collection> getServices() {
- return Collections.singleton(OJDiscoveryService.class);
+ return Set.of(OJDiscoveryService.class);
}
}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/OJCloudHandlerFactory.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/OJCloudHandlerFactory.java
index 04b92d0f825..718494f0fcc 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/OJCloudHandlerFactory.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/OJCloudHandlerFactory.java
@@ -14,7 +14,6 @@ package org.openhab.binding.ojelectronics.internal;
import static org.openhab.binding.ojelectronics.internal.BindingConstants.THING_TYPE_OJCLOUD;
-import java.util.Collections;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -40,7 +39,7 @@ import org.osgi.service.component.annotations.Reference;
@Component(configurationPid = "binding.ojelectronics", service = ThingHandlerFactory.class)
public class OJCloudHandlerFactory extends BaseThingHandlerFactory {
- private static final Set SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_OJCLOUD);
+ private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_OJCLOUD);
private final HttpClient httpClient;
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/ThermostatHandler.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/ThermostatHandler.java
index 5bc823e2a13..2bcfec98fb0 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/ThermostatHandler.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/ThermostatHandler.java
@@ -20,6 +20,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
+import java.util.Objects;
import java.util.function.Consumer;
import javax.measure.quantity.Temperature;
@@ -27,7 +28,8 @@ import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.ojelectronics.internal.config.OJElectronicsThermostatConfiguration;
-import org.openhab.binding.ojelectronics.internal.models.Thermostat;
+import org.openhab.binding.ojelectronics.internal.models.thermostat.ThermostatModel;
+import org.openhab.binding.ojelectronics.internal.models.thermostat.ThermostatRealTimeValuesModel;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
@@ -35,10 +37,12 @@ import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.binding.BaseThingHandler;
+import org.openhab.core.thing.binding.BridgeHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
@@ -58,12 +62,13 @@ public class ThermostatHandler extends BaseThingHandler {
private final String serialNumber;
private final Logger logger = LoggerFactory.getLogger(ThermostatHandler.class);
- private final Map> channelrefreshActions = createChannelRefreshActionMap();
+ private final Map> channelRefreshActions = createChannelRefreshActionMap();
+ private final Map> channelRealTimeRefreshActions = createRealTimeChannelRefreshActionMap();
private final Map> updateThermostatValueActions = createUpdateThermostatValueActionMap();
private final TimeZoneProvider timeZoneProvider;
private LinkedList> updatedValues = new LinkedList<>();
- private @Nullable Thermostat currentThermostat;
+ private @Nullable ThermostatModel currentThermostat;
/**
* Creates a new instance of {@link ThermostatHandler}
@@ -92,9 +97,9 @@ public class ThermostatHandler extends BaseThingHandler {
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
- final Thermostat thermostat = currentThermostat;
- if (thermostat != null && channelrefreshActions.containsKey(channelUID.getId())) {
- final @Nullable Consumer consumer = channelrefreshActions.get(channelUID.getId());
+ final ThermostatModel thermostat = currentThermostat;
+ if (thermostat != null && channelRefreshActions.containsKey(channelUID.getId())) {
+ final @Nullable Consumer consumer = channelRefreshActions.get(channelUID.getId());
if (consumer != null) {
consumer.accept(thermostat);
}
@@ -102,6 +107,14 @@ public class ThermostatHandler extends BaseThingHandler {
} else {
synchronized (this) {
updatedValues.add(new AbstractMap.SimpleImmutableEntry(channelUID.getId(), command));
+
+ BridgeHandler bridgeHandler = Objects.requireNonNull(getBridge()).getHandler();
+ if (bridgeHandler != null) {
+ ((OJCloudHandler) (bridgeHandler)).updateThinksChannelValuesToCloud();
+ } else {
+ currentThermostat = null;
+ updateStatus(ThingStatus.OFFLINE);
+ }
}
}
}
@@ -111,7 +124,15 @@ public class ThermostatHandler extends BaseThingHandler {
*/
@Override
public void initialize() {
- updateStatus(ThingStatus.ONLINE);
+ @Nullable
+ Bridge bridge = getBridge();
+ if (bridge != null && bridge.getStatus() == ThingStatus.ONLINE && currentThermostat == null) {
+ @Nullable
+ OJCloudHandler bridgeHandler = (OJCloudHandler) (bridge.getHandler());
+ if (bridgeHandler != null) {
+ bridgeHandler.reInitialize();
+ }
+ }
}
/**
@@ -119,17 +140,37 @@ public class ThermostatHandler extends BaseThingHandler {
*
* @param thermostat thermostat values
*/
- public void handleThermostatRefresh(Thermostat thermostat) {
+ public void handleThermostatRefresh(ThermostatModel thermostat) {
+ if (currentThermostat == null) {
+ updateStatus(ThingStatus.ONLINE);
+ }
currentThermostat = thermostat;
- channelrefreshActions.forEach((channelUID, action) -> action.accept(thermostat));
+ channelRefreshActions.forEach((channelUID, action) -> action.accept(thermostat));
}
/**
- * Gets a {@link Thermostat} with changed values or null if nothing has changed
+ * Sets the values after refreshing the thermostats values
*
- * @return The changed {@link Thermostat}
+ * @param thermostat thermostat values
*/
- public @Nullable Thermostat tryHandleAndGetUpdatedThermostat() {
+ public void handleThermostatRefresh(ThermostatRealTimeValuesModel thermostat) {
+ final ThermostatModel currentThermostat = this.currentThermostat;
+ if (currentThermostat != null) {
+ currentThermostat.heating = thermostat.heating;
+ currentThermostat.floorTemperature = thermostat.floorTemperature;
+ currentThermostat.action = thermostat.action;
+ currentThermostat.online = thermostat.online;
+ currentThermostat.roomTemperature = thermostat.roomTemperature;
+ channelRealTimeRefreshActions.forEach((channelUID, action) -> action.accept(thermostat));
+ }
+ }
+
+ /**
+ * Gets a {@link ThermostatModel} with changed values or null if nothing has changed
+ *
+ * @return The changed {@link ThermostatModel}
+ */
+ public @Nullable ThermostatModel tryHandleAndGetUpdatedThermostat() {
final LinkedList> updatedValues = this.updatedValues;
if (updatedValues.isEmpty()) {
return null;
@@ -146,59 +187,64 @@ public class ThermostatHandler extends BaseThingHandler {
return currentThermostat;
}
- private void updateManualSetpoint(Thermostat thermostat) {
+ private ThermostatModel getCurrentThermostat() {
+ return Objects.requireNonNull(currentThermostat);
+ }
+
+ private void updateManualSetpoint(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_MANUALSETPOINT,
new QuantityType(thermostat.manualModeSetpoint / (double) 100, SIUnits.CELSIUS));
}
private void updateManualSetpoint(Command command) {
if (command instanceof QuantityType>) {
- currentThermostat.manualModeSetpoint = (int) (((QuantityType>) command).floatValue() * 100);
+ getCurrentThermostat().manualModeSetpoint = (int) (((QuantityType>) command).floatValue() * 100);
} else {
logger.warn("Unable to set value {}", command);
}
}
- private void updateBoostEndTime(Thermostat thermostat) {
+ private void updateBoostEndTime(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_BOOSTENDTIME, new DateTimeType(
ZonedDateTime.ofInstant(thermostat.boostEndTime.toInstant(), timeZoneProvider.getTimeZone())));
}
private void updateBoostEndTime(Command command) {
if (command instanceof DateTimeType) {
- currentThermostat.boostEndTime = Date.from(((DateTimeType) command).getZonedDateTime().toInstant());
+ getCurrentThermostat().boostEndTime = Date.from(((DateTimeType) command).getZonedDateTime().toInstant());
} else {
logger.warn("Unable to set value {}", command);
}
}
- private void updateComfortEndTime(Thermostat thermostat) {
+ private void updateComfortEndTime(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_COMFORTENDTIME, new DateTimeType(
ZonedDateTime.ofInstant(thermostat.comfortEndTime.toInstant(), timeZoneProvider.getTimeZone())));
}
private void updateComfortEndTime(Command command) {
if (command instanceof DateTimeType) {
- currentThermostat.comfortEndTime = Date.from(((DateTimeType) command).getZonedDateTime().toInstant());
+ getCurrentThermostat().comfortEndTime = Objects
+ .requireNonNull(Date.from(((DateTimeType) command).getZonedDateTime().toInstant()));
} else {
logger.warn("Unable to set value {}", command);
}
}
- private void updateComfortSetpoint(Thermostat thermostat) {
+ private void updateComfortSetpoint(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_COMFORTSETPOINT,
new QuantityType(thermostat.comfortSetpoint / (double) 100, SIUnits.CELSIUS));
}
private void updateComfortSetpoint(Command command) {
if (command instanceof QuantityType>) {
- currentThermostat.comfortSetpoint = (int) (((QuantityType>) command).floatValue() * 100);
+ getCurrentThermostat().comfortSetpoint = (int) (((QuantityType>) command).floatValue() * 100);
} else {
logger.warn("Unable to set value {}", command);
}
}
- private void updateRegulationMode(Thermostat thermostat) {
+ private void updateRegulationMode(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_REGULATIONMODE,
StringType.valueOf(getRegulationMode(thermostat.regulationMode)));
}
@@ -207,51 +253,71 @@ public class ThermostatHandler extends BaseThingHandler {
if (command instanceof StringType && (REVERSE_REGULATION_MODES.containsKey(command.toString().toLowerCase()))) {
final @Nullable Integer mode = REVERSE_REGULATION_MODES.get(command.toString().toLowerCase());
if (mode != null) {
- currentThermostat.regulationMode = mode;
+ getCurrentThermostat().regulationMode = mode;
}
} else {
logger.warn("Unable to set value {}", command);
}
}
- private void updateThermostatName(Thermostat thermostat) {
+ private void updateThermostatName(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_THERMOSTATNAME, StringType.valueOf(thermostat.thermostatName));
}
- private void updateFloorTemperature(Thermostat thermostat) {
+ private void updateFloorTemperature(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_FLOORTEMPERATURE,
new QuantityType(thermostat.floorTemperature / (double) 100, SIUnits.CELSIUS));
}
- private void updateRoomTemperature(Thermostat thermostat) {
+ private void updateFloorTemperature(ThermostatRealTimeValuesModel thermostatRealTimeValues) {
+ updateState(BindingConstants.CHANNEL_OWD5_FLOORTEMPERATURE, new QuantityType(
+ thermostatRealTimeValues.floorTemperature / (double) 100, SIUnits.CELSIUS));
+ }
+
+ private void updateRoomTemperature(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_ROOMTEMPERATURE,
new QuantityType(thermostat.roomTemperature / (double) 100, SIUnits.CELSIUS));
}
- private void updateHeating(Thermostat thermostat) {
+ private void updateRoomTemperature(ThermostatRealTimeValuesModel thermostatRealTimeValues) {
+ updateState(BindingConstants.CHANNEL_OWD5_ROOMTEMPERATURE, new QuantityType(
+ thermostatRealTimeValues.roomTemperature / (double) 100, SIUnits.CELSIUS));
+ }
+
+ private void updateHeating(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_HEATING,
thermostat.heating ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
}
- private void updateOnline(Thermostat thermostat) {
+ private void updateHeating(ThermostatRealTimeValuesModel thermostatRealTimeValues) {
+ updateState(BindingConstants.CHANNEL_OWD5_HEATING,
+ thermostatRealTimeValues.heating ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
+ }
+
+ private void updateOnline(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_ONLINE,
thermostat.online ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
}
- private void updateGroupId(Thermostat thermostat) {
+ private void updateOnline(ThermostatRealTimeValuesModel thermostatRealTimeValues) {
+ updateState(BindingConstants.CHANNEL_OWD5_ONLINE,
+ thermostatRealTimeValues.online ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
+ }
+
+ private void updateGroupId(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_GROUPID, new DecimalType(thermostat.groupId));
}
- private void updateGroupName(Thermostat thermostat) {
+ private void updateGroupName(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_GROUPNAME, StringType.valueOf(thermostat.groupName));
}
- private void updateVacationEnabled(Thermostat thermostat) {
+ private void updateVacationEnabled(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_VACATIONENABLED,
thermostat.online ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
}
- private void updateVacationBeginDay(Thermostat thermostat) {
+ private void updateVacationBeginDay(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_VACATIONBEGINDAY,
new DateTimeType(
ZonedDateTime.ofInstant(thermostat.vacationBeginDay.toInstant(), timeZoneProvider.getTimeZone())
@@ -260,14 +326,14 @@ public class ThermostatHandler extends BaseThingHandler {
private void updateVacationBeginDay(Command command) {
if (command instanceof DateTimeType) {
- currentThermostat.vacationBeginDay = Date
+ getCurrentThermostat().vacationBeginDay = Date
.from(((DateTimeType) command).getZonedDateTime().toInstant().truncatedTo(ChronoUnit.DAYS));
} else {
logger.warn("Unable to set value {}", command);
}
}
- private void updateVacationEndDay(Thermostat thermostat) {
+ private void updateVacationEndDay(ThermostatModel thermostat) {
updateState(BindingConstants.CHANNEL_OWD5_VACATIONENDDAY,
new DateTimeType(
ZonedDateTime.ofInstant(thermostat.vacationEndDay.toInstant(), timeZoneProvider.getTimeZone())
@@ -276,7 +342,7 @@ public class ThermostatHandler extends BaseThingHandler {
private void updateVacationEndDay(Command command) {
if (command instanceof DateTimeType) {
- currentThermostat.vacationEndDay = Date
+ getCurrentThermostat().vacationEndDay = Date
.from(((DateTimeType) command).getZonedDateTime().toInstant().truncatedTo(ChronoUnit.DAYS));
} else {
logger.warn("Unable to set value {}", command);
@@ -311,8 +377,8 @@ public class ThermostatHandler extends BaseThingHandler {
return map;
};
- private Map> createChannelRefreshActionMap() {
- HashMap> map = new HashMap<>();
+ private Map> createChannelRefreshActionMap() {
+ HashMap> map = new HashMap<>();
map.put(BindingConstants.CHANNEL_OWD5_GROUPNAME, this::updateGroupName);
map.put(BindingConstants.CHANNEL_OWD5_GROUPID, this::updateGroupId);
map.put(BindingConstants.CHANNEL_OWD5_ONLINE, this::updateOnline);
@@ -331,6 +397,15 @@ public class ThermostatHandler extends BaseThingHandler {
return map;
}
+ private Map> createRealTimeChannelRefreshActionMap() {
+ HashMap> map = new HashMap<>();
+ map.put(BindingConstants.CHANNEL_OWD5_ONLINE, this::updateOnline);
+ map.put(BindingConstants.CHANNEL_OWD5_HEATING, this::updateHeating);
+ map.put(BindingConstants.CHANNEL_OWD5_ROOMTEMPERATURE, this::updateRoomTemperature);
+ map.put(BindingConstants.CHANNEL_OWD5_FLOORTEMPERATURE, this::updateFloorTemperature);
+ return map;
+ }
+
private Map> createUpdateThermostatValueActionMap() {
HashMap> map = new HashMap<>();
map.put(BindingConstants.CHANNEL_OWD5_REGULATIONMODE, this::updateRegulationMode);
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/ThermostatHandlerFactory.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/ThermostatHandlerFactory.java
index 62dc380516c..6e7ea95dedf 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/ThermostatHandlerFactory.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/ThermostatHandlerFactory.java
@@ -14,7 +14,6 @@ package org.openhab.binding.ojelectronics.internal;
import static org.openhab.binding.ojelectronics.internal.BindingConstants.THING_TYPE_OWD5;
-import java.util.Collections;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -38,7 +37,7 @@ import org.osgi.service.component.annotations.Reference;
@Component(configurationPid = "binding.ojelectronics", service = ThingHandlerFactory.class)
public class ThermostatHandlerFactory extends BaseThingHandlerFactory {
- private static final Set SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_OWD5);
+ private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_OWD5);
private final TimeZoneProvider timeZoneProvider;
/**
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/common/SignalRLogger.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/common/SignalRLogger.java
new file mode 100644
index 00000000000..af85dcd2056
--- /dev/null
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/common/SignalRLogger.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.ojelectronics.internal.common;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.slf4j.LoggerFactory;
+
+import com.github.signalr4j.client.LogLevel;
+import com.github.signalr4j.client.Logger;
+
+/**
+ * Logs SignalR information
+ *
+ * @author Christian Kittel - Initial Contribution
+ */
+@NonNullByDefault
+public class SignalRLogger implements Logger {
+
+ private final org.slf4j.Logger logger = LoggerFactory.getLogger(SignalRLogger.class);
+
+ @Override
+ public void log(@Nullable String message, @Nullable LogLevel level) {
+ if (message == null || level == null) {
+ return;
+ }
+ switch (level) {
+ case Critical:
+ logger.warn("Critical SignalR Message: {}", message);
+ break;
+ case Information:
+ logger.info("SignalR information message: {}", message);
+ break;
+ case Verbose:
+ default:
+ logger.trace("SignalR information message: {}", message);
+ break;
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/config/OJElectronicsBridgeConfiguration.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/config/OJElectronicsBridgeConfiguration.java
index a341e63d7a6..9e67b076d31 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/config/OJElectronicsBridgeConfiguration.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/config/OJElectronicsBridgeConfiguration.java
@@ -13,6 +13,7 @@
package org.openhab.binding.ojelectronics.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
/**
* The configuration for {@link org.openhab.binding.ojelectronics.internal.OJElectronicsCloudHandler}
@@ -40,7 +41,7 @@ public class OJElectronicsBridgeConfiguration {
/**
* Url for API
*/
- public String apiUrl = "https://OWD5-OJ001-App.ojelectronics.com/api";
+ private String apiUrl = "https://OWD5-OJ001-App.ojelectronics.com";
/**
* API-Key
@@ -52,8 +53,29 @@ public class OJElectronicsBridgeConfiguration {
*/
public int softwareVersion = 1060;
- /**
- * Refresh-Delay
+ private @Nullable String restApiUrl;
+
+ /*
+ * Gets the Api-URL
*/
- public long refreshDelayInSeconds = 30;
+ public String getRestApiUrl() {
+ String localRestApiUrl = restApiUrl;
+ if (localRestApiUrl == null) {
+ localRestApiUrl = restApiUrl = apiUrl.replace("/api", "") + "/api";
+ }
+ return localRestApiUrl;
+ }
+
+ private @Nullable String signalRApiUrl;
+
+ /*
+ * Gets the SignalR Notification URL
+ */
+ public String getSignalRUrl() {
+ String localSignalRApiUrl = signalRApiUrl;
+ if (localSignalRApiUrl == null) {
+ localSignalRApiUrl = signalRApiUrl = apiUrl.replace("/api", "") + "/ocd5notification";
+ }
+ return localSignalRApiUrl;
+ }
}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/SignalRResultModel.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/SignalRResultModel.java
new file mode 100644
index 00000000000..8b8b62220d6
--- /dev/null
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/SignalRResultModel.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.ojelectronics.internal.models;
+
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.ojelectronics.internal.models.groups.GroupContentModel;
+import org.openhab.binding.ojelectronics.internal.models.thermostat.ThermostatModel;
+import org.openhab.binding.ojelectronics.internal.models.thermostat.ThermostatRealTimeValuesModel;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Model for a SignalR query result
+ *
+ * @author Christian Kittel - Initial contribution
+ */
+@NonNullByDefault
+public class SignalRResultModel {
+ @SerializedName("Groups")
+ private List groups = List.of();
+ @SerializedName("SequenceNr")
+ private int sequenceNr;
+
+ @SerializedName("ThermostatRealTimes")
+ private List thermostatRealTimes = List.of();
+
+ @SerializedName("Thermostats")
+ private List thermostats = List.of();
+
+ public List getGroups() {
+ return this.groups;
+ }
+
+ public int getSequenceNr() {
+ return this.sequenceNr;
+ }
+
+ public List getThermostatRealTimes() {
+ return this.thermostatRealTimes;
+ }
+
+ public List getThermostats() {
+ return this.thermostats;
+ }
+
+ public void setGroups(List paramArrayList) {
+ this.groups = paramArrayList;
+ }
+
+ public void setSequenceNr(int paramInt) {
+ this.sequenceNr = paramInt;
+ }
+
+ public void setThermostatRealTimes(List paramArrayList) {
+ this.thermostatRealTimes = paramArrayList;
+ }
+
+ public void setThermostats(List paramArrayList) {
+ this.thermostats = paramArrayList;
+ }
+}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/Day.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/DayModel.java
similarity index 89%
rename from bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/Day.java
rename to bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/DayModel.java
index 6b088a1cade..fca68d44d08 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/Day.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/DayModel.java
@@ -23,9 +23,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
* @author Christian Kittel - Initial contribution
*/
@NonNullByDefault
-public class Day {
+public class DayModel {
public int weekDayGrpNo;
- public List events = new ArrayList<>();
+ public List events = new ArrayList<>();
}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/Event.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/EventModel.java
similarity index 96%
rename from bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/Event.java
rename to bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/EventModel.java
index e91d00461fe..49cbd4c02bb 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/Event.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/EventModel.java
@@ -20,7 +20,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
* @author Christian Kittel - Initial contribution
*/
@NonNullByDefault
-public class Event {
+public class EventModel {
public int scheduleType;
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/GroupContent.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/GroupContentModel.java
similarity index 83%
rename from bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/GroupContent.java
rename to bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/GroupContentModel.java
index 9ef2bbcde3f..6d8576302c8 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/GroupContent.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/GroupContentModel.java
@@ -17,7 +17,7 @@ import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.binding.ojelectronics.internal.models.Thermostat;
+import org.openhab.binding.ojelectronics.internal.models.thermostat.ThermostatModel;
/**
* Model for content of a group
@@ -25,7 +25,7 @@ import org.openhab.binding.ojelectronics.internal.models.Thermostat;
* @author Christian Kittel - Initial contribution
*/
@NonNullByDefault
-public class GroupContent {
+public class GroupContentModel {
public int action;
@@ -33,11 +33,11 @@ public class GroupContent {
public String groupName = "";
- public List thermostats = new ArrayList();
+ public List thermostats = new ArrayList();
public int regulationMode;
- public @Nullable Schedule schedule;
+ public @Nullable ScheduleModel schedule;
public int comfortSetpoint;
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/GroupContentResponseModel.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/GroupContentResponseModel.java
index b080ca0642c..c54cdeaa90c 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/GroupContentResponseModel.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/GroupContentResponseModel.java
@@ -26,5 +26,5 @@ import org.openhab.binding.ojelectronics.internal.models.ResponseModelBase;
@NonNullByDefault
public class GroupContentResponseModel extends ResponseModelBase {
- public List groupContents = new ArrayList();
+ public List groupContents = new ArrayList();
}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/Schedule.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/ScheduleModel.java
similarity index 88%
rename from bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/Schedule.java
rename to bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/ScheduleModel.java
index 3ce6028544c..22c63a058a2 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/Schedule.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/groups/ScheduleModel.java
@@ -23,9 +23,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
* @author Christian Kittel - Initial contribution
*/
@NonNullByDefault
-public class Schedule {
+public class ScheduleModel {
- public List days = new ArrayList();
+ public List days = new ArrayList();
public boolean modifiedDueToVerification;
}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/Thermostat.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/thermostat/ThermostatModel.java
similarity index 90%
rename from bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/Thermostat.java
rename to bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/thermostat/ThermostatModel.java
index 774d5b8d563..b0990bfbb40 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/Thermostat.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/thermostat/ThermostatModel.java
@@ -10,13 +10,13 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
-package org.openhab.binding.ojelectronics.internal.models;
+package org.openhab.binding.ojelectronics.internal.models.thermostat;
import java.util.Date;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.binding.ojelectronics.internal.models.groups.Schedule;
+import org.openhab.binding.ojelectronics.internal.models.groups.ScheduleModel;
import com.google.gson.annotations.SerializedName;
@@ -26,14 +26,12 @@ import com.google.gson.annotations.SerializedName;
* @author Christian Kittel - Initial contribution
*/
@NonNullByDefault
-public class Thermostat {
+public class ThermostatModel extends ThermostatModelBase {
public int id;
public int action;
- public String serialNumber = "";
-
public String groupName = "";
public int groupId;
@@ -53,7 +51,7 @@ public class Thermostat {
public int regulationMode;
- public @Nullable Schedule schedule;
+ public @Nullable ScheduleModel schedule;
public int comfortSetpoint;
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/thermostat/ThermostatModelBase.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/thermostat/ThermostatModelBase.java
new file mode 100644
index 00000000000..ed874e2a2f1
--- /dev/null
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/thermostat/ThermostatModelBase.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.ojelectronics.internal.models.thermostat;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Base-Model for thermostat models
+ *
+ * @author Christian Kittel - Initial contribution
+ */
+@NonNullByDefault
+public class ThermostatModelBase {
+
+ public String serialNumber = "";
+}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/thermostat/ThermostatRealTimeValuesModel.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/thermostat/ThermostatRealTimeValuesModel.java
new file mode 100644
index 00000000000..d41b3bcfc5e
--- /dev/null
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/thermostat/ThermostatRealTimeValuesModel.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.ojelectronics.internal.models.thermostat;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Model for realtime values of a thermostat
+ *
+ * @author Christian Kittel - Initial contribution
+ */
+@NonNullByDefault
+public class ThermostatRealTimeValuesModel extends ThermostatModelBase {
+
+ public int action;
+
+ public int floorTemperature;
+
+ public boolean heating;
+
+ public int id;
+
+ public boolean online;
+
+ public int roomTemperature;
+
+ public int sensorAppl;
+}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/thermostat/UpdateThermostatRequestModel.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/thermostat/UpdateThermostatRequestModel.java
index c3ccdba3f89..d3b6ec796d8 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/thermostat/UpdateThermostatRequestModel.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/models/thermostat/UpdateThermostatRequestModel.java
@@ -14,7 +14,6 @@ package org.openhab.binding.ojelectronics.internal.models.thermostat;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.ojelectronics.internal.models.RequestModelBase;
-import org.openhab.binding.ojelectronics.internal.models.Thermostat;
/**
* Model for updating a thermostat
@@ -24,12 +23,12 @@ import org.openhab.binding.ojelectronics.internal.models.Thermostat;
@NonNullByDefault
public class UpdateThermostatRequestModel extends RequestModelBase {
- public UpdateThermostatRequestModel(Thermostat thermostat) {
+ public UpdateThermostatRequestModel(ThermostatModel thermostat) {
setThermostat = thermostat;
thermostatID = thermostat.serialNumber;
}
- public Thermostat setThermostat;
+ public ThermostatModel setThermostat;
public String thermostatID;
}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/OJDiscoveryService.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/OJDiscoveryService.java
index 7409752eb8e..d37334601a4 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/OJDiscoveryService.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/OJDiscoveryService.java
@@ -15,14 +15,13 @@ package org.openhab.binding.ojelectronics.internal.services;
import static org.openhab.binding.ojelectronics.internal.BindingConstants.*;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.ojelectronics.internal.OJCloudHandler;
-import org.openhab.binding.ojelectronics.internal.models.groups.GroupContent;
+import org.openhab.binding.ojelectronics.internal.models.groups.GroupContentModel;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
@@ -39,12 +38,11 @@ import org.osgi.service.component.annotations.Component;
*/
@NonNullByDefault
@Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.ojelectronics")
-public final class OJDiscoveryService extends AbstractDiscoveryService
- implements DiscoveryService, ThingHandlerService {
+public final class OJDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService {
- private static final Set SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_OJCLOUD);
+ private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_OJCLOUD);
private @Nullable OJCloudHandler bridgeHandler;
- private @Nullable Collection groupContents;
+ private @Nullable Collection groupContents;
/**
* Creates a new instance of {@link OJDiscoveryService}
@@ -59,14 +57,14 @@ public final class OJDiscoveryService extends AbstractDiscoveryService
*
* @param groupContents Content from API
*/
- public void setScanResultForDiscovery(List groupContents) {
+ public void setScanResultForDiscovery(List groupContents) {
this.groupContents = groupContents;
}
@Override
protected void startScan() {
final OJCloudHandler bridgeHandler = this.bridgeHandler;
- final Collection groupContents = this.groupContents;
+ final Collection groupContents = this.groupContents;
if (groupContents != null && bridgeHandler != null) {
groupContents.stream().flatMap(content -> content.thermostats.stream())
.forEach(thermostat -> thingDiscovered(bridgeHandler.getThing().getUID(), thermostat.serialNumber));
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/RefreshGroupContentService.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/RefreshGroupContentService.java
index 8cdaf1ea4d4..bba63f40473 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/RefreshGroupContentService.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/RefreshGroupContentService.java
@@ -12,12 +12,13 @@
*/
package org.openhab.binding.ojelectronics.internal.services;
+import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.ojelectronics.internal.ThermostatHandler;
-import org.openhab.binding.ojelectronics.internal.models.Thermostat;
-import org.openhab.binding.ojelectronics.internal.models.groups.GroupContent;
+import org.openhab.binding.ojelectronics.internal.models.groups.GroupContentModel;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,17 +31,17 @@ import org.slf4j.LoggerFactory;
@NonNullByDefault
public class RefreshGroupContentService {
- private final List groupContentList;
+ private final List groupContentList;
private final Logger logger = LoggerFactory.getLogger(RefreshGroupContentService.class);
private List things;
/**
* Creates a new instance of {@link RefreshGroupContentService}
*
- * @param groupContents {@link GroupContent}
+ * @param groupContents {@link GroupContentModel}
* @param things Things
*/
- public RefreshGroupContentService(List groupContents, List things) {
+ public RefreshGroupContentService(List groupContents, List things) {
this.groupContentList = groupContents;
this.things = things;
if (this.things.isEmpty()) {
@@ -52,13 +53,7 @@ public class RefreshGroupContentService {
* Handles the changes to all things.
*/
public void handle() {
- groupContentList.stream().flatMap(entry -> entry.thermostats.stream()).forEach(this::handleThermostat);
- }
-
- private void handleThermostat(Thermostat thermostat) {
- things.stream().filter(thing -> thing.getHandler() instanceof ThermostatHandler)
- .map(thing -> (ThermostatHandler) thing.getHandler())
- .filter(thingHandler -> thingHandler.getSerialNumber().equals(thermostat.serialNumber))
- .forEach(thingHandler -> thingHandler.handleThermostatRefresh(thermostat));
+ new RefreshThermostatsService(groupContentList.stream().flatMap(entry -> entry.thermostats.stream())
+ .collect(Collectors.toCollection(ArrayList::new)), things).handle();
}
}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/RefreshService.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/RefreshService.java
index 446931de725..39930766081 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/RefreshService.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/RefreshService.java
@@ -12,10 +12,9 @@
*/
package org.openhab.binding.ojelectronics.internal.services;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
+import java.util.Objects;
import java.util.function.BiConsumer;
+import java.util.function.Consumer;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@@ -26,11 +25,16 @@ import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.openhab.binding.ojelectronics.internal.common.OJGSonBuilder;
+import org.openhab.binding.ojelectronics.internal.common.SignalRLogger;
import org.openhab.binding.ojelectronics.internal.config.OJElectronicsBridgeConfiguration;
+import org.openhab.binding.ojelectronics.internal.models.SignalRResultModel;
import org.openhab.binding.ojelectronics.internal.models.groups.GroupContentResponseModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.github.signalr4j.client.Connection;
+import com.github.signalr4j.client.ConnectionState;
+import com.github.signalr4j.client.Platform;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
@@ -47,14 +51,14 @@ public final class RefreshService implements AutoCloseable {
private final HttpClient httpClient;
private final Gson gson = OJGSonBuilder.getGSon();
- private final ScheduledExecutorService schedulerService;
-
- private @Nullable Runnable connectionLost;
- private @Nullable BiConsumer<@Nullable GroupContentResponseModel, @Nullable String> refreshDone;
- private @Nullable ScheduledFuture> scheduler;
+ private @Nullable Consumer<@Nullable String> connectionLost;
+ private @Nullable BiConsumer<@Nullable GroupContentResponseModel, @Nullable String> initializationDone;
+ private @Nullable BiConsumer<@Nullable SignalRResultModel, @Nullable String> refreshDone;
private @Nullable Runnable unauthorized;
private @Nullable String sessionId;
- private static boolean destroyed = false;
+ private @Nullable Connection signalRConnection;
+ private boolean destroyed = false;
+ private boolean isInitializing = false;
/**
* Creates a new instance of {@link RefreshService}
@@ -63,11 +67,10 @@ public final class RefreshService implements AutoCloseable {
* @param httpClient HTTP client
* @param updateService Service to update the thermostat in the cloud
*/
- public RefreshService(OJElectronicsBridgeConfiguration config, HttpClient httpClient,
- ScheduledExecutorService schedulerService) {
+ public RefreshService(OJElectronicsBridgeConfiguration config, HttpClient httpClient) {
this.config = config;
this.httpClient = httpClient;
- this.schedulerService = schedulerService;
+ Platform.loadPlatformComponent(null);
}
/**
@@ -78,17 +81,21 @@ public final class RefreshService implements AutoCloseable {
* @param connectionLosed This method is called if no connection could established.
* @param unauthorized This method is called if the result is unauthorized.
*/
- public void start(String sessionId, BiConsumer<@Nullable GroupContentResponseModel, @Nullable String> refreshDone,
- Runnable connectionLost, Runnable unauthorized) {
+ public void start(String sessionId,
+ BiConsumer<@Nullable GroupContentResponseModel, @Nullable String> initializationDone,
+ BiConsumer<@Nullable SignalRResultModel, @Nullable String> refreshDone,
+ Consumer<@Nullable String> connectionLost, Runnable unauthorized) {
logger.trace("RefreshService.startService({})", sessionId);
this.connectionLost = connectionLost;
+ this.initializationDone = initializationDone;
this.refreshDone = refreshDone;
this.unauthorized = unauthorized;
this.sessionId = sessionId;
- long refreshTime = config.refreshDelayInSeconds;
- scheduler = schedulerService.scheduleWithFixedDelay(this::refresh, refreshTime, refreshTime, TimeUnit.SECONDS);
- refresh();
+
+ signalRConnection = createSignalRConnection();
destroyed = false;
+ isInitializing = false;
+ initializeGroups(true);
}
/**
@@ -96,25 +103,70 @@ public final class RefreshService implements AutoCloseable {
*/
public void stop() {
destroyed = true;
- final ScheduledFuture> scheduler = this.scheduler;
- if (scheduler != null) {
- scheduler.cancel(false);
+ final Connection localSignalRConnection = signalRConnection;
+ if (localSignalRConnection != null) {
+ localSignalRConnection.stop();
+ signalRConnection = null;
}
- this.scheduler = null;
}
- private void refresh() {
+ private Connection createSignalRConnection() {
+ Connection signalRConnection = new Connection(config.getSignalRUrl(), new SignalRLogger());
+ signalRConnection.setReconnectOnError(false);
+ signalRConnection.received(json -> {
+ if (json != null && json.isJsonObject()) {
+ BiConsumer<@Nullable SignalRResultModel, @Nullable String> refreshDone = this.refreshDone;
+ if (refreshDone != null) {
+ logger.trace("refresh {}", json);
+ try {
+ SignalRResultModel content = Objects
+ .requireNonNull(gson.fromJson(json, SignalRResultModel.class));
+ refreshDone.accept(content, null);
+ } catch (JsonSyntaxException exception) {
+ logger.debug("Error mapping Result to model", exception);
+ refreshDone.accept(null, exception.getMessage());
+ }
+ }
+ }
+ });
+ signalRConnection.stateChanged((oldState, newState) -> {
+ logger.trace("Connection state changed from {} to {}", oldState, newState);
+ if (newState == ConnectionState.Disconnected && !destroyed) {
+ handleConnectionLost("Connection broken");
+ }
+ });
+ signalRConnection.reconnected(() -> {
+ initializeGroups(false);
+ });
+ signalRConnection.connected(() -> {
+ signalRConnection.send(sessionId);
+ });
+ signalRConnection.error(error -> logger.info("SignalR error {}", error.getLocalizedMessage()));
+ return signalRConnection;
+ }
+
+ private void initializeGroups(boolean shouldStartSignalRService) {
+ if (destroyed || isInitializing) {
+ return;
+ }
final String sessionId = this.sessionId;
if (sessionId == null) {
- handleConnectionLost();
+ handleConnectionLost("No session id");
}
+ isInitializing = true;
+ logger.trace("initializeGroups started");
final Runnable unauthorized = this.unauthorized;
createRequest().send(new BufferingResponseListener() {
@Override
public void onComplete(@Nullable Result result) {
- if (!destroyed) {
- if (result == null || result.isFailed()) {
- handleConnectionLost();
+ try {
+ if (destroyed || result == null) {
+ return;
+ }
+ if (result.isFailed()) {
+ final Throwable failure = result.getFailure();
+ logger.error("Error initializing groups", failure);
+ handleConnectionLost(failure.getLocalizedMessage());
} else {
int status = result.getResponse().getStatus();
logger.trace("HTTP-Status {}", status);
@@ -122,32 +174,40 @@ public final class RefreshService implements AutoCloseable {
if (unauthorized != null) {
unauthorized.run();
} else {
- handleConnectionLost();
+ handleConnectionLost(null);
}
} else if (status == HttpStatus.OK_200) {
- handleRefreshDone(getContentAsString());
+ initializationDone(Objects.requireNonNull(getContentAsString()));
+ final Connection localSignalRConnection = signalRConnection;
+ if (shouldStartSignalRService && localSignalRConnection != null) {
+ localSignalRConnection.start();
+ }
} else {
logger.warn("unsupported HTTP-Status {}", status);
- handleConnectionLost();
+ handleConnectionLost(null);
}
}
+ } finally {
+ logger.trace("initializeGroups completed");
+ isInitializing = false;
}
}
});
}
private Request createRequest() {
- Request request = httpClient.newRequest(config.apiUrl + "/Group/GroupContents").param("sessionid", sessionId)
- .param("apiKey", config.apiKey).method(HttpMethod.GET);
+ Request request = httpClient.newRequest(config.getRestApiUrl() + "/Group/GroupContents")
+ .param("sessionid", sessionId).param("apiKey", config.apiKey).method(HttpMethod.GET);
return request;
}
- private void handleRefreshDone(String responseBody) {
- BiConsumer<@Nullable GroupContentResponseModel, @Nullable String> refreshDone = this.refreshDone;
+ private void initializationDone(String responseBody) {
+ BiConsumer<@Nullable GroupContentResponseModel, @Nullable String> refreshDone = this.initializationDone;
if (refreshDone != null) {
- logger.trace("refresh {}", responseBody);
+ logger.trace("initializationDone {}", responseBody);
try {
- GroupContentResponseModel content = gson.fromJson(responseBody, GroupContentResponseModel.class);
+ GroupContentResponseModel content = Objects
+ .requireNonNull(gson.fromJson(responseBody, GroupContentResponseModel.class));
refreshDone.accept(content, null);
} catch (JsonSyntaxException exception) {
logger.debug("Error mapping Result to model", exception);
@@ -156,15 +216,15 @@ public final class RefreshService implements AutoCloseable {
}
}
- private void handleConnectionLost() {
- final Runnable connectionLost = this.connectionLost;
+ private void handleConnectionLost(@Nullable String message) {
+ final Consumer<@Nullable String> connectionLost = this.connectionLost;
if (connectionLost != null) {
- connectionLost.run();
+ connectionLost.accept(message);
}
}
@Override
- public void close() throws Exception {
+ public void close() {
stop();
}
}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/RefreshThermostatsService.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/RefreshThermostatsService.java
new file mode 100644
index 00000000000..8b3dfa1f0bb
--- /dev/null
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/RefreshThermostatsService.java
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) 2010-2023 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.ojelectronics.internal.services;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.BiConsumer;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.ojelectronics.internal.ThermostatHandler;
+import org.openhab.binding.ojelectronics.internal.models.thermostat.ThermostatModel;
+import org.openhab.binding.ojelectronics.internal.models.thermostat.ThermostatModelBase;
+import org.openhab.binding.ojelectronics.internal.models.thermostat.ThermostatRealTimeValuesModel;
+import org.openhab.core.thing.Thing;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Refreshes values of {@link ThermostatHandler}
+ *
+ * @author Christian Kittel - Initial Contribution
+ */
+@NonNullByDefault
+public class RefreshThermostatsService {
+
+ private final List thermostats;
+ private final Logger logger = LoggerFactory.getLogger(RefreshThermostatsService.class);
+ private final List things;
+ private final List realTimeValues;
+
+ /**
+ * Creates a new instance of {@link RefreshThermostatsService}
+ *
+ * @param thermostats {@link ThermostatModel}
+ * @param things Things
+ */
+ public RefreshThermostatsService(List thermostats, List things) {
+ this(thermostats, new ArrayList<>(), things);
+ }
+
+ /**
+ * Creates a new instance of {@link RefreshThermostatsService}
+ *
+ * @param thermostats {@link ThermostatModel}
+ * @param realTimeValues {@link ThermostatRealTimeValuesModel}
+ * @param things Things
+ */
+ public RefreshThermostatsService(List thermostats,
+ List realTimeValues, List things) {
+ this.thermostats = thermostats;
+ this.things = things;
+ this.realTimeValues = realTimeValues;
+ if (this.things.isEmpty()) {
+ logger.warn("Bridge contains no thermostats.");
+ }
+ }
+
+ /**
+ * Handles the changes to all things.
+ */
+ public synchronized void handle() {
+ thermostats.forEach(thermostat -> handleThermostat(thermostat, this::handleThermostatRefresh));
+ realTimeValues.forEach(thermostat -> handleThermostat(thermostat, this::handleThermostatRealTimeValueRefresh));
+ }
+
+ private void handleThermostat(T thermostat,
+ BiConsumer refreshHandler) {
+ things.stream().filter(thing -> thing.getHandler() instanceof ThermostatHandler)
+ .map(thing -> (ThermostatHandler) thing.getHandler())
+ .filter(thingHandler -> thingHandler.getSerialNumber().equals(thermostat.serialNumber))
+ .forEach(thingHandler -> {
+ try {
+ refreshHandler.accept(Objects.requireNonNull(thingHandler), thermostat);
+ } catch (Exception e) {
+ logger.info("Error Handling Refresh of thermostat {}", thermostat, e);
+ }
+ });
+ }
+
+ private void handleThermostatRefresh(ThermostatHandler thingHandler, ThermostatModel thermostat) {
+ thingHandler.handleThermostatRefresh(thermostat);
+ }
+
+ private void handleThermostatRealTimeValueRefresh(ThermostatHandler thingHandler,
+ ThermostatRealTimeValuesModel thermostat) {
+ thingHandler.handleThermostatRefresh(thermostat);
+ }
+}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/SignInService.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/SignInService.java
index dbc95dd3e61..1a364c1d704 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/SignInService.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/SignInService.java
@@ -12,6 +12,8 @@
*/
package org.openhab.binding.ojelectronics.internal.services;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -27,6 +29,8 @@ import org.openhab.binding.ojelectronics.internal.config.OJElectronicsBridgeConf
import org.openhab.binding.ojelectronics.internal.models.RequestModelBase;
import org.openhab.binding.ojelectronics.internal.models.userprofile.PostSignInQueryModel;
import org.openhab.binding.ojelectronics.internal.models.userprofile.PostSignInResponseModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
@@ -39,7 +43,7 @@ import com.google.gson.Gson;
public class SignInService {
private final Gson gson = OJGSonBuilder.getGSon();
-
+ private final Logger logger = LoggerFactory.getLogger(SignInService.class);
private final HttpClient httpClient;
private final OJElectronicsBridgeConfiguration config;
@@ -61,30 +65,41 @@ public class SignInService {
* @param connectionLosed This method is called if no connection could established.
* @param unauthorized This method is called if the result is unauthorized.
*/
- public void signIn(Consumer signInDone, Runnable connectionLosed, Runnable unauthorized) {
- Request request = httpClient.POST(config.apiUrl + "/UserProfile/SignIn")
+ public void signIn(Consumer signInDone, Consumer<@Nullable String> connectionLosed, Runnable unauthorized) {
+ logger.trace("Trying to sign in");
+
+ Request request = httpClient.POST(config.getRestApiUrl() + "/UserProfile/SignIn")
.header(HttpHeader.CONTENT_TYPE, "application/json")
- .content(new StringContentProvider(gson.toJson(getPostSignInQueryModel())));
+ .content(new StringContentProvider(gson.toJson(getPostSignInQueryModel())))
+ .timeout(1, TimeUnit.MINUTES);
request.send(new BufferingResponseListener() {
@Override
public void onComplete(@Nullable Result result) {
- if (result == null || result.isFailed()) {
- connectionLosed.run();
+ if (result == null) {
return;
}
+
+ if (result.isFailed()) {
+ final Throwable failure = result.getFailure();
+ logger.error("Signing in failed", failure);
+ connectionLosed.accept(failure.getLocalizedMessage());
+ return;
+ }
+
if (result.getResponse().getStatus() == 200) {
- PostSignInResponseModel signInModel = gson.fromJson(getContentAsString(),
- PostSignInResponseModel.class);
- if (signInModel == null || signInModel.errorCode != 0 || signInModel.sessionId.equals("")) {
+ PostSignInResponseModel signInModel = Objects
+ .requireNonNull(gson.fromJson(getContentAsString(), PostSignInResponseModel.class));
+ if (signInModel.errorCode != 0 || signInModel.sessionId.equals("")) {
unauthorized.run();
return;
}
+ logger.trace("Signing in successful {}", getContentAsString());
signInDone.accept(signInModel.sessionId);
return;
}
- connectionLosed.run();
+ connectionLosed.accept(null);
return;
}
});
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/UpdateService.java b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/UpdateService.java
index 7beb926a0f2..22ac84d6c01 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/UpdateService.java
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/java/org/openhab/binding/ojelectronics/internal/services/UpdateService.java
@@ -13,6 +13,8 @@
package org.openhab.binding.ojelectronics.internal.services;
import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@@ -26,7 +28,7 @@ import org.openhab.binding.ojelectronics.internal.ThermostatHandler;
import org.openhab.binding.ojelectronics.internal.common.OJGSonBuilder;
import org.openhab.binding.ojelectronics.internal.config.OJElectronicsBridgeConfiguration;
import org.openhab.binding.ojelectronics.internal.models.SimpleResponseModel;
-import org.openhab.binding.ojelectronics.internal.models.Thermostat;
+import org.openhab.binding.ojelectronics.internal.models.thermostat.ThermostatModel;
import org.openhab.binding.ojelectronics.internal.models.thermostat.UpdateThermostatRequestModel;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
@@ -45,14 +47,17 @@ public final class UpdateService {
private final Gson gson = OJGSonBuilder.getGSon();
private final Logger logger = LoggerFactory.getLogger(UpdateService.class);
- private final String sessionId;
private final HttpClient httpClient;
private final OJElectronicsBridgeConfiguration configuration;
+ private final Runnable unauthorized;
+ private final Consumer<@Nullable String> connectionLost;
- public UpdateService(OJElectronicsBridgeConfiguration configuration, HttpClient httpClient, String sessionId) {
+ public UpdateService(OJElectronicsBridgeConfiguration configuration, HttpClient httpClient,
+ Consumer<@Nullable String> connectionLost, Runnable unauthorized) {
this.configuration = configuration;
this.httpClient = httpClient;
- this.sessionId = sessionId;
+ this.unauthorized = unauthorized;
+ this.connectionLost = connectionLost;
}
/**
@@ -61,34 +66,42 @@ public final class UpdateService {
* @param things
*/
public void updateAllThermostats(List things) {
- things.stream().filter(thing -> thing.getHandler() instanceof ThermostatHandler)
- .map(thing -> (ThermostatHandler) thing.getHandler())
- .map(handler -> handler.tryHandleAndGetUpdatedThermostat()).forEach(this::updateThermostat);
+ new SignInService(configuration, httpClient).signIn((sessionId) -> updateAllThermostats(things, sessionId),
+ connectionLost, unauthorized);
}
- private void updateThermostat(@Nullable Thermostat thermostat) {
+ private void updateAllThermostats(List things, String sessionId) {
+ things.stream().filter(thing -> thing.getHandler() instanceof ThermostatHandler)
+ .map(thing -> (ThermostatHandler) thing.getHandler())
+ .map(handler -> handler.tryHandleAndGetUpdatedThermostat())
+ .forEach((thermostat) -> updateThermostat(thermostat, sessionId));
+ }
+
+ private void updateThermostat(@Nullable ThermostatModel thermostat, String sessionId) {
if (thermostat == null) {
return;
}
- Request request = httpClient.POST(configuration.apiUrl + "/Thermostat/UpdateThermostat")
+ String jsonPayload = gson.toJson(new UpdateThermostatRequestModel(thermostat).withApiKey(configuration.apiKey));
+ Request request = httpClient.POST(configuration.getRestApiUrl() + "/Thermostat/UpdateThermostat")
.param("sessionid", sessionId).header(HttpHeader.CONTENT_TYPE, "application/json")
- .content(new StringContentProvider(
- gson.toJson(new UpdateThermostatRequestModel(thermostat).withApiKey(configuration.apiKey))));
+ .content(new StringContentProvider(jsonPayload));
+ logger.trace("updateThermostat payload for themostat with serial {} is {}", thermostat.serialNumber,
+ jsonPayload);
request.send(new BufferingResponseListener() {
@Override
public void onComplete(@Nullable Result result) {
if (result != null) {
- logger.trace("onComplete {}", result);
+ logger.trace("onComplete Http Status {} {}", result.getResponse().getStatus(), result);
if (result.isFailed()) {
- logger.warn("updateThermostat failed {}", thermostat);
+ logger.warn("updateThermostat failed for themostat with serial {}", thermostat.serialNumber);
+ return;
}
- SimpleResponseModel responseModel = gson.fromJson(getContentAsString(), SimpleResponseModel.class);
- if (responseModel == null) {
- logger.warn("updateThermostat failed with empty result {}", thermostat);
- } else if (responseModel.errorCode != 0) {
- logger.warn("updateThermostat failed with errorCode {} {}", responseModel.errorCode,
- thermostat);
+ SimpleResponseModel responseModel = Objects
+ .requireNonNull(gson.fromJson(getContentAsString(), SimpleResponseModel.class));
+ if (responseModel.errorCode != 0) {
+ logger.warn("updateThermostat failed with errorCode {} for thermostat with serial {}",
+ responseModel.errorCode, thermostat.serialNumber);
}
}
}
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/resources/OH-INF/i18n/ojelectronics.properties b/bundles/org.openhab.binding.ojelectronics/src/main/resources/OH-INF/i18n/ojelectronics.properties
index 10910ce7562..177912d5a86 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/resources/OH-INF/i18n/ojelectronics.properties
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/resources/OH-INF/i18n/ojelectronics.properties
@@ -15,13 +15,11 @@ thing-type.ojelectronics.owd5.description = OWD5/MWD5 Thermostat
thing-type.config.ojelectronics.ojcloud.apiKey.label = API Key
thing-type.config.ojelectronics.ojcloud.apiKey.description = API-Key from your local distributor
thing-type.config.ojelectronics.ojcloud.apiUrl.label = API-URL
-thing-type.config.ojelectronics.ojcloud.apiUrl.description = URL to cloud API-service.
+thing-type.config.ojelectronics.ojcloud.apiUrl.description = URL to cloud API-service and Socket-Notification.
thing-type.config.ojelectronics.ojcloud.customerId.label = Customer ID
thing-type.config.ojelectronics.ojcloud.customerId.description = Customer ID
thing-type.config.ojelectronics.ojcloud.password.label = Password
thing-type.config.ojelectronics.ojcloud.password.description = Password for access cloud service.
-thing-type.config.ojelectronics.ojcloud.refreshDelayInSeconds.label = Refresh Delay
-thing-type.config.ojelectronics.ojcloud.refreshDelayInSeconds.description = Refresh delay in seconds.
thing-type.config.ojelectronics.ojcloud.softwareVersion.label = Software Version
thing-type.config.ojelectronics.ojcloud.softwareVersion.description = Software Version
thing-type.config.ojelectronics.ojcloud.userName.label = User Name
diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.ojelectronics/src/main/resources/OH-INF/thing/thing-types.xml
index ba64ef5d99f..251f6255553 100644
--- a/bundles/org.openhab.binding.ojelectronics/src/main/resources/OH-INF/thing/thing-types.xml
+++ b/bundles/org.openhab.binding.ojelectronics/src/main/resources/OH-INF/thing/thing-types.xml
@@ -22,16 +22,10 @@
- URL to cloud API-service.
+ URL to cloud API-service and Socket-Notification.
url
true
- https://OWD5-OJ001-App.ojelectronics.com/api
-
-
-
- Refresh delay in seconds.
- true
- 30
+ https://OWD5-OJ001-App.ojelectronics.com