Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ojelectronics] Initial contribution #7138

Merged
merged 11 commits into from
Jul 11, 2020
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
/bundles/org.openhab.binding.ntp/ @marcelrv
/bundles/org.openhab.binding.nuki/ @mkatter
/bundles/org.openhab.binding.oceanic/ @kgoderis
/bundles/org.openhab.binding.ojelectronics/ @EvilPingu
/bundles/org.openhab.binding.omnikinverter/ @hansbogert
/bundles/org.openhab.binding.onebusaway/ @sdwilsh
/bundles/org.openhab.binding.onewiregpio/ @aogorek
Expand Down
5 changes: 5 additions & 0 deletions bom/openhab-addons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,11 @@
<artifactId>org.openhab.binding.oceanic</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.ojelectronics</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.omnikinverter</artifactId>
Expand Down
32 changes: 32 additions & 0 deletions bundles/org.openhab.binding.ojelectronics/.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>
23 changes: 23 additions & 0 deletions bundles/org.openhab.binding.ojelectronics/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.binding.ojelectronics</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>
13 changes: 13 additions & 0 deletions bundles/org.openhab.binding.ojelectronics/NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.

* Project home: https://www.openhab.org

== Declared Project Licenses

This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.

== Source Code

https://github.com/openhab/openhab-addons
57 changes: 57 additions & 0 deletions bundles/org.openhab.binding.ojelectronics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# OJElectronics Binding

With this binding it is possible to connect [OWD5/MWD5 Thermostat](https://www.ojelectronics.com/business-areas/wifi-thermostat-owd5-prod400) of OJ Electronics.

At this moment all information is read only.

## Supported Things

There are two things:

| Thing | Type | Description |
|----------------------|--------|-------------------------------------|
| ojcloud | Bridge | OJ Electronics Cloud Connector |
| owd5 | Thing | OJ Electronics OWD5/MWD5 Thermostat |

## Discovery

Not supported at the moment.

## Thing Configuration

### OJ Electronics Bridge configuration (ojcloud)

| Parameter | Description |
|-----------------------|--------------------------------------------------------------------------|
| userName | user name from the OJElectronics App (required) |
| 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. |

### OJ Electronics OWD5/MWD5 Thermostat configuration (owd5)

| Parameter | Description |
|-----------------------|--------------------------------------------------------------------------|
| serialNumber | serial number from the OJElectronics App or the thermostat (required) |

## Channels

| Channel | Type | Description |
|--------------------|--------------------|------------------------------------------------------------------------------------|
| floorTemperature | Number:Temperature | Floor temperature |
| groupName | Text | Group name |
| groupId | Number | Group Id |
| online | Switch | Online |
| heating | Switch | Heating |
| roomTemperature | Number:Temperature | Room temperature |
| thermostatName | Text | Thermostat name |
| regulationMode | Text | Regulation mode |
| serialNumber | Text | Serial number |
| comfortSetpoint | Number:Temperature | Target comfort temperature |
| comfortEndTime | Date time | Date and time when the thermostat switchs back from comfort mode to automatic mode |
| boostEndTime | Date time | Date and time when the thermostat switchs back from boost mode to automatic mode |
| manualModeSetpoint | Number:Temperature | Target temperature of the manual mode |
| vacationEnabled | Switch | Vacation is enabled |
EvilPingu marked this conversation as resolved.
Show resolved Hide resolved
16 changes: 16 additions & 0 deletions bundles/org.openhab.binding.ojelectronics/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>2.5.7-SNAPSHOT</version>
</parent>

<artifactId>org.openhab.binding.ojelectronics</artifactId>

<name>openHAB Add-ons :: Bundles :: OJElectronics Binding</name>
</project>
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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.eclipse.smarthome.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";
}
Original file line number Diff line number Diff line change
@@ -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.eclipse.smarthome.core.thing.Bridge;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.ThingStatus;
import org.eclipse.smarthome.core.thing.ThingStatusDetail;
import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler;
import org.eclipse.smarthome.core.thing.binding.BridgeHandler;
import org.eclipse.smarthome.core.types.Command;
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.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);
}
}
Loading