2 * Copyright (c) 2010-2023 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.HomekitOHItemProxy;
30 import org.openhab.io.homekit.internal.HomekitSettings;
31 import org.openhab.io.homekit.internal.HomekitTaggedItem;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
35 import io.github.hapjava.accessories.GarageDoorOpenerAccessory;
36 import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
37 import io.github.hapjava.characteristics.impl.garagedoor.CurrentDoorStateEnum;
38 import io.github.hapjava.characteristics.impl.garagedoor.TargetDoorStateEnum;
39 import io.github.hapjava.services.impl.GarageDoorOpenerService;
42 * Implements Garage Door Opener
44 * @author Eugen Freiter - Initial contribution
46 public class HomekitGarageDoorOpenerImpl extends AbstractHomekitAccessoryImpl implements GarageDoorOpenerAccessory {
47 private final Logger logger = LoggerFactory.getLogger(HomekitGarageDoorOpenerImpl.class);
48 private final BooleanItemReader obstructionReader;
50 public HomekitGarageDoorOpenerImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
51 HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
52 super(taggedItem, mandatoryCharacteristics, updater, settings);
53 obstructionReader = createBooleanReader(OBSTRUCTION_STATUS);
54 getServices().add(new GarageDoorOpenerService(this));
58 public CompletableFuture<CurrentDoorStateEnum> getCurrentDoorState() {
59 final Optional<HomekitTaggedItem> characteristic = getCharacteristic(CURRENT_DOOR_STATE);
60 final HomekitSettings settings = getSettings();
61 String stringValue = settings.doorCurrentStateClosed;
62 if (characteristic.isPresent()) {
63 stringValue = characteristic.get().getItem().getState().toString();
65 logger.warn("Missing mandatory characteristic {}", CURRENT_DOOR_STATE);
67 CurrentDoorStateEnum mode;
69 if (stringValue.equalsIgnoreCase(settings.doorCurrentStateClosed)) {
70 mode = CurrentDoorStateEnum.CLOSED;
71 } else if (stringValue.equalsIgnoreCase(settings.doorCurrentStateClosing)) {
72 mode = CurrentDoorStateEnum.CLOSING;
73 } else if (stringValue.equalsIgnoreCase(settings.doorCurrentStateOpen)) {
74 mode = CurrentDoorStateEnum.OPEN;
75 } else if (stringValue.equalsIgnoreCase(settings.doorCurrentStateOpening)) {
76 mode = CurrentDoorStateEnum.OPENING;
77 } else if (stringValue.equalsIgnoreCase(settings.doorCurrentStateStopped)) {
78 mode = CurrentDoorStateEnum.STOPPED;
79 } else if (stringValue.equals("UNDEF") || stringValue.equals("NULL")) {
80 logger.warn("Current door state not available. Relaying value of CLOSED to HomeKit");
81 mode = CurrentDoorStateEnum.CLOSED;
83 logger.warn("Unrecognized current door state: {}. Expected {}, {}, {}, {} or {} strings in value.",
84 stringValue, settings.doorCurrentStateClosed, settings.doorCurrentStateClosing,
85 settings.doorCurrentStateOpen, settings.doorCurrentStateOpening, settings.doorCurrentStateStopped);
86 mode = CurrentDoorStateEnum.CLOSED;
88 return CompletableFuture.completedFuture(mode);
92 public CompletableFuture<TargetDoorStateEnum> getTargetDoorState() {
93 final Optional<HomekitTaggedItem> characteristic = getCharacteristic(TARGET_DOOR_STATE);
96 if (characteristic.isPresent()) {
97 item = characteristic.get().getItem();
99 logger.warn("Missing mandatory characteristic {}", TARGET_DOOR_STATE);
100 return CompletableFuture.completedFuture(TargetDoorStateEnum.CLOSED);
102 TargetDoorStateEnum mode;
104 final Item baseItem = HomekitOHItemProxy.getBaseItem(item);
105 if (baseItem instanceof SwitchItem) {
106 mode = item.getState() == OnOffType.ON ? TargetDoorStateEnum.OPEN : TargetDoorStateEnum.CLOSED;
107 } else if (baseItem instanceof StringItem) {
108 final HomekitSettings settings = getSettings();
109 final String stringValue = item.getState().toString();
110 if (stringValue.equalsIgnoreCase(settings.doorTargetStateClosed)) {
111 mode = TargetDoorStateEnum.CLOSED;
112 } else if (stringValue.equalsIgnoreCase(settings.doorTargetStateOpen)) {
113 mode = TargetDoorStateEnum.OPEN;
116 "Unsupported value {} for {}. Only {} and {} supported. Check HomeKit settings if you want to change the mapping",
117 stringValue, item.getName(), settings.doorTargetStateClosed, settings.doorTargetStateOpen);
118 mode = TargetDoorStateEnum.CLOSED;
121 logger.warn("Unsupported item type {} for {}. Only Switch and String are supported", baseItem.getType(),
123 mode = TargetDoorStateEnum.CLOSED;
125 return CompletableFuture.completedFuture(mode);
129 public CompletableFuture<Boolean> getObstructionDetected() {
130 return CompletableFuture.completedFuture(obstructionReader.getValue());
134 public CompletableFuture<Void> setTargetDoorState(TargetDoorStateEnum targetDoorStateEnum) {
135 final Optional<HomekitTaggedItem> characteristic = getCharacteristic(TARGET_DOOR_STATE);
136 final HomekitTaggedItem taggedItem;
137 if (characteristic.isPresent()) {
138 taggedItem = characteristic.get();
140 logger.warn("Missing mandatory characteristic {}", TARGET_DOOR_STATE);
141 return CompletableFuture.completedFuture(null);
144 if (taggedItem.getBaseItem() instanceof SwitchItem) {
145 taggedItem.send(OnOffType.from(targetDoorStateEnum == TargetDoorStateEnum.OPEN));
146 } else if (taggedItem.getBaseItem() instanceof StringItem) {
147 final HomekitSettings settings = getSettings();
149 .send(new StringType(targetDoorStateEnum == TargetDoorStateEnum.OPEN ? settings.doorTargetStateOpen
150 : settings.doorTargetStateClosed));
152 logger.warn("Unsupported item type {} for {}. Only Switch and String are supported",
153 taggedItem.getBaseItem().getType(), taggedItem.getName());
155 return CompletableFuture.completedFuture(null);
159 public void subscribeCurrentDoorState(HomekitCharacteristicChangeCallback callback) {
160 subscribe(CURRENT_DOOR_STATE, callback);
164 public void subscribeTargetDoorState(HomekitCharacteristicChangeCallback callback) {
165 subscribe(TARGET_DOOR_STATE, callback);
169 public void subscribeObstructionDetected(HomekitCharacteristicChangeCallback callback) {
170 subscribe(OBSTRUCTION_STATUS, callback);
174 public void unsubscribeCurrentDoorState() {
175 unsubscribe(CURRENT_DOOR_STATE);
179 public void unsubscribeTargetDoorState() {
180 unsubscribe(TARGET_DOOR_STATE);
184 public void unsubscribeObstructionDetected() {
185 unsubscribe(OBSTRUCTION_STATUS);