added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.ojelectronics-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-ojelectronics" description="OJElectronics Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.ojelectronics/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link OJElectronicsBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Christian Kittel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "ojelectronics";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_OJCLOUD = new ThingTypeUID(BINDING_ID, "ojcloud");
|
||||
public static final ThingTypeUID THING_TYPE_OWD5 = new ThingTypeUID(BINDING_ID, "owd5");
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String CHANNEL_OWD5_FLOORTEMPERATURE = "floorTemperature";
|
||||
public static final String CHANNEL_OWD5_GROUPNAME = "groupName";
|
||||
public static final String CHANNEL_OWD5_GROUPID = "groupId";
|
||||
public static final String CHANNEL_OWD5_ONLINE = "online";
|
||||
public static final String CHANNEL_OWD5_HEATING = "heating";
|
||||
public static final String CHANNEL_OWD5_ROOMTEMPERATURE = "roomTemperature";
|
||||
public static final String CHANNEL_OWD5_THERMOSTATNAME = "thermostatName";
|
||||
public static final String CHANNEL_OWD5_REGULATIONMODE = "regulationMode";
|
||||
public static final String CHANNEL_OWD5_COMFORTSETPOINT = "comfortSetpoint";
|
||||
public static final String CHANNEL_OWD5_COMFORTENDTIME = "comfortEndTime";
|
||||
public static final String CHANNEL_OWD5_BOOSTENDTIME = "boostEndTime";
|
||||
public static final String CHANNEL_OWD5_MANUALSETPOINT = "manualSetpoint";
|
||||
public static final String CHANNEL_OWD5_VACATIONENABLED = "vacationEnabled";
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
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.openhab.binding.ojelectronics.internal.config.OJElectronicsBridgeConfiguration;
|
||||
import org.openhab.binding.ojelectronics.internal.models.groups.GroupContentResponseModel;
|
||||
import org.openhab.binding.ojelectronics.internal.services.RefreshGroupContentService;
|
||||
import org.openhab.binding.ojelectronics.internal.services.RefreshService;
|
||||
import org.openhab.binding.ojelectronics.internal.services.SignInService;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
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.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handles all traffic with OJ Electronics cloud
|
||||
*
|
||||
* @author Christian Kittel - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OJCloudHandler extends BaseBridgeHandler implements BridgeHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(OJCloudHandler.class);
|
||||
private final HttpClient httpClient;
|
||||
|
||||
private @Nullable RefreshService refreshService;
|
||||
private @Nullable SignInService signInService;
|
||||
private OJElectronicsBridgeConfiguration configuration;
|
||||
private @Nullable ScheduledFuture<?> signTask;
|
||||
|
||||
public OJCloudHandler(Bridge bridge, HttpClient httpClient) {
|
||||
super(bridge);
|
||||
this.httpClient = httpClient;
|
||||
this.configuration = new OJElectronicsBridgeConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the binding.
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
configuration = getConfigAs(OJElectronicsBridgeConfiguration.class);
|
||||
ensureSignIn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the binding.
|
||||
*/
|
||||
@Override
|
||||
public void dispose() {
|
||||
final RefreshService refreshService = this.refreshService;
|
||||
if (refreshService != null) {
|
||||
refreshService.stop();
|
||||
}
|
||||
final ScheduledFuture<?> signTask = this.signTask;
|
||||
if (signTask != null) {
|
||||
signTask.cancel(true);
|
||||
}
|
||||
this.refreshService = null;
|
||||
signInService = null;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
|
||||
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,
|
||||
this::handleUnauthorizedWhileSignIn);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRefreshDone(@Nullable GroupContentResponseModel groupContentResponse,
|
||||
@Nullable String errorMessage) {
|
||||
logger.trace("OJElectronicsCloudHandler.handleRefreshDone({})", groupContentResponse);
|
||||
|
||||
if (groupContentResponse != null && groupContentResponse.errorCode == 0) {
|
||||
new RefreshGroupContentService(groupContentResponse.groupContents, getThing().getThings()).handle();
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSignInDone(String sessionId) {
|
||||
logger.trace("OJElectronicsCloudHandler.handleSignInDone({})", sessionId);
|
||||
if (refreshService == null) {
|
||||
refreshService = new RefreshService(configuration, httpClient, scheduler);
|
||||
}
|
||||
final RefreshService refreshService = this.refreshService;
|
||||
if (refreshService != null) {
|
||||
refreshService.start(sessionId, this::handleRefreshDone, this::handleConnectionLost,
|
||||
this::handleUnauthorized);
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUnauthorized() {
|
||||
final RefreshService refreshService = this.refreshService;
|
||||
if (refreshService != null) {
|
||||
refreshService.stop();
|
||||
}
|
||||
restartRefreshServiceAsync(1);
|
||||
}
|
||||
|
||||
private void 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();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleConnectionLost() {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
final RefreshService refreshService = this.refreshService;
|
||||
if (refreshService != null) {
|
||||
refreshService.stop();
|
||||
}
|
||||
restartRefreshServiceAsync(configuration.refreshDelayInSeconds);
|
||||
}
|
||||
|
||||
private void restartRefreshServiceAsync(long delayInSeconds) {
|
||||
signTask = scheduler.schedule(this::ensureSignIn, delayInSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
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;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* Factory to create {@link OJCloudHandler}
|
||||
*
|
||||
* @author Christian Kittel - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.ojelectronics", service = ThingHandlerFactory.class)
|
||||
public class OJCloudHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_OJCLOUD);
|
||||
|
||||
private final HttpClient httpClient;
|
||||
|
||||
/**
|
||||
* Creates a new factory
|
||||
*
|
||||
* @param httpClientFactory Factory for HttpClient
|
||||
*/
|
||||
@Activate
|
||||
public OJCloudHandlerFactory(@Reference HttpClientFactory httpClientFactory) {
|
||||
this.httpClient = httpClientFactory.getCommonHttpClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported things for this factory
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
if (SUPPORTED_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
|
||||
OJCloudHandler handler = new OJCloudHandler((Bridge) thing, httpClient);
|
||||
return handler;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
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.groups.Thermostat;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
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.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
|
||||
/**
|
||||
* The {@link ThermostatHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Christian Kittel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ThermostatHandler extends BaseThingHandler {
|
||||
|
||||
private final String serialNumber;
|
||||
private @Nullable Thermostat currentThermostat;
|
||||
private static final Map<Integer, String> REGULATION_MODES = createRegulationMap();
|
||||
private final Map<String, Consumer<Thermostat>> channelrefreshActions = createChannelRefreshActionMap();
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link ThermostatHandler}
|
||||
*
|
||||
* @param thing Thing
|
||||
*/
|
||||
public ThermostatHandler(Thing thing) {
|
||||
super(thing);
|
||||
serialNumber = getConfigAs(OJElectronicsThermostatConfiguration.class).serialNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the thing's serial number.
|
||||
*
|
||||
* @return serial number
|
||||
*/
|
||||
public String getSerialNumber() {
|
||||
return serialNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles commands to this thing.
|
||||
*/
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
final Thermostat thermostat = currentThermostat;
|
||||
if (thermostat != null && channelrefreshActions.containsKey(channelUID.getId())) {
|
||||
channelrefreshActions.get(channelUID.getId()).accept(thermostat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the thing handler.
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the values after refreshing the thermostats values
|
||||
*
|
||||
* @param thermostat thermostat values
|
||||
*/
|
||||
public void handleThermostatRefresh(Thermostat thermostat) {
|
||||
currentThermostat = thermostat;
|
||||
channelrefreshActions.forEach((channelUID, action) -> action.accept(thermostat));
|
||||
}
|
||||
|
||||
private void updateManualSetpoint(Thermostat thermostat) {
|
||||
updateState(BindingConstants.CHANNEL_OWD5_MANUALSETPOINT,
|
||||
new QuantityType<Temperature>(thermostat.manualModeSetpoint / (double) 100, SIUnits.CELSIUS));
|
||||
}
|
||||
|
||||
private void updateBoostEndTime(Thermostat thermostat) {
|
||||
updateState(BindingConstants.CHANNEL_OWD5_BOOSTENDTIME,
|
||||
new DateTimeType(ZonedDateTime.ofInstant(thermostat.boostEndTime.toInstant(), ZoneId.systemDefault())));
|
||||
}
|
||||
|
||||
private void updateComfortEndTime(Thermostat thermostat) {
|
||||
updateState(BindingConstants.CHANNEL_OWD5_COMFORTENDTIME, new DateTimeType(
|
||||
ZonedDateTime.ofInstant(thermostat.comfortEndTime.toInstant(), ZoneId.systemDefault())));
|
||||
}
|
||||
|
||||
private void updateComfortSetpoint(Thermostat thermostat) {
|
||||
updateState(BindingConstants.CHANNEL_OWD5_COMFORTSETPOINT,
|
||||
new QuantityType<Temperature>(thermostat.comfortSetpoint / (double) 100, SIUnits.CELSIUS));
|
||||
}
|
||||
|
||||
private void updateRegulationMode(Thermostat thermostat) {
|
||||
updateState(BindingConstants.CHANNEL_OWD5_REGULATIONMODE,
|
||||
StringType.valueOf(getRegulationMode(thermostat.regulationMode)));
|
||||
}
|
||||
|
||||
private void updateThermostatName(Thermostat thermostat) {
|
||||
updateState(BindingConstants.CHANNEL_OWD5_THERMOSTATNAME, StringType.valueOf(thermostat.thermostatName));
|
||||
}
|
||||
|
||||
private void updateFloorTemperature(Thermostat thermostat) {
|
||||
updateState(BindingConstants.CHANNEL_OWD5_FLOORTEMPERATURE,
|
||||
new QuantityType<Temperature>(thermostat.floorTemperature / (double) 100, SIUnits.CELSIUS));
|
||||
}
|
||||
|
||||
private void updateRoomTemperature(Thermostat thermostat) {
|
||||
updateState(BindingConstants.CHANNEL_OWD5_ROOMTEMPERATURE,
|
||||
new QuantityType<Temperature>(thermostat.roomTemperature / (double) 100, SIUnits.CELSIUS));
|
||||
}
|
||||
|
||||
private void updateHeating(Thermostat thermostat) {
|
||||
updateState(BindingConstants.CHANNEL_OWD5_HEATING,
|
||||
thermostat.heating ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
|
||||
}
|
||||
|
||||
private void updateOnline(Thermostat thermostat) {
|
||||
updateState(BindingConstants.CHANNEL_OWD5_ONLINE,
|
||||
thermostat.online ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
|
||||
}
|
||||
|
||||
private void updateGroupId(Thermostat thermostat) {
|
||||
updateState(BindingConstants.CHANNEL_OWD5_GROUPID, new DecimalType(thermostat.groupId));
|
||||
}
|
||||
|
||||
private void updateGroupName(Thermostat thermostat) {
|
||||
updateState(BindingConstants.CHANNEL_OWD5_GROUPNAME, StringType.valueOf(thermostat.groupName));
|
||||
}
|
||||
|
||||
private String getRegulationMode(int regulationMode) {
|
||||
return REGULATION_MODES.get(regulationMode);
|
||||
}
|
||||
|
||||
private static Map<Integer, String> createRegulationMap() {
|
||||
HashMap<Integer, String> map = new HashMap<>();
|
||||
map.put(1, "auto");
|
||||
map.put(2, "comfort");
|
||||
map.put(3, "manual");
|
||||
map.put(4, "vacation");
|
||||
map.put(6, "frostProtection");
|
||||
map.put(8, "boost");
|
||||
map.put(9, "eco");
|
||||
return map;
|
||||
};
|
||||
|
||||
private Map<String, Consumer<Thermostat>> createChannelRefreshActionMap() {
|
||||
HashMap<String, Consumer<Thermostat>> 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);
|
||||
map.put(BindingConstants.CHANNEL_OWD5_HEATING, this::updateHeating);
|
||||
map.put(BindingConstants.CHANNEL_OWD5_ROOMTEMPERATURE, this::updateRoomTemperature);
|
||||
map.put(BindingConstants.CHANNEL_OWD5_FLOORTEMPERATURE, this::updateFloorTemperature);
|
||||
map.put(BindingConstants.CHANNEL_OWD5_THERMOSTATNAME, this::updateThermostatName);
|
||||
map.put(BindingConstants.CHANNEL_OWD5_REGULATIONMODE, this::updateRegulationMode);
|
||||
map.put(BindingConstants.CHANNEL_OWD5_COMFORTSETPOINT, this::updateComfortSetpoint);
|
||||
map.put(BindingConstants.CHANNEL_OWD5_COMFORTENDTIME, this::updateComfortEndTime);
|
||||
map.put(BindingConstants.CHANNEL_OWD5_BOOSTENDTIME, this::updateBoostEndTime);
|
||||
map.put(BindingConstants.CHANNEL_OWD5_MANUALSETPOINT, this::updateManualSetpoint);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
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;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* The {@link ThermostatHandlerFactory} is responsible for creating {@link OJElectronicsThermostatHandler}.
|
||||
*
|
||||
* @author Christian Kittel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.ojelectronics", service = ThingHandlerFactory.class)
|
||||
public class ThermostatHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_OWD5);
|
||||
|
||||
/**
|
||||
* Supported things of this factory.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (THING_TYPE_OWD5.equals(thingTypeUID)) {
|
||||
return new ThermostatHandler(thing);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The configuration for {@link org.openhab.binding.ojelectronics.internal.OJElectronicsCloudHandler}
|
||||
*
|
||||
* @author Christian Kittel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OJElectronicsBridgeConfiguration {
|
||||
|
||||
/**
|
||||
* Password
|
||||
*/
|
||||
public String password = "";
|
||||
|
||||
/**
|
||||
* Customer-ID
|
||||
*/
|
||||
public int customerId = 1;
|
||||
|
||||
/**
|
||||
* User Name
|
||||
*/
|
||||
public String userName = "";
|
||||
|
||||
/**
|
||||
* Url for API
|
||||
*/
|
||||
public String apiUrl = "https://OWD5-OJ001-App.ojelectronics.com/api";
|
||||
|
||||
/**
|
||||
* API-Key
|
||||
*/
|
||||
public String apiKey = "";
|
||||
|
||||
/**
|
||||
* Software Version
|
||||
*/
|
||||
public int softwareVersion = 1060;
|
||||
|
||||
/**
|
||||
* Refresh-Delay
|
||||
*/
|
||||
public long refreshDelayInSeconds = 30;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The configuration for {@link org.openhab.binding.ojelectronics.internal.OJElectronicsThermostatHandler}
|
||||
*
|
||||
* @author Christian Kittel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OJElectronicsThermostatConfiguration {
|
||||
|
||||
/**
|
||||
* serial number of thermostat
|
||||
*/
|
||||
public String serialNumber = "";
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.groups;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Model for a day
|
||||
*
|
||||
* @author Christian Kittel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Day {
|
||||
|
||||
public int weekDayGrpNo;
|
||||
|
||||
public List<Event> events = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.groups;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Model for events
|
||||
*
|
||||
* @author Christian Kittel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Event {
|
||||
|
||||
public int scheduleType;
|
||||
|
||||
public String clock = "";
|
||||
|
||||
public int temperature;
|
||||
|
||||
public boolean active;
|
||||
|
||||
public boolean eventIsOnNextDay;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.groups;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Model for content of a group
|
||||
*
|
||||
* @author Christian Kittel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GroupContent {
|
||||
|
||||
public int action;
|
||||
|
||||
public int groupId;
|
||||
|
||||
public String groupName = "";
|
||||
|
||||
public List<Thermostat> thermostats = new ArrayList<Thermostat>();
|
||||
|
||||
public int regulationMode;
|
||||
|
||||
public @Nullable Schedule schedule;
|
||||
|
||||
public int comfortSetpoint;
|
||||
|
||||
public String comfortEndTime = "";
|
||||
|
||||
public int manualModeSetpoint;
|
||||
|
||||
public boolean vacationEnabled;
|
||||
|
||||
public String vacationBeginDay = "";
|
||||
|
||||
public String vacationEndDay = "";
|
||||
|
||||
public int vacationTemperature;
|
||||
|
||||
public boolean lastPrimaryModeIsAuto;
|
||||
|
||||
public String boostEndTime = "";
|
||||
|
||||
public int frostProtectionTemperature;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.groups;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Model for the response of a content group
|
||||
*
|
||||
* @author Christian Kittel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GroupContentResponseModel {
|
||||
|
||||
public List<GroupContent> groupContents = new ArrayList<GroupContent>();
|
||||
|
||||
public int errorCode;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.groups;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Model for a schedule
|
||||
*
|
||||
* @author Christian Kittel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Schedule {
|
||||
|
||||
public List<Day> days = new ArrayList<Day>();
|
||||
|
||||
public boolean modifiedDueToVerification;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.groups;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Model for a thermostat
|
||||
*
|
||||
* @author Christian Kittel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Thermostat {
|
||||
|
||||
public int id;
|
||||
|
||||
public int action;
|
||||
|
||||
public String serialNumber = "";
|
||||
|
||||
public String groupName = "";
|
||||
|
||||
public int groupId;
|
||||
|
||||
public int customerId;
|
||||
|
||||
@SerializedName("SWversion")
|
||||
public String softwareVersion = "";
|
||||
|
||||
public boolean online;
|
||||
|
||||
public boolean heating;
|
||||
|
||||
public int roomTemperature;
|
||||
|
||||
public int floorTemperature;
|
||||
|
||||
public int regulationMode;
|
||||
|
||||
public @Nullable Schedule schedule;
|
||||
|
||||
public int comfortSetpoint;
|
||||
|
||||
public Date comfortEndTime = new Date();
|
||||
|
||||
public int manualModeSetpoint;
|
||||
|
||||
public boolean vacationEnabled;
|
||||
|
||||
public Date vacationBeginDay = new Date();
|
||||
|
||||
public Date vacationEndDay = new Date();
|
||||
|
||||
public int vacationTemperature;
|
||||
|
||||
public boolean lastPrimaryModeIsAuto;
|
||||
|
||||
public Date boostEndTime = new Date();
|
||||
|
||||
public int frostProtectionTemperature;
|
||||
|
||||
public int errorCode;
|
||||
|
||||
public String thermostatName = "";
|
||||
|
||||
public boolean openWindow;
|
||||
|
||||
public boolean adaptiveMode;
|
||||
|
||||
public boolean daylightSaving;
|
||||
|
||||
public int sensorAppl;
|
||||
|
||||
public int minSetpoint;
|
||||
|
||||
public int maxSetpoint;
|
||||
|
||||
public int timeZone;
|
||||
|
||||
public boolean daylightSavingActive;
|
||||
|
||||
public int floorType;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.userprofile;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Model for signing sin
|
||||
*
|
||||
* @author Christian Kittel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PostSignInQueryModel {
|
||||
|
||||
@SerializedName("APIKEY")
|
||||
public String apiKey = "";
|
||||
|
||||
public String userName = "";
|
||||
|
||||
public String password = "";
|
||||
|
||||
public int customerId;
|
||||
|
||||
public int clientSWVersion;
|
||||
|
||||
/**
|
||||
* Add API-Key
|
||||
*
|
||||
* @param apiKey API-Key
|
||||
* @return Model
|
||||
*/
|
||||
public PostSignInQueryModel withApiKey(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add User-Name
|
||||
*
|
||||
* @param userName User-Name for API access
|
||||
* @return Model
|
||||
*/
|
||||
public PostSignInQueryModel withUserName(String userName) {
|
||||
this.userName = userName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Password
|
||||
*
|
||||
* @param password Password for API access
|
||||
* @return Model
|
||||
*/
|
||||
public PostSignInQueryModel withPassword(String password) {
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add customer ID
|
||||
*
|
||||
* @param customerId Customer Id
|
||||
* @return Model
|
||||
*/
|
||||
public PostSignInQueryModel withCustomerId(int customerId) {
|
||||
this.customerId = customerId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Software Version
|
||||
*
|
||||
* @param clientSWVersion Software Version
|
||||
* @return Model
|
||||
*/
|
||||
public PostSignInQueryModel withClientSWVersion(int clientSWVersion) {
|
||||
this.clientSWVersion = clientSWVersion;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.userprofile;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Response-Model after signing in
|
||||
*
|
||||
* @author Christian Kittel - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PostSignInResponseModel {
|
||||
|
||||
public String sessionId = "";
|
||||
|
||||
public String userName = "";
|
||||
|
||||
public int errorCode;
|
||||
|
||||
public PostSignInResponseModel withSessionId(String sessionId) {
|
||||
this.sessionId = sessionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PostSignInResponseModel withUserName(String userName) {
|
||||
this.userName = userName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PostSignInResponseModel withErrorCode(int errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.ojelectronics.internal.ThermostatHandler;
|
||||
import org.openhab.binding.ojelectronics.internal.models.groups.GroupContent;
|
||||
import org.openhab.binding.ojelectronics.internal.models.groups.Thermostat;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* Refreshes values of {@link ThermostatHandler}
|
||||
*
|
||||
* @author Christian Kittel - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class RefreshGroupContentService {
|
||||
|
||||
private final List<GroupContent> groupContentList;
|
||||
private List<Thing> things;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link RefreshGroupContentService}
|
||||
*
|
||||
* @param groupContents {@link GroupContent}
|
||||
* @param things Things
|
||||
*/
|
||||
public RefreshGroupContentService(List<GroupContent> groupContents, List<Thing> things) {
|
||||
this.groupContentList = groupContents;
|
||||
this.things = things;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
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.config.OJElectronicsBridgeConfiguration;
|
||||
import org.openhab.binding.ojelectronics.internal.models.groups.GroupContentResponseModel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* Handles the refreshing of the devices of a session
|
||||
*
|
||||
* @author Christian Kittel - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public final class RefreshService implements AutoCloseable {
|
||||
|
||||
private final OJElectronicsBridgeConfiguration config;
|
||||
private final Logger logger = LoggerFactory.getLogger(RefreshService.class);
|
||||
private final HttpClient httpClient;
|
||||
private final Gson gson = createGson();
|
||||
|
||||
private final ScheduledExecutorService schedulerService;
|
||||
|
||||
private @Nullable Runnable connectionLost;
|
||||
private @Nullable BiConsumer<@Nullable GroupContentResponseModel, @Nullable String> refreshDone;
|
||||
private @Nullable ScheduledFuture<?> scheduler;
|
||||
private @Nullable Runnable unauthorized;
|
||||
private @Nullable String sessionId;
|
||||
private static boolean destroyed = false;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link RefreshService}
|
||||
*
|
||||
* @param config Configuration of the bridge
|
||||
* @param httpClient HTTP client
|
||||
*/
|
||||
public RefreshService(OJElectronicsBridgeConfiguration config, HttpClient httpClient,
|
||||
ScheduledExecutorService schedulerService) {
|
||||
this.config = config;
|
||||
this.httpClient = httpClient;
|
||||
this.schedulerService = schedulerService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts refreshing all thing values
|
||||
*
|
||||
* @param sessionId Session-Id
|
||||
* @param refreshDone This method is called if refreshing is done.
|
||||
* @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) {
|
||||
logger.trace("RefreshService.startService({})", sessionId);
|
||||
this.connectionLost = connectionLost;
|
||||
this.refreshDone = refreshDone;
|
||||
this.unauthorized = unauthorized;
|
||||
this.sessionId = sessionId;
|
||||
long refreshTime = config.refreshDelayInSeconds;
|
||||
scheduler = schedulerService.scheduleWithFixedDelay(this::refresh, refreshTime, refreshTime, TimeUnit.SECONDS);
|
||||
refresh();
|
||||
destroyed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops refreshing.
|
||||
*/
|
||||
public void stop() {
|
||||
destroyed = true;
|
||||
final ScheduledFuture<?> scheduler = this.scheduler;
|
||||
if (scheduler != null) {
|
||||
scheduler.cancel(false);
|
||||
}
|
||||
this.scheduler = null;
|
||||
}
|
||||
|
||||
private Gson createGson() {
|
||||
return new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).setPrettyPrinting()
|
||||
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create();
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
final String sessionId = this.sessionId;
|
||||
if (sessionId == null) {
|
||||
handleConnectionLost();
|
||||
}
|
||||
final Runnable unauthorized = this.unauthorized;
|
||||
createRequest().send(new BufferingResponseListener() {
|
||||
@Override
|
||||
public void onComplete(@Nullable Result result) {
|
||||
if (!destroyed) {
|
||||
if (result == null || result.isFailed()) {
|
||||
handleConnectionLost();
|
||||
} else if (result.getResponse().getStatus() == HttpStatus.FORBIDDEN_403) {
|
||||
if (unauthorized != null) {
|
||||
unauthorized.run();
|
||||
}
|
||||
} else {
|
||||
handleRefreshDone(getContentAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Request createRequest() {
|
||||
Request request = httpClient.newRequest(config.apiUrl + "/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;
|
||||
if (refreshDone != null) {
|
||||
logger.trace("refresh {}", responseBody);
|
||||
try {
|
||||
GroupContentResponseModel content = gson.fromJson(responseBody, GroupContentResponseModel.class);
|
||||
refreshDone.accept(content, null);
|
||||
} catch (JsonSyntaxException exception) {
|
||||
logger.debug("Error mapping Result to model", exception);
|
||||
refreshDone.accept(null, exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleConnectionLost() {
|
||||
final Runnable connectionLost = this.connectionLost;
|
||||
if (connectionLost != null) {
|
||||
connectionLost.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.function.Consumer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.client.util.BufferingResponseListener;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.openhab.binding.ojelectronics.internal.config.OJElectronicsBridgeConfiguration;
|
||||
import org.openhab.binding.ojelectronics.internal.models.userprofile.PostSignInQueryModel;
|
||||
import org.openhab.binding.ojelectronics.internal.models.userprofile.PostSignInResponseModel;
|
||||
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* Handles the sign in process.
|
||||
*
|
||||
* @author Christian Kittel - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SignInService {
|
||||
|
||||
private final Gson gson = createGson();
|
||||
|
||||
private final HttpClient httpClient;
|
||||
private final OJElectronicsBridgeConfiguration config;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link SignInService}
|
||||
*
|
||||
* @param config configuration {@link OJElectronicsBridgeConfiguration}
|
||||
* @param httpClient HTTP client
|
||||
*/
|
||||
public SignInService(OJElectronicsBridgeConfiguration config, HttpClient httpClient) {
|
||||
this.config = config;
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signing in
|
||||
*
|
||||
* @param signInDone This method is called if sign in process was successful.
|
||||
* @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<String> signInDone, Runnable connectionLosed, Runnable unauthorized) {
|
||||
Request request = httpClient.POST(config.apiUrl + "/UserProfile/SignIn")
|
||||
.header(HttpHeader.CONTENT_TYPE, "application/json")
|
||||
.content(new StringContentProvider(gson.toJson(getPostSignInQueryModel())));
|
||||
|
||||
request.send(new BufferingResponseListener() {
|
||||
@Override
|
||||
public void onComplete(@Nullable Result result) {
|
||||
if (result == null || result.isFailed()) {
|
||||
connectionLosed.run();
|
||||
return;
|
||||
}
|
||||
if (result.getResponse().getStatus() != 200) {
|
||||
unauthorized.run();
|
||||
return;
|
||||
}
|
||||
PostSignInResponseModel signInModel = gson.fromJson(getContentAsString(),
|
||||
PostSignInResponseModel.class);
|
||||
if (signInModel.errorCode != 0 || signInModel.sessionId.equals("")) {
|
||||
unauthorized.run();
|
||||
return;
|
||||
}
|
||||
signInDone.accept(signInModel.sessionId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Gson createGson() {
|
||||
return new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).setPrettyPrinting().create();
|
||||
}
|
||||
|
||||
private PostSignInQueryModel getPostSignInQueryModel() {
|
||||
return new PostSignInQueryModel().withApiKey(config.apiKey).withClientSWVersion(config.softwareVersion)
|
||||
.withCustomerId(config.customerId).withUserName(config.userName).withPassword(config.password);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="ojelectronics"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
<name>OJElectronics Binding</name>
|
||||
<description>This is the binding for OJElectronics.</description>
|
||||
<author>Christian Kittel</author>
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,38 @@
|
||||
# binding
|
||||
binding.ojelectronics.name = Binding für OJElectronics
|
||||
binding.ojelectronics.description = Binding für OJElectronics.
|
||||
|
||||
# thing types
|
||||
thing-type.ojelectronics.owd5.label = OWD5/MWD5 Thermostate
|
||||
thing-type.ojelectronics.owd5.description = OWD5/MWD5 Thermostate
|
||||
thing-type.ojelectronics.ojcloud.label = OJ Electronics Cloud
|
||||
thing-type.ojelectronics.ojcloud.description = Zugriff auf alle OJ Electronic Geräte.
|
||||
|
||||
# thing type config description
|
||||
thing-type.config.ojelectronics.ojcloud.userName.label = Nutzername
|
||||
thing-type.config.ojelectronics.ojcloud.userName.description = Nutzername für den Zugriff auf die Cloud.
|
||||
thing-type.config.ojelectronics.ojcloud.password.label = Passwort
|
||||
thing-type.config.ojelectronics.ojcloud.password.description = Passwort für den Zugriff auf die Cloud.
|
||||
thing-type.config.ojelectronics.ojcloud.apiKey.label = API-Key
|
||||
thing-type.config.ojelectronics.ojcloud.apiKey.description = API-Key von deinem Händler
|
||||
|
||||
# channel types
|
||||
channel-type.ojelectronics.floorTemperature.label = Bodentemperatur
|
||||
channel-type.ojelectronics.roomTemperature.label = Zimmertemperatur
|
||||
channel-type.ojelectronics.groupName.label = Gruppenname
|
||||
channel-type.ojelectronics.online.label = Ist Online
|
||||
channel-type.ojelectronics.heating.label = Heizt
|
||||
channel-type.ojelectronics.thermostatName.label = Name des Thermostats
|
||||
channel-type.ojelectronics.regulationMode.label = Regelungsmodus
|
||||
channel-type.ojelectronics.regulationMode.state.option.auto = Automatisch
|
||||
channel-type.ojelectronics.regulationMode.state.option.comfort = Komfort
|
||||
channel-type.ojelectronics.regulationMode.state.option.manual = Manuell
|
||||
channel-type.ojelectronics.regulationMode.state.option.vacation = Urlaub
|
||||
channel-type.ojelectronics.regulationMode.state.option.frostProtection = Frostschutz
|
||||
channel-type.ojelectronics.regulationMode.state.option.boost = Boost
|
||||
channel-type.ojelectronics.regulationMode.state.option.eco = Spar
|
||||
channel-type.ojelectronics.comfortSetpoint.label = Komfort-Sollwert
|
||||
channel-type.ojelectronics.comfortEndTime.label = Komfort-Endzeit
|
||||
channel-type.ojelectronics.boostEndTime.label = Boost Endzeit
|
||||
channel-type.ojelectronics.manualSetpoint.label = manuelle Endzeit
|
||||
channel-type.ojelectronics.vacationEnabled.label = Urlausbmodus aktiviert
|
||||
@@ -0,0 +1,161 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bindingId="ojelectronics"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
<!-- Bridge -->
|
||||
<bridge-type id="ojcloud">
|
||||
<label>OJ Electronics Cloud</label>
|
||||
<description>Access to all OJ Electronic devices.</description>
|
||||
<config-description>
|
||||
<parameter name="userName" type="text" required="true">
|
||||
<label>User Name</label>
|
||||
<description>User Name for access cloud service.</description>
|
||||
</parameter>
|
||||
<parameter name="password" type="text" required="true">
|
||||
<label>Password</label>
|
||||
<description>Password for access cloud service.</description>
|
||||
<context>password</context>
|
||||
</parameter>
|
||||
<parameter name="apiKey" type="text" required="true" min="36" max="36">
|
||||
<label>API Key</label>
|
||||
<description>API-Key from your local distributor</description>
|
||||
</parameter>
|
||||
<parameter name="apiUrl" type="text" required="true">
|
||||
<label>API-URL</label>
|
||||
<description>URL to cloud API-service.</description>
|
||||
<context>url</context>
|
||||
<advanced>true</advanced>
|
||||
<default>https://OWD5-OJ001-App.ojelectronics.com/api</default>
|
||||
</parameter>
|
||||
<parameter name="refreshDelayInSeconds" type="integer" required="true" min="15" unit="s">
|
||||
<label>Refresh Delay</label>
|
||||
<description>Refresh delay in seconds.</description>
|
||||
<advanced>true</advanced>
|
||||
<default>30</default>
|
||||
</parameter>
|
||||
<parameter name="customerId" type="integer" required="true">
|
||||
<label>Customer ID</label>
|
||||
<description>Customer ID</description>
|
||||
<advanced>true</advanced>
|
||||
<default>1</default>
|
||||
</parameter>
|
||||
<parameter name="softwareVersion" type="integer" required="true">
|
||||
<label>Software Version</label>
|
||||
<description>Software Version</description>
|
||||
<advanced>true</advanced>
|
||||
<default>1060</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
<thing-type id="owd5">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="ojcloud"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>OWD5/MWD5 Thermostat</label>
|
||||
<description>OWD5/MWD5 Thermostat</description>
|
||||
<category>RadiatorControl</category>
|
||||
<channels>
|
||||
<channel id="floorTemperature" typeId="floorTemperature"/>
|
||||
<channel id="roomTemperature" typeId="roomTemperature"/>
|
||||
<channel id="groupName" typeId="groupName"/>
|
||||
<channel id="groupId" typeId="groupId"/>
|
||||
<channel id="online" typeId="online"/>
|
||||
<channel id="heating" typeId="heating"/>
|
||||
<channel id="thermostatName" typeId="thermostatName"/>
|
||||
<channel id="regulationMode" typeId="regulationMode"/>
|
||||
<channel id="comfortSetpoint" typeId="comfortSetpoint"/>
|
||||
<channel id="comfortEndTime" typeId="comfortEndTime"/>
|
||||
<channel id="boostEndTime" typeId="boostEndTime"/>
|
||||
<channel id="manualSetpoint" typeId="manualSetpoint"/>
|
||||
<channel id="vacationEnabled" typeId="vacationEnabled"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="vendor">OJ Electronics</property>
|
||||
</properties>
|
||||
<config-description>
|
||||
<parameter name="serialNumber" type="text" required="true">
|
||||
<label>Serial Number</label>
|
||||
<description>Serial number of the thermostat. You can find the serial number in the app or on the thermostat itself.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
<channel-type id="floorTemperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Floor Temperature</label>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="groupName">
|
||||
<item-type>String</item-type>
|
||||
<label>Group Name</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="groupId">
|
||||
<item-type>Number</item-type>
|
||||
<label>Group ID</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="online">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Online</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="heating">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Heating</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="roomTemperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Room Temperature</label>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="thermostatName">
|
||||
<item-type>String</item-type>
|
||||
<label>Thermostat Name</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="regulationMode">
|
||||
<item-type>String</item-type>
|
||||
<label>Regulation Mode</label>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="auto">Auto</option>
|
||||
<option value="comfort">Comfort</option>
|
||||
<option value="manual">Manual</option>
|
||||
<option value="vacation">Vacation</option>
|
||||
<option value="frostProtection">Frost Protection</option>
|
||||
<option value="boost">Boost</option>
|
||||
<option value="eco">Eco</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
<channel-type id="comfortSetpoint">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Comfort Set Point Temperature</label>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="comfortEndTime">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>End Time of Comfort Mode</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="boostEndTime">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>End Time of Boost Mode</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="manualSetpoint">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Manual Set Point Temperature</label>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="vacationEnabled">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Vacation Mode Enabled</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user