forked from hap-java/HAP-Java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEnumCharacteristic.java
More file actions
162 lines (146 loc) · 4.75 KB
/
EnumCharacteristic.java
File metadata and controls
162 lines (146 loc) · 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package io.github.hapjava.characteristics.impl.base;
import io.github.hapjava.characteristics.CharacteristicEnum;
import io.github.hapjava.characteristics.ExceptionalConsumer;
import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonNumber;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.JsonValue;
/**
* Characteristic that exposes an Enum value. Enums are represented as an Integer value in the
* HomeKit protocol, and classes extending this one must handle the static mapping to an Integer
* value.
*
* @author Andy Lintner
*/
public abstract class EnumCharacteristic<T extends CharacteristicEnum>
extends BaseCharacteristic<Integer> {
private final T[] validValues;
protected Optional<Supplier<CompletableFuture<T>>> getter;
protected Optional<ExceptionalConsumer<T>> setter;
/**
* Default constructor
*
* @param type a string containing a UUID that indicates the type of characteristic. Apple defines
* a set of these, however implementors can create their own as well.
* @param description a description of the characteristic to be passed to the consuming device.
* @param validValues an array of valid values for enum.
* @param getter getter to retrieve the value
* @param setter setter to set value
* @param subscriber subscriber to subscribe to changes
* @param unsubscriber unsubscriber to unsubscribe from chnages
*/
public EnumCharacteristic(
String type,
String description,
T[] validValues,
Optional<Supplier<CompletableFuture<T>>> getter,
Optional<ExceptionalConsumer<T>> setter,
Optional<Consumer<HomekitCharacteristicChangeCallback>> subscriber,
Optional<Runnable> unsubscriber) {
super(
type, "int", description, getter.isPresent(), setter.isPresent(), subscriber, unsubscriber);
this.getter = getter;
this.setter = setter;
this.validValues = validValues;
}
/** {@inheritDoc} */
@Override
protected CompletableFuture<JsonObjectBuilder> makeBuilder(int iid) {
JsonArrayBuilder validValuesBuilder = Json.createArrayBuilder();
if (validValues != null && validValues.length != 0) {
Arrays.stream(validValues).forEach((T value) -> validValuesBuilder.add(value.getCode()));
}
return super.makeBuilder(iid)
.thenApply(
builder -> {
return builder.add("valid-values", validValuesBuilder);
});
}
/** {@inheritDoc} */
@Override
protected Integer convert(JsonValue jsonValue) {
if (jsonValue instanceof JsonNumber) {
return ((JsonNumber) jsonValue).intValue();
} else if (jsonValue == JsonObject.TRUE) {
return 1; // For at least one enum type (locks), homekit will send a true instead of 1
} else if (jsonValue == JsonObject.FALSE) {
return 0;
} else {
throw new IndexOutOfBoundsException("Cannot convert " + jsonValue.getClass() + " to int");
}
}
/**
* @return the current value of this characteristic, or null if it has no value or can't be
* fetched
*/
public CompletableFuture<T> getEnumValue() {
if (!getter.isPresent()) {
return null;
}
return getter.get().get();
}
@Override
public CompletableFuture<Integer> getValue() {
if (!getter.isPresent()) {
return null;
}
return getter
.get()
.get()
.thenApply(
e -> {
if (e == null) {
return null;
}
return e.getCode();
});
}
public void setValue(T value) throws Exception {
setValue(value, null);
}
public void setValue(T value, String username) throws Exception {
if (!setter.isPresent()) {
return;
}
setter.get().accept(value, username);
}
@Override
public void setValue(Integer value) throws Exception {
setValue(value, null);
}
@Override
public void setValue(Integer value, String username) throws Exception {
if (!setter.isPresent()) {
return;
}
// check if value is in valid values
if (validValues != null && value != null) {
for (T valid : validValues) {
if (valid.getCode() == value) {
setValue(valid, username);
return;
}
}
}
}
/** {@inheritDoc} */
@Override
public Integer getDefault() {
// as default return first item from valid values
if (validValues != null && validValues.length > 0) {
return validValues[0].getCode();
}
return 0;
}
public T[] getValidValues() {
return validValues;
}
}