2 * Copyright (c) 2010-2021 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.accessories;
15 import static org.openhab.io.homekit.internal.HomekitCharacteristicType.CURRENT_DOOR_STATE;
16 import static org.openhab.io.homekit.internal.HomekitCharacteristicType.OBSTRUCTION_STATUS;
17 import static org.openhab.io.homekit.internal.HomekitCharacteristicType.TARGET_DOOR_STATE;
19 import java.util.List;
20 import java.util.Optional;
21 import java.util.concurrent.CompletableFuture;
23 import org.openhab.core.items.Item;
24 import org.openhab.core.library.items.StringItem;
25 import org.openhab.core.library.items.SwitchItem;
26 import org.openhab.core.library.types.OnOffType;
27 import org.openhab.core.library.types.StringType;
28 import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
29 import org.openhab.io.homekit.internal.HomekitSettings;
30 import org.openhab.io.homekit.internal.HomekitTaggedItem;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
34 import io.github.hapjava.accessories.GarageDoorOpenerAccessory;
35 import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
36 import io.github.hapjava.characteristics.impl.garagedoor.CurrentDoorStateEnum;
37 import io.github.hapjava.characteristics.impl.garagedoor.TargetDoorStateEnum;
38 import io.github.hapjava.services.impl.GarageDoorOpenerService;
41 * Implements Garage Door Opener
43 * @author Eugen Freiter - Initial contribution
45 public class HomekitGarageDoorOpenerImpl extends AbstractHomekitAccessoryImpl implements GarageDoorOpenerAccessory {
46 private final Logger logger = LoggerFactory.getLogger(HomekitGarageDoorOpenerImpl.class);
47 private final BooleanItemReader obstructionReader;
49 public HomekitGarageDoorOpenerImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
50 HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
51 super(taggedItem, mandatoryCharacteristics, updater, settings);
52 obstructionReader = createBooleanReader(OBSTRUCTION_STATUS);
53 getServices().add(new GarageDoorOpenerService(this));
57 public CompletableFuture<CurrentDoorStateEnum> getCurrentDoorState() {
58 final Optional<HomekitTaggedItem> characteristic = getCharacteristic(CURRENT_DOOR_STATE);
59 final HomekitSettings settings = getSettings();
60 String stringValue = settings.doorCurrentStateClosed;
61 if (characteristic.isPresent()) {
62 stringValue = characteristic.get().getItem().getState().toString();
64 logger.warn("Missing mandatory characteristic {}", CURRENT_DOOR_STATE);
66 CurrentDoorStateEnum mode;
68 if (stringValue.equalsIgnoreCase(settings.doorCurrentStateClosed)) {
69 mode = CurrentDoorStateEnum.CLOSED;
70 } else if (stringValue.equalsIgnoreCase(settings.doorCurrentStateClosing)) {
71 mode = CurrentDoorStateEnum.CLOSING;
72 } else if (stringValue.equalsIgnoreCase(settings.doorCurrentStateOpen)) {
73 mode = CurrentDoorStateEnum.OPEN;
74 } else if (stringValue.equalsIgnoreCase(settings.doorCurrentStateOpening)) {
75 mode = CurrentDoorStateEnum.OPENING;
76 } else if (stringValue.equalsIgnoreCase(settings.doorCurrentStateStopped)) {
77 mode = CurrentDoorStateEnum.SOPPED;
78 } else if (stringValue.equals("UNDEF") || stringValue.equals("NULL")) {
79 logger.warn("Current door state not available. Relaying value of CLOSED to HomeKit");
80 mode = CurrentDoorStateEnum.CLOSED;
82 logger.warn("Unrecognized current door state: {}. Expected {}, {}, {}, {} or {} strings in value.",
83 stringValue, settings.doorCurrentStateClosed, settings.doorCurrentStateClosing,
84 settings.doorCurrentStateOpen, settings.doorCurrentStateOpening, settings.doorCurrentStateStopped);
85 mode = CurrentDoorStateEnum.CLOSED;
87 return CompletableFuture.completedFuture(mode);
91 public CompletableFuture<TargetDoorStateEnum> getTargetDoorState() {
92 final Optional<HomekitTaggedItem> characteristic = getCharacteristic(TARGET_DOOR_STATE);
95 if (characteristic.isPresent()) {
96 item = characteristic.get().getItem();
98 logger.warn("Missing mandatory characteristic {}", TARGET_DOOR_STATE);
99 return CompletableFuture.completedFuture(TargetDoorStateEnum.CLOSED);
101 TargetDoorStateEnum mode;
103 if (item instanceof SwitchItem) {
104 mode = item.getState() == OnOffType.ON ? TargetDoorStateEnum.OPEN : TargetDoorStateEnum.CLOSED;
105 } else if (item instanceof StringItem) {
106 final HomekitSettings settings = getSettings();
107 final String stringValue = item.getState().toString();
108 if (stringValue.equalsIgnoreCase(settings.doorTargetStateClosed)) {
109 mode = TargetDoorStateEnum.CLOSED;
110 } else if (stringValue.equalsIgnoreCase(settings.doorTargetStateOpen)) {
111 mode = TargetDoorStateEnum.OPEN;
114 "Unsupported value {} for {}. Only {} and {} supported. Check HomeKit settings if you want to change the mapping",
115 stringValue, item.getName(), settings.doorTargetStateClosed, settings.doorTargetStateOpen);
116 mode = TargetDoorStateEnum.CLOSED;
119 logger.warn("Unsupported item type {} for {}. Only Switch and String are supported", item.getType(),
121 mode = TargetDoorStateEnum.CLOSED;
123 return CompletableFuture.completedFuture(mode);
127 public CompletableFuture<Boolean> getObstructionDetected() {
128 return CompletableFuture.completedFuture(obstructionReader.getValue());
132 public CompletableFuture<Void> setTargetDoorState(TargetDoorStateEnum targetDoorStateEnum) {
133 final Optional<HomekitTaggedItem> characteristic = getCharacteristic(TARGET_DOOR_STATE);
135 if (characteristic.isPresent()) {
136 item = characteristic.get().getItem();
138 logger.warn("Missing mandatory characteristic {}", TARGET_DOOR_STATE);
139 return CompletableFuture.completedFuture(null);
142 if (item instanceof SwitchItem) {
143 ((SwitchItem) item).send(OnOffType.from(targetDoorStateEnum == TargetDoorStateEnum.OPEN));
144 } else if (item instanceof StringItem) {
145 final HomekitSettings settings = getSettings();
147 .send(new StringType(targetDoorStateEnum == TargetDoorStateEnum.OPEN ? settings.doorTargetStateOpen
148 : settings.doorTargetStateClosed));
150 logger.warn("Unsupported item type {} for {}. Only Switch and String are supported", item.getType(),
153 return CompletableFuture.completedFuture(null);
157 public void subscribeCurrentDoorState(HomekitCharacteristicChangeCallback callback) {
158 subscribe(CURRENT_DOOR_STATE, callback);
162 public void subscribeTargetDoorState(HomekitCharacteristicChangeCallback callback) {
163 subscribe(TARGET_DOOR_STATE, callback);
167 public void subscribeObstructionDetected(HomekitCharacteristicChangeCallback callback) {
168 subscribe(OBSTRUCTION_STATUS, callback);
172 public void unsubscribeCurrentDoorState() {
173 unsubscribe(CURRENT_DOOR_STATE);
177 public void unsubscribeTargetDoorState() {
178 unsubscribe(TARGET_DOOR_STATE);
182 public void unsubscribeObstructionDetected() {
183 unsubscribe(OBSTRUCTION_STATUS);