]> git.basschouten.com Git - openhab-addons.git/blob
36354778c4f5b92fcba25773854c03db10a62cee
[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");
86     }
87
88     @Override
89     public void execute(String[] args, Console console) {
90         if (args.length == 0) {
91             printUsage(console);
92             return;
93         }
94         try {
95             if (GET_BRIDGEINFO.equals(args[0])) {
96                 console.print(buildBridgeInfo());
97                 return;
98             }
99             if (GET_DEVICES.equals(args[0])) {
100                 console.print(buildDeviceInfo());
101                 return;
102             }
103             if (SHOW_BINDINGINFO.equals(args[0])) {
104                 console.print(buildBindingInfo());
105                 return;
106             }
107             if (SHOW_DEVICES.equals(args[0])) {
108                 console.print(buildSupportedDeviceStatus());
109                 return;
110             }
111             if (SHOW_SERVICES.equals(args[0])) {
112                 console.print(buildSupportedServiceStatus());
113                 return;
114             }
115         } catch (BoschSHCException | ExecutionException | TimeoutException e) {
116             console.print(String.format("Error %1s%n", e.getMessage()));
117         } catch (InterruptedException e) {
118             Thread.currentThread().interrupt();
119         }
120         // unsupported command, print usage
121         printUsage(console);
122     }
123
124     private List<BridgeHandler> getBridgeHandlers() {
125         List<BridgeHandler> bridges = new ArrayList<>();
126         for (Thing thing : thingRegistry.getAll()) {
127             ThingHandler thingHandler = thing.getHandler();
128             if (thingHandler instanceof BridgeHandler bridgeHandler) {
129                 bridges.add(bridgeHandler);
130             }
131         }
132         return bridges;
133     }
134
135     String buildBridgeInfo() throws BoschSHCException, InterruptedException, ExecutionException, TimeoutException {
136         List<BridgeHandler> bridges = getBridgeHandlers();
137         StringBuilder builder = new StringBuilder();
138         for (BridgeHandler bridgeHandler : bridges) {
139             builder.append(String.format("Bridge: %1s%n", bridgeHandler.getThing().getLabel()));
140             builder.append(String.format("  access possible: %1s%n", bridgeHandler.checkBridgeAccess()));
141
142             PublicInformation publicInformation = bridgeHandler.getPublicInformation();
143             builder.append(String.format("  SHC Generation: %1s%n", publicInformation.shcGeneration));
144             builder.append(String.format("  IP Address: %1s%n", publicInformation.shcIpAddress));
145             builder.append(String.format("  API Versions: %1s%n", publicInformation.apiVersions));
146             builder.append(String.format("  Software Version: %1s%n",
147                     publicInformation.softwareUpdateState.swInstalledVersion));
148             builder.append(String.format("  Version Update State: %1s%n",
149                     publicInformation.softwareUpdateState.swUpdateState));
150             builder.append(String.format("  Available Version: %1s%n",
151                     publicInformation.softwareUpdateState.swUpdateAvailableVersion));
152             builder.append(String.format("%n"));
153         }
154         return builder.toString();
155     }
156
157     String buildDeviceInfo() throws InterruptedException {
158         StringBuilder builder = new StringBuilder();
159         for (Thing thing : thingRegistry.getAll()) {
160             ThingHandler thingHandler = thing.getHandler();
161             if (thingHandler instanceof BridgeHandler bridgeHandler) {
162                 builder.append(String.format("thing: %1s%n", thing.getLabel()));
163                 builder.append(String.format("  thingHandler: %1s%n", thingHandler.getClass().getName()));
164                 builder.append(String.format("bridge access possible: %1s%n", bridgeHandler.checkBridgeAccess()));
165
166                 List<Device> devices = bridgeHandler.getDevices();
167                 builder.append(String.format("devices (%1d): %n", devices.size()));
168                 for (Device device : devices) {
169                     builder.append(buildDeviceInfo(device));
170                     builder.append(String.format("%n"));
171                 }
172             }
173         }
174         return builder.toString();
175     }
176
177     private String buildDeviceInfo(Device device) {
178         StringBuilder builder = new StringBuilder();
179         builder.append(String.format("  deviceID: %1s%n", device.id));
180         builder.append(String.format("      type: %1s -> ", device.deviceModel));
181         if (DEVICEMODEL_TO_THINGTYPE_MAP.containsKey(device.deviceModel)) {
182             builder.append(DEVICEMODEL_TO_THINGTYPE_MAP.get(device.deviceModel).getId());
183         } else {
184             builder.append("!UNSUPPORTED!");
185         }
186         builder.append(String.format("%n"));
187
188         builder.append(buildDeviceServices(device.deviceServiceIds));
189         return builder.toString();
190     }
191
192     private String buildDeviceServices(List<String> deviceServiceIds) {
193         StringBuilder builder = new StringBuilder();
194         List<String> existingServices = getAllBoschShcServices();
195         for (String serviceName : deviceServiceIds) {
196             builder.append(String.format("            service: %1s -> ", serviceName));
197
198             if (existingServices.stream().anyMatch(s -> s.equals(serviceName.toLowerCase()))) {
199                 for (String existingService : existingServices) {
200                     if (existingService.equals(serviceName.toLowerCase())) {
201                         builder.append(existingService);
202                     }
203                 }
204             } else {
205                 builder.append("!UNSUPPORTED!");
206             }
207             builder.append(String.format("%n"));
208         }
209         return builder.toString();
210     }
211
212     String buildBindingInfo() {
213         StringBuilder builder = new StringBuilder();
214         builder.append(String.format("Bosch SHC Binding%n"));
215         Bundle bundle = FrameworkUtil.getBundle(getClass());
216         if (bundle != null) {
217             builder.append(String.format("  SymbolicName %1s%n", bundle.getSymbolicName()));
218             builder.append(String.format("  Version %1s%n", bundle.getVersion()));
219         }
220         return builder.toString();
221     }
222
223     String buildSupportedDeviceStatus() {
224         StringBuilder builder = new StringBuilder();
225         builder.append(String.format("Supported Devices (%1d):%n", DEVICEMODEL_TO_THINGTYPE_MAP.size()));
226         for (Map.Entry<String, ThingTypeUID> entry : DEVICEMODEL_TO_THINGTYPE_MAP.entrySet()) {
227             builder.append(
228                     String.format(" - %1s = %1s%n", entry.getKey(), DEVICEMODEL_TO_THINGTYPE_MAP.get(entry.getKey())));
229         }
230         return builder.toString();
231     }
232
233     String buildSupportedServiceStatus() {
234         StringBuilder builder = new StringBuilder();
235         List<String> supportedServices = getAllBoschShcServices();
236         builder.append(String.format("Supported Services (%1d):%n", supportedServices.size()));
237         for (String service : supportedServices) {
238             builder.append(String.format(" - %1s%n", service));
239         }
240         return builder.toString();
241     }
242
243     @Override
244     public List<String> getUsages() {
245         return List.of(buildCommandUsage(SHOW_BINDINGINFO, "list detailed information about this binding"),
246                 buildCommandUsage(SHOW_DEVICES, "list all devices supported by this binding"),
247                 buildCommandUsage(SHOW_SERVICES, "list all services supported by this binding"),
248                 buildCommandUsage(GET_DEVICES, "get all Bosch SHC devices"),
249                 buildCommandUsage(GET_BRIDGEINFO, "get detailed information from Bosch SHC"));
250     }
251
252     @Override
253     public @Nullable ConsoleCommandCompleter getCompleter() {
254         return this;
255     }
256
257     @Override
258     public boolean complete(String[] args, int cursorArgumentIndex, int cursorPosition, List<String> candidates) {
259         if (cursorArgumentIndex <= 0) {
260             return SUBCMD_COMPLETER.complete(args, cursorArgumentIndex, cursorPosition, candidates);
261         }
262         return false;
263     }
264 }