]> git.basschouten.com Git - openhab-addons.git/blob
4cc5c3446ebad45707c46315cd46820cfdc40afc
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.io.homekit.internal;
14
15 import java.util.Arrays;
16 import java.util.List;
17 import java.util.concurrent.ExecutionException;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.core.io.console.Console;
22 import org.openhab.core.io.console.ConsoleCommandCompleter;
23 import org.openhab.core.io.console.StringsCompleter;
24 import org.openhab.core.io.console.extensions.AbstractConsoleCommandExtension;
25 import org.openhab.core.io.console.extensions.ConsoleCommandExtension;
26 import org.openhab.io.homekit.Homekit;
27 import org.openhab.io.homekit.internal.accessories.DummyHomekitAccessory;
28 import org.osgi.service.component.annotations.Component;
29 import org.osgi.service.component.annotations.Reference;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import io.github.hapjava.services.Service;
34
35 /**
36  * Console commands for interacting with the HomeKit integration
37  *
38  * @author Andy Lintner - Initial contribution
39  */
40 @Component(service = ConsoleCommandExtension.class)
41 @NonNullByDefault
42 public class HomekitCommandExtension extends AbstractConsoleCommandExtension {
43     private static final String SUBCMD_CLEAR_PAIRINGS = "clearPairings";
44     private static final String SUBCMD_LIST_ACCESSORIES = "list";
45     private static final String SUBCMD_PRINT_ACCESSORY = "show";
46     private static final String SUBCMD_ALLOW_UNAUTHENTICATED = "allowUnauthenticated";
47     private static final String SUBCMD_PRUNE_DUMMY_ACCESSORIES = "pruneDummyAccessories";
48     private static final String SUBCMD_LIST_DUMMY_ACCESSORIES = "listDummyAccessories";
49     private static final StringsCompleter SUBCMD_COMPLETER = new StringsCompleter(
50             List.of(SUBCMD_CLEAR_PAIRINGS, SUBCMD_LIST_ACCESSORIES, SUBCMD_PRINT_ACCESSORY,
51                     SUBCMD_ALLOW_UNAUTHENTICATED, SUBCMD_PRUNE_DUMMY_ACCESSORIES, SUBCMD_LIST_DUMMY_ACCESSORIES),
52             false);
53
54     private class CommandCompleter implements ConsoleCommandCompleter {
55         public boolean complete(String[] args, int cursorArgumentIndex, int cursorPosition, List<String> candidates) {
56             if (cursorArgumentIndex == 0) {
57                 boolean result = SUBCMD_COMPLETER.complete(args, cursorArgumentIndex, cursorPosition, candidates);
58                 return result;
59             }
60             return false;
61         }
62     }
63
64     private final Logger logger = LoggerFactory.getLogger(HomekitCommandExtension.class);
65
66     private @NonNullByDefault({}) Homekit homekit;
67
68     public HomekitCommandExtension() {
69         super("homekit", "Interact with the HomeKit integration.");
70     }
71
72     @Override
73     public void execute(String[] args, Console console) {
74         if (args.length > 0) {
75             String subCommand = args[0];
76             switch (subCommand) {
77                 case SUBCMD_CLEAR_PAIRINGS:
78                     clearHomekitPairings(console);
79                     break;
80
81                 case SUBCMD_ALLOW_UNAUTHENTICATED:
82                     if (args.length > 1) {
83                         boolean allow = Boolean.parseBoolean(args[1]);
84                         allowUnauthenticatedHomekitRequests(allow, console);
85                     } else {
86                         console.println("true/false is required as an argument");
87                     }
88                     break;
89                 case SUBCMD_LIST_ACCESSORIES:
90                     listAccessories(console);
91                     break;
92                 case SUBCMD_PRINT_ACCESSORY:
93                     if (args.length > 1) {
94                         printAccessory(args[1], console);
95                     } else {
96                         console.println("accessory id or name is required as an argument");
97                     }
98                     break;
99                 case SUBCMD_PRUNE_DUMMY_ACCESSORIES:
100                     pruneDummyAccessories(console);
101                     break;
102                 case SUBCMD_LIST_DUMMY_ACCESSORIES:
103                     listDummyAccessories(console);
104                     break;
105                 default:
106                     console.println("Unknown command '" + subCommand + "'");
107                     printUsage(console);
108                     break;
109             }
110         } else {
111             printUsage(console);
112         }
113     }
114
115     @Override
116     public List<String> getUsages() {
117         return Arrays.asList(buildCommandUsage(SUBCMD_LIST_ACCESSORIES, "list all HomeKit accessories"),
118                 buildCommandUsage(SUBCMD_PRINT_ACCESSORY + " <accessory id | accessory name>",
119                         "print additional details of the accessories which partially match provided ID or name."),
120                 buildCommandUsage(SUBCMD_CLEAR_PAIRINGS, "removes all pairings with HomeKit clients."),
121                 buildCommandUsage(SUBCMD_ALLOW_UNAUTHENTICATED + " <boolean>",
122                         "enables or disables unauthenticated access to facilitate debugging"),
123                 buildCommandUsage(SUBCMD_PRUNE_DUMMY_ACCESSORIES,
124                         "removes dummy accessories whose items no longer exist."),
125                 buildCommandUsage(SUBCMD_LIST_DUMMY_ACCESSORIES,
126                         "list dummy accessories whose items no longer exist."));
127     }
128
129     @Reference
130     public void setHomekit(Homekit homekit) {
131         this.homekit = homekit;
132     }
133
134     @Override
135     public @Nullable ConsoleCommandCompleter getCompleter() {
136         return new CommandCompleter();
137     }
138
139     private void clearHomekitPairings(Console console) {
140         homekit.clearHomekitPairings();
141         console.println("Cleared HomeKit pairings");
142     }
143
144     private void allowUnauthenticatedHomekitRequests(boolean allow, Console console) {
145         homekit.allowUnauthenticatedRequests(allow);
146         console.println((allow ? "Enabled " : "Disabled ") + "unauthenticated HomeKit access");
147     }
148
149     private void pruneDummyAccessories(Console console) {
150         homekit.pruneDummyAccessories();
151         console.println("Dummy accessories pruned.");
152     }
153
154     private void listAccessories(Console console) {
155         homekit.getAccessories().forEach(v -> {
156             try {
157                 console.println(v.getId() + " " + v.getName().get());
158             } catch (InterruptedException | ExecutionException e) {
159                 logger.warn("Cannot list accessories", e);
160             }
161         });
162     }
163
164     private void listDummyAccessories(Console console) {
165         homekit.getAccessories().forEach(v -> {
166             try {
167                 if (v instanceof DummyHomekitAccessory) {
168                     console.println(v.getSerialNumber().get());
169                 }
170             } catch (InterruptedException | ExecutionException e) {
171                 logger.warn("Cannot list accessories", e);
172             }
173         });
174     }
175
176     private void printService(Console console, Service service, int indent) {
177         console.println(" ".repeat(indent) + "Service Type: " + service.getClass().getSimpleName() + " ("
178                 + service.getType() + ")");
179         console.println(" ".repeat(indent + 2) + "Characteristics:");
180         service.getCharacteristics().forEach((c) -> {
181             try {
182                 console.println(
183                         " ".repeat(indent + 4) + c.getClass().getSimpleName() + ": " + c.toJson(0).get().toString());
184             } catch (InterruptedException | ExecutionException e) {
185             }
186         });
187         if (service.getLinkedServices().isEmpty()) {
188             return;
189         }
190         console.println(" ".repeat(indent + 2) + "Linked Services:");
191         service.getLinkedServices().forEach((s) -> printService(console, s, indent + 2));
192     }
193
194     private void printAccessory(String id, Console console) {
195         homekit.getAccessories().forEach(v -> {
196             try {
197                 if (("" + v.getId()).contains(id) || ((v.getName().get() != null)
198                         && (v.getName().get().toUpperCase().contains(id.toUpperCase())))) {
199                     console.println(v.getId() + " " + v.getName().get());
200                     console.println("Services:");
201                     v.getServices().forEach(s -> printService(console, s, 2));
202                     console.println("");
203                 }
204             } catch (InterruptedException | ExecutionException e) {
205                 logger.warn("Cannot print accessory", e);
206             }
207         });
208     }
209 }