2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.io.homekit.internal;
15 import java.util.Arrays;
16 import java.util.List;
17 import java.util.concurrent.ExecutionException;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.openhab.core.io.console.Console;
21 import org.openhab.core.io.console.extensions.AbstractConsoleCommandExtension;
22 import org.openhab.core.io.console.extensions.ConsoleCommandExtension;
23 import org.openhab.io.homekit.Homekit;
24 import org.openhab.io.homekit.internal.accessories.DummyHomekitAccessory;
25 import org.osgi.service.component.annotations.Component;
26 import org.osgi.service.component.annotations.Reference;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
30 import io.github.hapjava.services.Service;
33 * Console commands for interacting with the HomeKit integration
35 * @author Andy Lintner - Initial contribution
37 @Component(service = ConsoleCommandExtension.class)
39 public class HomekitCommandExtension extends AbstractConsoleCommandExtension {
40 private static final String SUBCMD_CLEAR_PAIRINGS = "clearPairings";
41 private static final String SUBCMD_LIST_ACCESSORIES = "list";
42 private static final String SUBCMD_PRINT_ACCESSORY = "show";
43 private static final String SUBCMD_ALLOW_UNAUTHENTICATED = "allowUnauthenticated";
44 private static final String SUBCMD_PRUNE_DUMMY_ACCESSORIES = "pruneDummyAccessories";
45 private static final String SUBCMD_LIST_DUMMY_ACCESSORIES = "listDummyAccessories";
47 private final Logger logger = LoggerFactory.getLogger(HomekitCommandExtension.class);
49 private @NonNullByDefault({}) Homekit homekit;
51 public HomekitCommandExtension() {
52 super("homekit", "Interact with the HomeKit integration.");
56 public void execute(String[] args, Console console) {
57 if (args.length > 0) {
58 String subCommand = args[0];
60 case SUBCMD_CLEAR_PAIRINGS:
61 clearHomekitPairings(console);
64 case SUBCMD_ALLOW_UNAUTHENTICATED:
65 if (args.length > 1) {
66 boolean allow = Boolean.parseBoolean(args[1]);
67 allowUnauthenticatedHomekitRequests(allow, console);
69 console.println("true/false is required as an argument");
72 case SUBCMD_LIST_ACCESSORIES:
73 listAccessories(console);
75 case SUBCMD_PRINT_ACCESSORY:
76 if (args.length > 1) {
77 printAccessory(args[1], console);
79 console.println("accessory id or name is required as an argument");
82 case SUBCMD_PRUNE_DUMMY_ACCESSORIES:
83 pruneDummyAccessories(console);
85 case SUBCMD_LIST_DUMMY_ACCESSORIES:
86 listDummyAccessories(console);
89 console.println("Unknown command '" + subCommand + "'");
99 public List<String> getUsages() {
100 return Arrays.asList(buildCommandUsage(SUBCMD_LIST_ACCESSORIES, "list all HomeKit accessories"),
101 buildCommandUsage(SUBCMD_PRINT_ACCESSORY + " <accessory id | accessory name>",
102 "print additional details of the accessories which partially match provided ID or name."),
103 buildCommandUsage(SUBCMD_CLEAR_PAIRINGS, "removes all pairings with HomeKit clients."),
104 buildCommandUsage(SUBCMD_ALLOW_UNAUTHENTICATED + " <boolean>",
105 "enables or disables unauthenticated access to facilitate debugging"),
106 buildCommandUsage(SUBCMD_PRUNE_DUMMY_ACCESSORIES,
107 "removes dummy accessories whose items no longer exist."),
108 buildCommandUsage(SUBCMD_LIST_DUMMY_ACCESSORIES,
109 "list dummy accessories whose items no longer exist."));
113 public void setHomekit(Homekit homekit) {
114 this.homekit = homekit;
117 private void clearHomekitPairings(Console console) {
118 homekit.clearHomekitPairings();
119 console.println("Cleared HomeKit pairings");
122 private void allowUnauthenticatedHomekitRequests(boolean allow, Console console) {
123 homekit.allowUnauthenticatedRequests(allow);
124 console.println((allow ? "Enabled " : "Disabled ") + "unauthenticated HomeKit access");
127 private void pruneDummyAccessories(Console console) {
128 homekit.pruneDummyAccessories();
129 console.println("Dummy accessories pruned.");
132 private void listAccessories(Console console) {
133 homekit.getAccessories().forEach(v -> {
135 console.println(v.getId() + " " + v.getName().get());
136 } catch (InterruptedException | ExecutionException e) {
137 logger.warn("Cannot list accessories", e);
142 private void listDummyAccessories(Console console) {
143 homekit.getAccessories().forEach(v -> {
145 if (v instanceof DummyHomekitAccessory) {
146 console.println(v.getSerialNumber().get());
148 } catch (InterruptedException | ExecutionException e) {
149 logger.warn("Cannot list accessories", e);
154 private void printService(Console console, Service service, int indent) {
155 console.println(" ".repeat(indent) + "Service Type: " + service.getClass().getSimpleName() + " ("
156 + service.getType() + ")");
157 console.println(" ".repeat(indent + 2) + "Characteristics:");
158 service.getCharacteristics().forEach((c) -> {
161 " ".repeat(indent + 4) + c.getClass().getSimpleName() + ": " + c.toJson(0).get().toString());
162 } catch (InterruptedException | ExecutionException e) {
165 if (service.getLinkedServices().isEmpty()) {
168 console.println(" ".repeat(indent + 2) + "Linked Services:");
169 service.getLinkedServices().forEach((s) -> printService(console, s, indent + 2));
172 private void printAccessory(String id, Console console) {
173 homekit.getAccessories().forEach(v -> {
175 if (("" + v.getId()).contains(id) || ((v.getName().get() != null)
176 && (v.getName().get().toUpperCase().contains(id.toUpperCase())))) {
177 console.println(v.getId() + " " + v.getName().get());
178 console.println("Services:");
179 v.getServices().forEach(s -> printService(console, s, 2));
182 } catch (InterruptedException | ExecutionException e) {
183 logger.warn("Cannot print accessory", e);