]> git.basschouten.com Git - openhab-addons.git/blob
20d77e3bba26bcb5611f12eb7310f6847f471aa4
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.accessories;
14
15 import static org.openhab.io.homekit.internal.HomekitCharacteristicType.CURRENT_POSITION;
16 import static org.openhab.io.homekit.internal.HomekitCharacteristicType.POSITION_STATE;
17 import static org.openhab.io.homekit.internal.HomekitCharacteristicType.TARGET_POSITION;
18
19 import java.util.EnumMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.concurrent.CompletableFuture;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.core.library.items.RollershutterItem;
27 import org.openhab.core.library.types.DecimalType;
28 import org.openhab.core.library.types.PercentType;
29 import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
30 import org.openhab.io.homekit.internal.HomekitCharacteristicType;
31 import org.openhab.io.homekit.internal.HomekitSettings;
32 import org.openhab.io.homekit.internal.HomekitTaggedItem;
33
34 import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
35 import io.github.hapjava.characteristics.impl.windowcovering.PositionStateEnum;
36
37 /**
38  * Common methods for Door, Window and WindowCovering.
39  * 
40  * @author Eugen Freiter - Initial contribution
41  */
42 @NonNullByDefault
43 abstract class AbstractHomekitPositionAccessoryImpl extends AbstractHomekitAccessoryImpl {
44     protected int closedPosition;
45     protected int openPosition;
46     private final Map<PositionStateEnum, String> positionStateMapping;
47
48     public AbstractHomekitPositionAccessoryImpl(HomekitTaggedItem taggedItem,
49             List<HomekitTaggedItem> mandatoryCharacteristics, HomekitAccessoryUpdater updater,
50             HomekitSettings settings) {
51         super(taggedItem, mandatoryCharacteristics, updater, settings);
52         final String invertedConfig = getAccessoryConfiguration(HomekitTaggedItem.INVERTED, "true");
53         final boolean inverted = invertedConfig.equalsIgnoreCase("yes") || invertedConfig.equalsIgnoreCase("true");
54         closedPosition = inverted ? 0 : 100;
55         openPosition = inverted ? 100 : 0;
56         positionStateMapping = new EnumMap<>(PositionStateEnum.class);
57         positionStateMapping.put(PositionStateEnum.DECREASING, "DECREASING");
58         positionStateMapping.put(PositionStateEnum.INCREASING, "INCREASING");
59         positionStateMapping.put(PositionStateEnum.STOPPED, "STOPPED");
60         updateMapping(POSITION_STATE, positionStateMapping);
61     }
62
63     public CompletableFuture<Integer> getCurrentPosition() {
64         return CompletableFuture.completedFuture(convertPositionState(CURRENT_POSITION, openPosition, closedPosition));
65     }
66
67     public CompletableFuture<PositionStateEnum> getPositionState() {
68         return CompletableFuture
69                 .completedFuture(getKeyFromMapping(POSITION_STATE, positionStateMapping, PositionStateEnum.STOPPED));
70     }
71
72     public CompletableFuture<Integer> getTargetPosition() {
73         return CompletableFuture.completedFuture(convertPositionState(TARGET_POSITION, openPosition, closedPosition));
74     }
75
76     @NonNullByDefault({})
77     public CompletableFuture<Void> setTargetPosition(int value) {
78         getItem(TARGET_POSITION, RollershutterItem.class)
79                 .ifPresent(item -> item.send(new PercentType(convertPosition(value, openPosition))));
80         return CompletableFuture.completedFuture(null);
81     }
82
83     public void subscribeCurrentPosition(HomekitCharacteristicChangeCallback callback) {
84         subscribe(CURRENT_POSITION, callback);
85     }
86
87     public void subscribePositionState(HomekitCharacteristicChangeCallback callback) {
88         subscribe(POSITION_STATE, callback);
89     }
90
91     public void subscribeTargetPosition(HomekitCharacteristicChangeCallback callback) {
92         subscribe(TARGET_POSITION, callback);
93     }
94
95     public void unsubscribeCurrentPosition() {
96         unsubscribe(CURRENT_POSITION);
97     }
98
99     public void unsubscribePositionState() {
100         unsubscribe(POSITION_STATE);
101     }
102
103     public void unsubscribeTargetPosition() {
104         unsubscribe(TARGET_POSITION);
105     }
106
107     /**
108      * convert/invert position of door/window/blinds.
109      * openHAB Rollershutter is:
110      * - completely open if position is 0%,
111      * - completely closed if position is 100%.
112      * HomeKit mapping has inverted mapping
113      * From Specification: "For blinds/shades/awnings, a value of 0 indicates a position that permits the least light
114      * and a value
115      * of 100 indicates a position that allows most light.", i.e.
116      * HomeKit Blinds is
117      * - completely open if position is 100%,
118      * - completely closed if position is 0%.
119      *
120      * As openHAB rollershutter item is typically used for window covering, the binding has by default inverting
121      * mapping.
122      * One can override this default behaviour with inverted="false/no" flag. in this cases, openHAB item value will be
123      * sent to HomeKit with no changes.
124      *
125      * @param value source value
126      * @return target value
127      */
128     protected int convertPosition(int value, int openPosition) {
129         return Math.abs(openPosition - value);
130     }
131
132     protected int convertPositionState(HomekitCharacteristicType type, int openPosition, int closedPosition) {
133         final @Nullable DecimalType value = getStateAs(type, PercentType.class);
134         return value != null ? convertPosition(value.intValue(), openPosition) : closedPosition;
135     }
136 }