]> git.basschouten.com Git - openhab-addons.git/blob
0b91213621482991c19d4d80a9177f2dcfaf640a
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.boschshc.internal.console;
14
15 import static org.openhab.binding.boschshc.internal.discovery.ThingDiscoveryService.DEVICEMODEL_TO_THINGTYPE_MAP;
16
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.TimeoutException;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
26 import org.openhab.binding.boschshc.internal.devices.bridge.BridgeHandler;
27 import org.openhab.binding.boschshc.internal.devices.bridge.dto.Device;
28 import org.openhab.binding.boschshc.internal.devices.bridge.dto.PublicInformation;
29 import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
30 import org.openhab.core.io.console.Console;
31 import org.openhab.core.io.console.ConsoleCommandCompleter;
32 import org.openhab.core.io.console.StringsCompleter;
33 import org.openhab.core.io.console.extensions.AbstractConsoleCommandExtension;
34 import org.openhab.core.io.console.extensions.ConsoleCommandExtension;
35 import org.openhab.core.thing.Thing;
36 import org.openhab.core.thing.ThingRegistry;
37 import org.openhab.core.thing.ThingTypeUID;
38 import org.openhab.core.thing.binding.ThingHandler;
39 import org.osgi.framework.Bundle;
40 import org.osgi.framework.FrameworkUtil;
41 import org.osgi.service.component.annotations.Activate;
42 import org.osgi.service.component.annotations.Component;
43 import org.osgi.service.component.annotations.Reference;
44
45 /**
46  * Console command to list Bosch SHC devices and openhab support.
47  * Use the SHC API to get all SHC devices and SHC services
48  * and tries to lookup openhab devices and implemented service classes.
49  * Prints each name and looked-up implementation on console.
50  *
51  * @author Gerd Zanker - Initial contribution
52  */
53 @NonNullByDefault
54 @Component(service = ConsoleCommandExtension.class)
55 public class BoschShcCommandExtension extends AbstractConsoleCommandExtension implements ConsoleCommandCompleter {
56
57     static final String SHOW_BINDINGINFO = "showBindingInfo";
58     static final String SHOW_DEVICES = "showDevices";
59     static final String SHOW_SERVICES = "showServices";
60
61     static final String GET_BRIDGEINFO = "bridgeInfo";
62     static final String GET_DEVICES = "deviceInfo";
63     private static final StringsCompleter SUBCMD_COMPLETER = new StringsCompleter(
64             List.of(SHOW_BINDINGINFO, SHOW_DEVICES, SHOW_SERVICES, GET_BRIDGEINFO, GET_DEVICES), false);
65
66     private final ThingRegistry thingRegistry;
67
68     @Activate
69     public BoschShcCommandExtension(final @Reference ThingRegistry thingRegistry) {
70         super(BoschSHCBindingConstants.BINDING_ID, "Interact with the Bosch Smart Home Controller.");
71         this.thingRegistry = thingRegistry;
72     }
73
74     /**
75      * Returns all implemented services of this Bosch SHC binding.
76      * This list shall contain all available services and needs to be extended when a new service is added.
77      * A unit tests checks if this list matches with the existing subfolders in
78      * "src/main/java/org/openhab/binding/boschshc/internal/services".
79      */
80     List<String> getAllBoschShcServices() {
81         return List.of("airqualitylevel", "batterylevel", "binaryswitch", "bypass", "cameranotification", "childlock",
82                 "childprotection", "communicationquality", "hsbcoloractuator", "humiditylevel", "illuminance",
83                 "intrusion", "keypad", "latestmotion", "multilevelswitch", "powermeter", "powerswitch", "privacymode",
84                 "roomclimatecontrol", "shuttercontact", "shuttercontrol", "silentmode", "smokedetectorcheck",
85                 "temperaturelevel", "userstate", "valvetappet", "waterleakagesensor", "waterleakagesensorcheck",
86                 "waterleakagesensortilt");
87     }
88
89     @Override
90     public void execute(String[] args, Console console) {
91         if (args.length == 0) {
92             printUsage(console);
93             return;
94         }
95         try {
96             if (GET_BRIDGEINFO.equals(args[0])) {
97                 console.print(buildBridgeInfo());
98                 return;
99             }
100             if (GET_DEVICES.equals(args[0])) {
101                 console.print(buildDeviceInfo());
102                 return;
103             }
104             if (SHOW_BINDINGINFO.equals(args[0])) {
105                 console.print(buildBindingInfo());
106                 return;
107             }
108             if (SHOW_DEVICES.equals(args[0])) {
109                 console.print(buildSupportedDeviceStatus());
110                 return;
111             }
112             if (SHOW_SERVICES.equals(args[0])) {
113                 console.print(buildSupportedServiceStatus());
114                 return;
115             }
116         } catch (BoschSHCException | ExecutionException | TimeoutException e) {
117             console.print(String.format("Error %1s%n", e.getMessage()));
118         } catch (InterruptedException e) {
119             Thread.currentThread().interrupt();
120         }
121         // unsupported command, print usage
122         printUsage(console);
123     }
124
125     private List<BridgeHandler> getBridgeHandlers() {
126         List<BridgeHandler> bridges = new ArrayList<>();
127         for (Thing thing : thingRegistry.getAll()) {
128             ThingHandler thingHandler = thing.getHandler();
129             if (thingHandler instanceof BridgeHandler bridgeHandler) {
130                 bridges.add(bridgeHandler);
131             }
132         }
133         return bridges;
134     }
135
136     String buildBridgeInfo() throws BoschSHCException, InterruptedException, ExecutionException, TimeoutException {
137         List<BridgeHandler> bridges = getBridgeHandlers();
138         StringBuilder builder = new StringBuilder();
139         for (BridgeHandler bridgeHandler : bridges) {
140             builder.append(String.format("Bridge: %1s%n", bridgeHandler.getThing().getLabel()));
141             builder.append(String.format("  access possible: %1s%n", bridgeHandler.checkBridgeAccess()));
142
143             PublicInformation publicInformation = bridgeHandler.getPublicInformation();
144             builder.append(String.format("  SHC Generation: %1s%n", publicInformation.shcGeneration));
145             builder.append(String.format("  IP Address: %1s%n", publicInformation.shcIpAddress));
146             builder.append(String.format("  API Versions: %1s%n", publicInformation.apiVersions));
147             builder.append(String.format("  Software Version: %1s%n",
148                     publicInformation.softwareUpdateState.swInstalledVersion));
149             builder.append(String.format("  Version Update State: %1s%n",
150                     publicInformation.softwareUpdateState.swUpdateState));
151             builder.append(String.format("  Available Version: %1s%n",
152                     publicInformation.softwareUpdateState.swUpdateAvailableVersion));
153             builder.append(String.format("%n"));
154         }
155         return builder.toString();
156     }
157
158     String buildDeviceInfo() throws InterruptedException {
159         StringBuilder builder = new StringBuilder();
160         for (Thing thing : thingRegistry.getAll()) {
161             ThingHandler thingHandler = thing.getHandler();
162             if (thingHandler instanceof BridgeHandler bridgeHandler) {
163                 builder.append(String.format("thing: %1s%n", thing.getLabel()));
164                 builder.append(String.format("  thingHandler: %1s%n", thingHandler.getClass().getName()));
165                 builder.append(String.format("bridge access possible: %1s%n", bridgeHandler.checkBridgeAccess()));
166
167                 List<Device> devices = bridgeHandler.getDevices();
168                 builder.append(String.format("devices (%1d): %n", devices.size()));
169                 for (Device device : devices) {
170                     builder.append(buildDeviceInfo(device));
171                     builder.append(String.format("%n"));
172                 }
173             }
174         }
175         return builder.toString();
176     }
177
178     private String buildDeviceInfo(Device device) {
179         StringBuilder builder = new StringBuilder();
180         builder.append(String.format("  deviceID: %1s%n", device.id));
181         builder.append(String.format("      type: %1s -> ", device.deviceModel));
182         if (DEVICEMODEL_TO_THINGTYPE_MAP.containsKey(device.deviceModel)) {
183             builder.append(DEVICEMODEL_TO_THINGTYPE_MAP.get(device.deviceModel).getId());
184         } else {
185             builder.append("!UNSUPPORTED!");
186         }
187         builder.append(String.format("%n"));
188
189         builder.append(buildDeviceServices(device.deviceServiceIds));
190         return builder.toString();
191     }
192
193     private String buildDeviceServices(List<String> deviceServiceIds) {
194         StringBuilder builder = new StringBuilder();
195         List<String> existingServices = getAllBoschShcServices();
196         for (String serviceName : deviceServiceIds) {
197             builder.append(String.format("            service: %1s -> ", serviceName));
198
199             if (existingServices.stream().anyMatch(s -> s.equals(serviceName.toLowerCase()))) {
200                 for (String existingService : existingServices) {
201                     if (existingService.equals(serviceName.toLowerCase())) {
202                         builder.append(existingService);
203                     }
204                 }
205             } else {
206                 builder.append("!UNSUPPORTED!");
207             }
208             builder.append(String.format("%n"));
209         }
210         return builder.toString();
211     }
212
213     String buildBindingInfo() {
214         StringBuilder builder = new StringBuilder();
215         builder.append(String.format("Bosch SHC Binding%n"));
216         Bundle bundle = FrameworkUtil.getBundle(getClass());
217         if (bundle != null) {
218             builder.append(String.format("  SymbolicName %1s%n", bundle.getSymbolicName()));
219             builder.append(String.format("  Version %1s%n", bundle.getVersion()));
220         }
221         return builder.toString();
222     }
223
224     String buildSupportedDeviceStatus() {
225         StringBuilder builder = new StringBuilder();
226         builder.append(String.format("Supported Devices (%1d):%n", DEVICEMODEL_TO_THINGTYPE_MAP.size()));
227         for (Map.Entry<String, ThingTypeUID> entry : DEVICEMODEL_TO_THINGTYPE_MAP.entrySet()) {
228             builder.append(
229                     String.format(" - %1s = %1s%n", entry.getKey(), DEVICEMODEL_TO_THINGTYPE_MAP.get(entry.getKey())));
230         }
231         return builder.toString();
232     }
233
234     String buildSupportedServiceStatus() {
235         StringBuilder builder = new StringBuilder();
236         List<String> supportedServices = getAllBoschShcServices();
237         builder.append(String.format("Supported Services (%1d):%n", supportedServices.size()));
238         for (String service : supportedServices) {
239             builder.append(String.format(" - %1s%n", service));
240         }
241         return builder.toString();
242     }
243
244     @Override
245     public List<String> getUsages() {
246         return List.of(buildCommandUsage(SHOW_BINDINGINFO, "list detailed information about this binding"),
247                 buildCommandUsage(SHOW_DEVICES, "list all devices supported by this binding"),
248                 buildCommandUsage(SHOW_SERVICES, "list all services supported by this binding"),
249                 buildCommandUsage(GET_DEVICES, "get all Bosch SHC devices"),
250                 buildCommandUsage(GET_BRIDGEINFO, "get detailed information from Bosch SHC"));
251     }
252
253     @Override
254     public @Nullable ConsoleCommandCompleter getCompleter() {
255         return this;
256     }
257
258     @Override
259     public boolean complete(String[] args, int cursorArgumentIndex, int cursorPosition, List<String> candidates) {
260         if (cursorArgumentIndex <= 0) {
261             return SUBCMD_COMPLETER.complete(args, cursorArgumentIndex, cursorPosition, candidates);
262         }
263         return false;
264     }
265 }