Skip to content

Commit

Permalink
[boschshc] Release v1.1 (openhab#10097)
Browse files Browse the repository at this point in the history
* openhab#72 changed use units of measure for the twinguard humidity and purity values

all other QuantityTypes in bindingcode are fine

* openhab#77 changed title of binding to Bosch Smart Home

Replaced the SHC occurrences with Smart Home,
to avoid technical names.

* openhab#62 Try to restart long polling when it fails before taking the thing offline

* openhab#62 Run subscribe request on a new thread instead of using the thread of the previous long polling http request

This might be the reason why the subscribe request does never finish or finishes with a timeout

* openhab#74 Run the whole long polling response handling in a new thread to not get timeout from HTTP client

* openhab#74 Schedule initial access when long polling fails unexpected

We need to try to reconnect again and again (with 15 seconds between the requests) as the controller may have been restarted (update, manual restart,...). This is already done by the initial access, so I reuse that mechanism.

* Use direct formatting of logger.trace instead of String.format

* openhab#76 Use i18n texts instead of raw translations for status messages about failed long polling

* openhab#76 Use logger.debug instead of logger.warn for long poll error as it is handled now

* openhab#78 defined api-version

each HTTP request will use now the defined "avp-version=2.1" for request to the smart home controller

* logging bundle version

removed the old static version string
access OSGi bundle version information instead

* openhab#75 improved initial access

- added isOnline check and isAccessPossible now failed in case HTTPStatus is an error
- same HTTPStatus check done to all blocking send() request calls
- using i18n strings for all bridge updateStatus calls
- skipped the 'controller' and use only 'Bosch Smart Home' in descriptions
- added more @nullable annotations
* added newline

Signed-off-by: Gerd Zanker <gerd.zanker@web.de>
Signed-off-by: Christian Oeing <christian.oeing@slashgames.org>
Signed-off-by: John Marshall <john.marshall.au@gmail.com>
  • Loading branch information
coeing authored and themillhousegroup committed May 10, 2021
1 parent 80d82d3 commit 2cd37ab
Show file tree
Hide file tree
Showing 13 changed files with 289 additions and 119 deletions.
16 changes: 10 additions & 6 deletions bundles/org.openhab.binding.boschshc/DEVELOPERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Build

To only build the Bosch SHC binding code execute
To only build the Bosch Smart Home binding code execute

mvn -pl :org.openhab.binding.boschshc install

Expand All @@ -15,28 +15,32 @@ For the first time the jar is loaded automatically as a bundle.

It should also be reloaded automatically when the jar changed.

To reload the bundle manually you need to execute:
To reload the bundle manually you need to execute in the openhab console:

bundle:update "openHAB Add-ons :: Bundles :: BoschSHC Binding"
bundle:update "openHAB Add-ons :: Bundles :: Bosch Smart Home Binding"

or get the ID and update the bundle using the ID:

bundle:list
-> Get ID for "openHAB Add-ons :: Bundles :: BoschSHC Binding"
-> Get ID for "openHAB Add-ons :: Bundles :: Bosch Smart Home Binding"
bundle:update <ID>


## Debugging

To get debug output and traces of the Bosch SHC binding code
To get debug output and traces of the Bosch Smart Home binding code
add the following lines into ``userdata/etc/log4j2.xml`` Loggers XML section.

<!-- Bosch SHC for debugging -->
<Logger level="TRACE" name="org.openhab.binding.boschshc"/>

or use the openhab console to change the log level

log:set TRACE org.openhab.binding.boschshc

## Pairing and Certificates

We need secured and paired connection from the openHAB binding instance to the Bosch SHC.
We need secured and paired connection from the openHAB binding instance to the Bosch Smart Home Controller (SHC).

Read more about the pairing process in [register a new client to the bosch smart home controller](https://github.com/BoschSmartHome/bosch-shc-api-docs/tree/master/postman#register-a-new-client-to-the-bosch-smart-home-controller)

Expand Down
12 changes: 6 additions & 6 deletions bundles/org.openhab.binding.boschshc/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# BoschSHC Binding
# Bosch Smart Home Binding

Binding for the Bosch Smart Home Controller.
Binding for the Bosch Smart Home.

- [BoschSHC Binding](#boschshc-binding)
- [Bosch Smart Home Binding](#bosch-smart-home-binding)
- [Supported Things](#supported-things)
- [Bosch In-Wall switches & Bosch Smart Plugs](#bosch-in-wall-switches--bosch-smart-plugs)
- [Bosch TwinGuard smoke detector](#bosch-twinguard-smoke-detector)
Expand All @@ -13,7 +13,7 @@ Binding for the Bosch Smart Home Controller.
- [Bosch Climate Control](#bosch-climate-control)
- [Limitations](#limitations)
- [Discovery](#discovery)
- [Binding Configuration](#binding-configuration)
- [Bridge Configuration](#bridge-configuration)
- [Getting the device IDs](#getting-the-device-ids)
- [Thing Configuration](#thing-configuration)
- [Item Configuration](#item-configuration)
Expand Down Expand Up @@ -102,8 +102,8 @@ You need to provide the IP address and the system password of your Bosch Smart H
The IP address of the controller is visible in the Bosch Smart Home Mobile App (More -> System -> Smart Home Controller) or in your network router UI.
The system password is set by you during your initial registration steps in the _Bosch Smart Home App_.

A keystore file with a self signed certificate is created automatically.
This certificate is used for pairing between the Bridge and the Bosch SHC.
A keystore file with a self-signed certificate is created automatically.
This certificate is used for pairing between the Bridge and the Bosch Smart Home Controller.

*Press and hold the Bosch Smart Home Controller Bridge button until the LED starts blinking after you save your settings for pairing*.

Expand Down
2 changes: 1 addition & 1 deletion bundles/org.openhab.binding.boschshc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

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

<name>openHAB Add-ons :: Bundles :: BoschSHC Binding</name>
<name>openHAB Add-ons :: Bundles :: Bosch Smart Home Binding</name>

<dependencies>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<features name="org.openhab.binding.boschshc-${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-boschshc" description="BoschSHC Binding" version="${project.version}">
<feature name="openhab-binding-boschshc" description="Bosch Smart Home Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.boschshc/${project.version}</bundle>
</feature>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -60,6 +61,16 @@ public BoschHttpClient(String ipAddress, String systemPassword, SslContextFactor
this.systemPassword = systemPassword;
}

/**
* Returns the public information URL for the Bosch SHC clients, using port 8446.
* See https://github.com/BoschSmartHome/bosch-shc-api-docs/blob/master/postman/README.md
*
* @return URL for public information
*/
public String getPublicInformationUrl() {
return String.format("https://%s:8446/smarthome/public/information", this.ipAddress);
}

/**
* Returns the pairing URL for the Bosch SHC clients, using port 8443.
* See https://github.com/BoschSmartHome/bosch-shc-api-docs/blob/master/postman/README.md
Expand Down Expand Up @@ -102,22 +113,60 @@ public String getServiceUrl(String serviceName, String deviceId) {
return this.getBoschSmartHomeUrl(String.format("devices/%s/services/%s/state", deviceId, serviceName));
}

/**
* Checks if the Bosch SHC is online.
*
* The HTTP server could be offline (Timeout of request).
* Or during boot-up the server can response e.g. with SERVICE_UNAVAILABLE_503
*
* Will return true, if the server responds with the "public information".
*
*
* @return true if HTTP server is online
* @throws InterruptedException in case of an interrupt
*/
public boolean isOnline() throws InterruptedException {
try {
String url = this.getPublicInformationUrl();
Request request = this.createRequest(url, GET);
ContentResponse contentResponse = request.send();
if (HttpStatus.getCode(contentResponse.getStatus()).isSuccess()) {
String content = contentResponse.getContentAsString();
logger.debug("Online check completed with success: {} - status code: {}", content,
contentResponse.getStatus());
return true;
} else {
logger.debug("Online check failed with status code: {}", contentResponse.getStatus());
return false;
}
} catch (TimeoutException | ExecutionException | NullPointerException e) {
logger.debug("Online check failed because of {}!", e.getMessage());
return false;
}
}

/**
* Checks if the Bosch SHC can be accessed.
*
* @return true if HTTP access was successful
*
* @return true if HTTP access to SHC devices was successful
* @throws InterruptedException in case of an interrupt
*/
public boolean isAccessPossible() throws InterruptedException {
try {
String url = this.getBoschSmartHomeUrl("devices");
Request request = this.createRequest(url, GET);
ContentResponse contentResponse = request.send();
String content = contentResponse.getContentAsString();
logger.debug("Access check response complete: {} - return code: {}", content, contentResponse.getStatus());
return true;
if (HttpStatus.getCode(contentResponse.getStatus()).isSuccess()) {
String content = contentResponse.getContentAsString();
logger.debug("Access check completed with success: {} - status code: {}", content,
contentResponse.getStatus());
return true;
} else {
logger.debug("Access check failed with status code: {}", contentResponse.getStatus());
return false;
}
} catch (TimeoutException | ExecutionException | NullPointerException e) {
logger.debug("Access check response failed because of {}!", e.getMessage());
logger.debug("Access check failed because of {}!", e.getMessage());
return false;
}
}
Expand All @@ -130,8 +179,8 @@ public boolean isAccessPossible() throws InterruptedException {
* @throws InterruptedException in case of an interrupt
*/
public boolean doPairing() throws InterruptedException {
logger.trace("Starting pairing openHAB Client with Bosch SmartHomeController!");
logger.trace("Please press the Bosch SHC button until LED starts blinking");
logger.trace("Starting pairing openHAB Client with Bosch Smart Home Controller!");
logger.trace("Please press the Bosch Smart Home Controller button until LED starts blinking");

ContentResponse contentResponse;
try {
Expand Down Expand Up @@ -169,7 +218,7 @@ public boolean doPairing() throws InterruptedException {
// javax.net.ssl.SSLHandshakeException: General SSLEngine problem
// => usually the pairing failed, because hardware button was not pressed.
logger.trace("Pairing failed - Details: {}", e.getMessage());
logger.warn("Pairing failed. Was the Bosch SHC button pressed?");
logger.warn("Pairing failed. Was the Bosch Smart Home Controller button pressed?");
return false;
}
}
Expand All @@ -194,7 +243,12 @@ public Request createRequest(String url, HttpMethod method) {
* @return created HTTP request instance
*/
public Request createRequest(String url, HttpMethod method, @Nullable Object content) {
Request request = this.newRequest(url).method(method).header("Content-Type", "application/json");
logger.trace("Create request for http client {}", this.toString());

Request request = this.newRequest(url).method(method).header("Content-Type", "application/json")
.header("api-version", "2.1") // see https://github.com/BoschSmartHome/bosch-shc-api-docs/issues/46
.timeout(10, TimeUnit.SECONDS); // Set default timeout

if (content != null) {
String body = GSON.toJson(content);
logger.trace("create request for {} and content {}", url, body);
Expand All @@ -203,9 +257,6 @@ public Request createRequest(String url, HttpMethod method, @Nullable Object con
logger.trace("create request for {}", url);
}

// Set default timeout
request.timeout(10, TimeUnit.SECONDS);

return request;
}

Expand All @@ -220,9 +271,11 @@ public Request createRequest(String url, HttpMethod method, @Nullable Object con
*/
public <TContent> TContent sendRequest(Request request, Class<TContent> responseContentClass)
throws InterruptedException, TimeoutException, ExecutionException {
logger.trace("Send request: {}", request.toString());

ContentResponse contentResponse = request.send();

logger.debug("BoschHttpClient: response complete: {} - return code: {}", contentResponse.getContentAsString(),
logger.debug("Received response: {} - status: {}", contentResponse.getContentAsString(),
contentResponse.getStatus());

try {
Expand Down

0 comments on commit 2cd37ab

Please sign in to comment.