mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[boschshc] Add command to list SHC device mappings (#15060)
* [boschshc] add command to list Bosch Smart Home Controller devices and mapping to openhab devices and related services Signed-off-by: Gerd Zanker <gerd.zanker@web.de> Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
parent
b9dba4a8b2
commit
c3b29b3508
@ -0,0 +1,264 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.boschshc.internal.console;
|
||||
|
||||
import static org.openhab.binding.boschshc.internal.discovery.ThingDiscoveryService.DEVICEMODEL_TO_THINGTYPE_MAP;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.BridgeHandler;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.dto.Device;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.dto.PublicInformation;
|
||||
import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
|
||||
import org.openhab.core.io.console.Console;
|
||||
import org.openhab.core.io.console.ConsoleCommandCompleter;
|
||||
import org.openhab.core.io.console.StringsCompleter;
|
||||
import org.openhab.core.io.console.extensions.AbstractConsoleCommandExtension;
|
||||
import org.openhab.core.io.console.extensions.ConsoleCommandExtension;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingRegistry;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* Console command to list Bosch SHC devices and openhab support.
|
||||
* Use the SHC API to get all SHC devices and SHC services
|
||||
* and tries to lookup openhab devices and implemented service classes.
|
||||
* Prints each name and looked-up implementation on console.
|
||||
*
|
||||
* @author Gerd Zanker - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = ConsoleCommandExtension.class)
|
||||
public class BoschShcCommandExtension extends AbstractConsoleCommandExtension implements ConsoleCommandCompleter {
|
||||
|
||||
static final String SHOW_BINDINGINFO = "showBindingInfo";
|
||||
static final String SHOW_DEVICES = "showDevices";
|
||||
static final String SHOW_SERVICES = "showServices";
|
||||
|
||||
static final String GET_BRIDGEINFO = "bridgeInfo";
|
||||
static final String GET_DEVICES = "deviceInfo";
|
||||
private static final StringsCompleter SUBCMD_COMPLETER = new StringsCompleter(
|
||||
List.of(SHOW_BINDINGINFO, SHOW_DEVICES, SHOW_SERVICES, GET_BRIDGEINFO, GET_DEVICES), false);
|
||||
|
||||
private final ThingRegistry thingRegistry;
|
||||
|
||||
@Activate
|
||||
public BoschShcCommandExtension(final @Reference ThingRegistry thingRegistry) {
|
||||
super(BoschSHCBindingConstants.BINDING_ID, "Interact with the Bosch Smart Home Controller.");
|
||||
this.thingRegistry = thingRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all implemented services of this Bosch SHC binding.
|
||||
* This list shall contain all available services and needs to be extended when a new service is added.
|
||||
* A unit tests checks if this list matches with the existing subfolders in
|
||||
* "src/main/java/org/openhab/binding/boschshc/internal/services".
|
||||
*/
|
||||
List<String> getAllBoschShcServices() {
|
||||
return List.of("airqualitylevel", "batterylevel", "binaryswitch", "bypass", "cameranotification", "childlock",
|
||||
"communicationquality", "hsbcoloractuator", "humiditylevel", "illuminance", "intrusion", "keypad",
|
||||
"latestmotion", "multilevelswitch", "powermeter", "powerswitch", "privacymode", "roomclimatecontrol",
|
||||
"shuttercontact", "shuttercontrol", "silentmode", "smokedetectorcheck", "temperaturelevel", "userstate",
|
||||
"valvetappet");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String[] args, Console console) {
|
||||
if (args.length == 0) {
|
||||
printUsage(console);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (GET_BRIDGEINFO.equals(args[0])) {
|
||||
console.print(buildBridgeInfo());
|
||||
return;
|
||||
}
|
||||
if (GET_DEVICES.equals(args[0])) {
|
||||
console.print(buildDeviceInfo());
|
||||
return;
|
||||
}
|
||||
if (SHOW_BINDINGINFO.equals(args[0])) {
|
||||
console.print(buildBindingInfo());
|
||||
return;
|
||||
}
|
||||
if (SHOW_DEVICES.equals(args[0])) {
|
||||
console.print(buildSupportedDeviceStatus());
|
||||
return;
|
||||
}
|
||||
if (SHOW_SERVICES.equals(args[0])) {
|
||||
console.print(buildSupportedServiceStatus());
|
||||
return;
|
||||
}
|
||||
} catch (BoschSHCException | ExecutionException | TimeoutException e) {
|
||||
console.print(String.format("Error %1s%n", e.getMessage()));
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
// unsupported command, print usage
|
||||
printUsage(console);
|
||||
}
|
||||
|
||||
private List<BridgeHandler> getBridgeHandlers() {
|
||||
List<BridgeHandler> bridges = new ArrayList<>();
|
||||
for (Thing thing : thingRegistry.getAll()) {
|
||||
ThingHandler thingHandler = thing.getHandler();
|
||||
if (thingHandler instanceof BridgeHandler bridgeHandler) {
|
||||
bridges.add(bridgeHandler);
|
||||
}
|
||||
}
|
||||
return bridges;
|
||||
}
|
||||
|
||||
String buildBridgeInfo() throws BoschSHCException, InterruptedException, ExecutionException, TimeoutException {
|
||||
List<BridgeHandler> bridges = getBridgeHandlers();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (BridgeHandler bridgeHandler : bridges) {
|
||||
builder.append(String.format("Bridge: %1s%n", bridgeHandler.getThing().getLabel()));
|
||||
builder.append(String.format(" access possible: %1s%n", bridgeHandler.checkBridgeAccess()));
|
||||
|
||||
PublicInformation publicInformation = bridgeHandler.getPublicInformation();
|
||||
builder.append(String.format(" SHC Generation: %1s%n", publicInformation.shcGeneration));
|
||||
builder.append(String.format(" IP Address: %1s%n", publicInformation.shcIpAddress));
|
||||
builder.append(String.format(" API Versions: %1s%n", publicInformation.apiVersions));
|
||||
builder.append(String.format(" Software Version: %1s%n",
|
||||
publicInformation.softwareUpdateState.swInstalledVersion));
|
||||
builder.append(String.format(" Version Update State: %1s%n",
|
||||
publicInformation.softwareUpdateState.swUpdateState));
|
||||
builder.append(String.format(" Available Version: %1s%n",
|
||||
publicInformation.softwareUpdateState.swUpdateAvailableVersion));
|
||||
builder.append(String.format("%n"));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
String buildDeviceInfo() throws InterruptedException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Thing thing : thingRegistry.getAll()) {
|
||||
ThingHandler thingHandler = thing.getHandler();
|
||||
if (thingHandler instanceof BridgeHandler bridgeHandler) {
|
||||
builder.append(String.format("thing: %1s%n", thing.getLabel()));
|
||||
builder.append(String.format(" thingHandler: %1s%n", thingHandler.getClass().getName()));
|
||||
builder.append(String.format("bridge access possible: %1s%n", bridgeHandler.checkBridgeAccess()));
|
||||
|
||||
List<Device> devices = bridgeHandler.getDevices();
|
||||
builder.append(String.format("devices (%1d): %n", devices.size()));
|
||||
for (Device device : devices) {
|
||||
builder.append(buildDeviceInfo(device));
|
||||
builder.append(String.format("%n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String buildDeviceInfo(Device device) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(String.format(" deviceID: %1s%n", device.id));
|
||||
builder.append(String.format(" type: %1s -> ", device.deviceModel));
|
||||
if (DEVICEMODEL_TO_THINGTYPE_MAP.containsKey(device.deviceModel)) {
|
||||
builder.append(DEVICEMODEL_TO_THINGTYPE_MAP.get(device.deviceModel).getId());
|
||||
} else {
|
||||
builder.append("!UNSUPPORTED!");
|
||||
}
|
||||
builder.append(String.format("%n"));
|
||||
|
||||
builder.append(buildDeviceServices(device.deviceServiceIds));
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String buildDeviceServices(List<String> deviceServiceIds) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
List<String> existingServices = getAllBoschShcServices();
|
||||
for (String serviceName : deviceServiceIds) {
|
||||
builder.append(String.format(" service: %1s -> ", serviceName));
|
||||
|
||||
if (existingServices.stream().anyMatch(s -> s.equals(serviceName.toLowerCase()))) {
|
||||
for (String existingService : existingServices) {
|
||||
if (existingService.equals(serviceName.toLowerCase())) {
|
||||
builder.append(existingService);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
builder.append("!UNSUPPORTED!");
|
||||
}
|
||||
builder.append(String.format("%n"));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
String buildBindingInfo() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(String.format("Bosch SHC Binding%n"));
|
||||
Bundle bundle = FrameworkUtil.getBundle(getClass());
|
||||
if (bundle != null) {
|
||||
builder.append(String.format(" SymbolicName %1s%n", bundle.getSymbolicName()));
|
||||
builder.append(String.format(" Version %1s%n", bundle.getVersion()));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
String buildSupportedDeviceStatus() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(String.format("Supported Devices (%1d):%n", DEVICEMODEL_TO_THINGTYPE_MAP.size()));
|
||||
for (Map.Entry<String, ThingTypeUID> entry : DEVICEMODEL_TO_THINGTYPE_MAP.entrySet()) {
|
||||
builder.append(
|
||||
String.format(" - %1s = %1s%n", entry.getKey(), DEVICEMODEL_TO_THINGTYPE_MAP.get(entry.getKey())));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
String buildSupportedServiceStatus() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
List<String> supportedServices = getAllBoschShcServices();
|
||||
builder.append(String.format("Supported Services (%1d):%n", supportedServices.size()));
|
||||
for (String service : supportedServices) {
|
||||
builder.append(String.format(" - %1s%n", service));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUsages() {
|
||||
return List.of(buildCommandUsage(SHOW_BINDINGINFO, "list detailed information about this binding"),
|
||||
buildCommandUsage(SHOW_DEVICES, "list all devices supported by this binding"),
|
||||
buildCommandUsage(SHOW_SERVICES, "list all services supported by this binding"),
|
||||
buildCommandUsage(GET_DEVICES, "get all Bosch SHC devices"),
|
||||
buildCommandUsage(GET_BRIDGEINFO, "get detailed information from Bosch SHC"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ConsoleCommandCompleter getCompleter() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean complete(String[] args, int cursorArgumentIndex, int cursorPosition, List<String> candidates) {
|
||||
if (cursorArgumentIndex <= 0) {
|
||||
return SUBCMD_COMPLETER.complete(args, cursorArgumentIndex, cursorPosition, candidates);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ import org.openhab.binding.boschshc.internal.devices.BoschSHCHandler;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.dto.Device;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.dto.DeviceServiceData;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.dto.LongPollResult;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.dto.PublicInformation;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.dto.Room;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.dto.Scenario;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.dto.UserDefinedState;
|
||||
@ -432,6 +433,23 @@ public class BridgeHandler extends BaseBridgeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get public information from Bosch SHC.
|
||||
*/
|
||||
public PublicInformation getPublicInformation()
|
||||
throws InterruptedException, BoschSHCException, ExecutionException, TimeoutException {
|
||||
@Nullable
|
||||
BoschHttpClient localHttpClient = this.httpClient;
|
||||
if (localHttpClient == null) {
|
||||
throw new BoschSHCException(HTTP_CLIENT_NOT_INITIALIZED);
|
||||
}
|
||||
|
||||
String url = localHttpClient.getPublicInformationUrl();
|
||||
Request request = localHttpClient.createRequest(url, GET);
|
||||
|
||||
return localHttpClient.sendRequest(request, PublicInformation.class, PublicInformation::isValid, null);
|
||||
}
|
||||
|
||||
public boolean registerDiscoveryListener(ThingDiscoveryService listener) {
|
||||
if (thingDiscoveryService == null) {
|
||||
thingDiscoveryService = listener;
|
||||
@ -604,7 +622,7 @@ public class BridgeHandler extends BaseBridgeHandler {
|
||||
@Nullable
|
||||
BoschHttpClient localHttpClient = this.httpClient;
|
||||
if (localHttpClient == null) {
|
||||
throw new BoschSHCException("HTTP client not initialized");
|
||||
throw new BoschSHCException(HTTP_CLIENT_NOT_INITIALIZED);
|
||||
}
|
||||
|
||||
String url = localHttpClient.getBoschSmartHomeUrl(String.format("devices/%s", deviceId));
|
||||
@ -634,7 +652,7 @@ public class BridgeHandler extends BaseBridgeHandler {
|
||||
@Nullable
|
||||
BoschHttpClient locaHttpClient = this.httpClient;
|
||||
if (locaHttpClient == null) {
|
||||
throw new BoschSHCException("HTTP client not initialized");
|
||||
throw new BoschSHCException(HTTP_CLIENT_NOT_INITIALIZED);
|
||||
}
|
||||
|
||||
String url = locaHttpClient.getBoschSmartHomeUrl(String.format("userdefinedstates/%s", stateId));
|
||||
|
@ -55,7 +55,7 @@ public class Device {
|
||||
public String status;
|
||||
public List<String> childDeviceIds;
|
||||
|
||||
public static Boolean isValid(Device obj) {
|
||||
public static boolean isValid(Device obj) {
|
||||
return obj != null && obj.id != null;
|
||||
}
|
||||
|
||||
|
@ -42,4 +42,10 @@ public class PublicInformation {
|
||||
public List<String> apiVersions;
|
||||
public String shcIpAddress;
|
||||
public String shcGeneration;
|
||||
public SoftwareUpdateState softwareUpdateState;
|
||||
|
||||
public static boolean isValid(PublicInformation obj) {
|
||||
return obj != null && obj.shcIpAddress != null && obj.shcGeneration != null && obj.apiVersions != null
|
||||
&& SoftwareUpdateState.isValid(obj.softwareUpdateState);
|
||||
}
|
||||
}
|
||||
|
@ -48,17 +48,13 @@ public class Scenario extends BoschSHCServiceState {
|
||||
return scenario;
|
||||
}
|
||||
|
||||
public static Boolean isValid(Scenario[] scenarios) {
|
||||
public static boolean isValid(Scenario[] scenarios) {
|
||||
return Arrays.stream(scenarios).allMatch(scenario -> (scenario.id != null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("Scenario{");
|
||||
sb.append("name='").append(name).append("'");
|
||||
sb.append(", id='").append(id).append("'");
|
||||
sb.append(", lastTimeTriggered='").append(lastTimeTriggered).append("'");
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
return "Scenario{" + "name='" + name + "'" + ", id='" + id + "'" + ", lastTimeTriggered='" + lastTimeTriggered
|
||||
+ "'" + '}';
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.boschshc.internal.devices.bridge.dto;
|
||||
|
||||
/**
|
||||
* Software Update State is part of PublicInformation.
|
||||
*
|
||||
* @author Gerd Zanker - Initial contribution
|
||||
*/
|
||||
public class SoftwareUpdateState {
|
||||
|
||||
public String swUpdateState;
|
||||
public String swInstalledVersion;
|
||||
public String swUpdateAvailableVersion;
|
||||
|
||||
public static boolean isValid(SoftwareUpdateState obj) {
|
||||
return obj != null && obj.swUpdateState != null && obj.swInstalledVersion != null
|
||||
&& obj.swUpdateAvailableVersion != null;
|
||||
}
|
||||
}
|
@ -31,7 +31,7 @@ public class SubscribeResult {
|
||||
return this.jsonrpc;
|
||||
}
|
||||
|
||||
public static Boolean isValid(SubscribeResult obj) {
|
||||
public static boolean isValid(SubscribeResult obj) {
|
||||
return obj != null && obj.result != null && obj.jsonrpc != null;
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ public class UserDefinedState extends BoschSHCServiceState {
|
||||
+ type + '\'' + '}';
|
||||
}
|
||||
|
||||
public static Boolean isValid(UserDefinedState obj) {
|
||||
public static boolean isValid(UserDefinedState obj) {
|
||||
return obj != null && obj.id != null;
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ public class ThingDiscoveryService extends AbstractThingHandlerDiscoveryService<
|
||||
BoschSHCBindingConstants.THING_TYPE_SMOKE_DETECTOR);
|
||||
|
||||
// @formatter:off
|
||||
protected static final Map<String, ThingTypeUID> DEVICEMODEL_TO_THINGTYPE_MAP = Map.ofEntries(
|
||||
public static final Map<String, ThingTypeUID> DEVICEMODEL_TO_THINGTYPE_MAP = Map.ofEntries(
|
||||
new AbstractMap.SimpleEntry<>("BBL", BoschSHCBindingConstants.THING_TYPE_SHUTTER_CONTROL),
|
||||
new AbstractMap.SimpleEntry<>("TWINGUARD", BoschSHCBindingConstants.THING_TYPE_TWINGUARD),
|
||||
new AbstractMap.SimpleEntry<>("BSM", BoschSHCBindingConstants.THING_TYPE_INWALL_SWITCH),
|
||||
|
@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.boschshc.internal.console;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.BridgeHandler;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.dto.Device;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.dto.PublicInformation;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.dto.SoftwareUpdateState;
|
||||
import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
|
||||
import org.openhab.core.io.console.Console;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingRegistry;
|
||||
|
||||
/**
|
||||
* Unit tests for Console command to list Bosch SHC devices and openhab support.
|
||||
*
|
||||
* @author Gerd Zanker - Initial contribution
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@NonNullByDefault
|
||||
class BoschShcCommandExtensionTest {
|
||||
|
||||
private @NonNullByDefault({}) BoschShcCommandExtension fixture;
|
||||
|
||||
private @Mock @NonNullByDefault({}) ThingRegistry thingRegistry;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
fixture = new BoschShcCommandExtension(thingRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
void execute() {
|
||||
// only sanity checks, content is tested with the functions called by execute
|
||||
Console consoleMock = mock(Console.class);
|
||||
when(thingRegistry.getAll()).thenReturn(Collections.emptyList());
|
||||
|
||||
fixture.execute(new String[] {}, consoleMock);
|
||||
verify(consoleMock, times(5)).printUsage(any());
|
||||
fixture.execute(new String[] { "" }, consoleMock);
|
||||
verify(consoleMock, times(10)).printUsage(any());
|
||||
|
||||
fixture.execute(new String[] { BoschShcCommandExtension.SHOW_BINDINGINFO }, consoleMock);
|
||||
verify(consoleMock, atLeastOnce()).print(any());
|
||||
fixture.execute(new String[] { BoschShcCommandExtension.SHOW_DEVICES }, consoleMock);
|
||||
verify(consoleMock, atLeastOnce()).print(any());
|
||||
fixture.execute(new String[] { BoschShcCommandExtension.SHOW_SERVICES }, consoleMock);
|
||||
verify(consoleMock, atLeastOnce()).print(any());
|
||||
|
||||
fixture.execute(new String[] { BoschShcCommandExtension.GET_BRIDGEINFO }, consoleMock);
|
||||
verify(consoleMock, atLeastOnce()).print(any());
|
||||
fixture.execute(new String[] { BoschShcCommandExtension.GET_DEVICES }, consoleMock);
|
||||
verify(consoleMock, atLeastOnce()).print(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCompleter() {
|
||||
assertThat(fixture.getCompleter(), is(fixture));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUsages() {
|
||||
List<String> strings = fixture.getUsages();
|
||||
assertThat(strings.size(), is(5));
|
||||
assertThat(strings.get(0), is("boschshc showBindingInfo - list detailed information about this binding"));
|
||||
assertThat(strings.get(1), is("boschshc showDevices - list all devices supported by this binding"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void complete() {
|
||||
ArrayList<String> candidates = new ArrayList<>();
|
||||
assertThat(fixture.complete(new String[] { "" }, 1, 0, candidates), is(false));
|
||||
assertThat(fixture.complete(new String[] { "" }, 0, 0, candidates), is(true));
|
||||
// for empty arguments, the completer suggest all usage commands
|
||||
assertThat(candidates.size(), is(fixture.getUsages().size()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void printBridgeInfo() throws BoschSHCException, ExecutionException, InterruptedException, TimeoutException {
|
||||
// no bridge
|
||||
when(thingRegistry.getAll()).thenReturn(Collections.emptyList());
|
||||
assertThat(fixture.buildBridgeInfo(), is(""));
|
||||
|
||||
// one bridge
|
||||
PublicInformation publicInformation = new PublicInformation();
|
||||
publicInformation.shcGeneration = "Gen-T";
|
||||
publicInformation.shcIpAddress = "1.2.3.4";
|
||||
publicInformation.softwareUpdateState = new SoftwareUpdateState();
|
||||
Bridge mockBridge = mock(Bridge.class);
|
||||
when(mockBridge.getLabel()).thenReturn("TestLabel");
|
||||
BridgeHandler mockBridgeHandler = mock(BridgeHandler.class);
|
||||
when(mockBridgeHandler.getThing()).thenReturn(mockBridge);
|
||||
when(mockBridgeHandler.getPublicInformation()).thenReturn(publicInformation);
|
||||
Thing mockBridgeThing = mock(Thing.class);
|
||||
when(mockBridgeThing.getHandler()).thenReturn(mockBridgeHandler);
|
||||
when(thingRegistry.getAll()).thenReturn(Collections.singletonList(mockBridgeThing));
|
||||
assertThat(fixture.buildBridgeInfo(),
|
||||
allOf(containsString("Bridge: TestLabel"), containsString("access possible: false"),
|
||||
containsString("SHC Generation: Gen-T"), containsString("IP Address: 1.2.3.4")));
|
||||
|
||||
// two bridges
|
||||
PublicInformation publicInformation2 = new PublicInformation();
|
||||
publicInformation2.shcGeneration = "Gen-U";
|
||||
publicInformation2.shcIpAddress = "11.22.33.44";
|
||||
publicInformation2.softwareUpdateState = new SoftwareUpdateState();
|
||||
Bridge mockBridge2 = mock(Bridge.class);
|
||||
when(mockBridge2.getLabel()).thenReturn("Bridge 2");
|
||||
BridgeHandler mockBridgeHandler2 = mock(BridgeHandler.class);
|
||||
when(mockBridgeHandler2.getThing()).thenReturn(mockBridge2);
|
||||
when(mockBridgeHandler2.getPublicInformation()).thenReturn(publicInformation2);
|
||||
Thing mockBridgeThing2 = mock(Thing.class);
|
||||
when(mockBridgeThing2.getHandler()).thenReturn(mockBridgeHandler2);
|
||||
when(thingRegistry.getAll()).thenReturn(Arrays.asList(mockBridgeThing, mockBridgeThing2));
|
||||
assertThat(fixture.buildBridgeInfo(),
|
||||
allOf(containsString("Bridge: TestLabel"), containsString("access possible: false"),
|
||||
containsString("SHC Generation: Gen-T"), containsString("IP Address: 1.2.3.4"),
|
||||
containsString("Bridge: Bridge 2"), containsString("access possible: false"),
|
||||
containsString("SHC Generation: Gen-U"), containsString("IP Address: 11.22.33.44")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void printDeviceInfo() throws InterruptedException {
|
||||
// no bridge
|
||||
when(thingRegistry.getAll()).thenReturn(Collections.emptyList());
|
||||
assertThat(fixture.buildDeviceInfo(), is(""));
|
||||
|
||||
// One bridge, No device
|
||||
BridgeHandler mockBridgeHandler = mock(BridgeHandler.class);
|
||||
Thing mockBridgeThing = mock(Thing.class);
|
||||
when(mockBridgeThing.getLabel()).thenReturn("TestLabel");
|
||||
when(mockBridgeThing.getHandler()).thenReturn(mockBridgeHandler);
|
||||
when(thingRegistry.getAll()).thenReturn(Collections.singletonList(mockBridgeThing));
|
||||
assertThat(fixture.buildDeviceInfo(), allOf(containsString("thing: TestLabel"), containsString("devices (0)")));
|
||||
|
||||
// One bridge, One UNsupported device
|
||||
Device mockShcDevice = mock(Device.class);
|
||||
mockShcDevice.deviceModel = "";
|
||||
mockShcDevice.deviceServiceIds = Collections.emptyList();
|
||||
when(mockBridgeHandler.getDevices()).thenReturn(List.of(mockShcDevice));
|
||||
assertThat(fixture.buildDeviceInfo(), allOf(containsString("thing: TestLabel"), containsString("devices (1)"),
|
||||
containsString("!UNSUPPORTED!")));
|
||||
|
||||
// One bridge, One supported device
|
||||
mockShcDevice.deviceModel = "TWINGUARD";
|
||||
mockShcDevice.deviceServiceIds = Collections.emptyList();
|
||||
when(mockBridgeHandler.getDevices()).thenReturn(List.of(mockShcDevice));
|
||||
assertThat(fixture.buildDeviceInfo(), allOf(containsString("thing: TestLabel"), containsString("devices (1)"),
|
||||
containsString("TWINGUARD -> twinguard")));
|
||||
|
||||
// One bridge, One supported device with services
|
||||
mockShcDevice.deviceModel = "TWINGUARD";
|
||||
mockShcDevice.deviceServiceIds = List.of("unknownService", "batterylevel");
|
||||
when(mockBridgeHandler.getDevices()).thenReturn(List.of(mockShcDevice));
|
||||
assertThat(fixture.buildDeviceInfo(), allOf(containsString("thing: TestLabel"), containsString("devices (1)"),
|
||||
containsString("TWINGUARD -> twinguard"), containsString("service: unknownService -> !UNSUPPORTED!"),
|
||||
containsString("batterylevel -> batterylevel")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void printBindingInfo() {
|
||||
assertThat(fixture.buildBindingInfo(), containsString("Bosch SHC Binding"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void printSupportedDevices() {
|
||||
assertThat(fixture.buildSupportedDeviceStatus(),
|
||||
allOf(containsString("Supported Devices"), containsString("BBL = boschshc:shutter-control")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void printSupportedServices() {
|
||||
assertThat(fixture.buildSupportedServiceStatus(),
|
||||
allOf(containsString("Supported Services"), containsString("airqualitylevel")));
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of services returned by getAllBoschShcServices() shall match
|
||||
* the implemented services in org.openhab.bindings.boschshc.internal.services.
|
||||
* Because reflection doesn't return all services classes during runtime
|
||||
* this test supports consistency between the lists of services and the implemented services.
|
||||
*/
|
||||
@Test
|
||||
void getAllBoschShcServices() throws IOException {
|
||||
List<String> services = Files
|
||||
.walk(Paths.get("src/main/java/org/openhab/binding/boschshc/internal/services").toAbsolutePath(), 1)
|
||||
.filter(Files::isDirectory).map(Path::getFileName).map(Path::toString)
|
||||
// exclude folders which no service implementation
|
||||
.filter(name -> !name.equals("dto")).filter(name -> !name.equals("services")).sorted()
|
||||
.collect(Collectors.toList());
|
||||
assertThat(services, is(fixture.getAllBoschShcServices()));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user