45
45
import io .github .hapjava .characteristics .Characteristic ;
46
46
import io .github .hapjava .characteristics .CharacteristicEnum ;
47
47
import io .github .hapjava .characteristics .HomekitCharacteristicChangeCallback ;
48
+ import io .github .hapjava .characteristics .impl .accessoryinformation .FirmwareRevisionCharacteristic ;
49
+ import io .github .hapjava .characteristics .impl .accessoryinformation .HardwareRevisionCharacteristic ;
50
+ import io .github .hapjava .characteristics .impl .accessoryinformation .IdentifyCharacteristic ;
51
+ import io .github .hapjava .characteristics .impl .accessoryinformation .ManufacturerCharacteristic ;
52
+ import io .github .hapjava .characteristics .impl .accessoryinformation .ModelCharacteristic ;
53
+ import io .github .hapjava .characteristics .impl .accessoryinformation .SerialNumberCharacteristic ;
48
54
import io .github .hapjava .characteristics .impl .base .BaseCharacteristic ;
55
+ import io .github .hapjava .characteristics .impl .common .NameCharacteristic ;
49
56
import io .github .hapjava .services .Service ;
57
+ import io .github .hapjava .services .impl .AccessoryInformationService ;
50
58
51
59
/**
52
60
* Abstract class for Homekit Accessory implementations, this provides the
@@ -62,6 +70,7 @@ public abstract class AbstractHomekitAccessoryImpl implements HomekitAccessory {
62
70
private final HomekitSettings settings ;
63
71
private final List <Service > services ;
64
72
private final Map <Class <? extends Characteristic >, Characteristic > rawCharacteristics ;
73
+ private boolean isLinkedService = false ;
65
74
66
75
public AbstractHomekitAccessoryImpl (HomekitTaggedItem accessory , List <HomekitTaggedItem > characteristics ,
67
76
HomekitAccessoryUpdater updater , HomekitSettings settings ) {
@@ -88,6 +97,52 @@ public AbstractHomekitAccessoryImpl(HomekitTaggedItem accessory, List<HomekitTag
88
97
* @throws HomekitException
89
98
*/
90
99
public void init () throws HomekitException {
100
+ // initialize the AccessoryInformation Service with defaults if not specified
101
+ if (!rawCharacteristics .containsKey (NameCharacteristic .class )) {
102
+ rawCharacteristics .put (NameCharacteristic .class , new NameCharacteristic (() -> {
103
+ return CompletableFuture .completedFuture (accessory .getItem ().getLabel ());
104
+ }));
105
+ }
106
+
107
+ if (!isLinkedService ()) {
108
+ if (!rawCharacteristics .containsKey (IdentifyCharacteristic .class )) {
109
+ rawCharacteristics .put (IdentifyCharacteristic .class , new IdentifyCharacteristic (v -> {
110
+ }));
111
+ }
112
+ if (!rawCharacteristics .containsKey (ManufacturerCharacteristic .class )) {
113
+ rawCharacteristics .put (ManufacturerCharacteristic .class , new ManufacturerCharacteristic (() -> {
114
+ return CompletableFuture .completedFuture ("none" );
115
+ }));
116
+ }
117
+ if (!rawCharacteristics .containsKey (ModelCharacteristic .class )) {
118
+ rawCharacteristics .put (ModelCharacteristic .class , new ModelCharacteristic (() -> {
119
+ return CompletableFuture .completedFuture ("none" );
120
+ }));
121
+ }
122
+ if (!rawCharacteristics .containsKey (SerialNumberCharacteristic .class )) {
123
+ rawCharacteristics .put (SerialNumberCharacteristic .class , new SerialNumberCharacteristic (() -> {
124
+ return CompletableFuture .completedFuture (accessory .getItem ().getName ());
125
+ }));
126
+ }
127
+ if (!rawCharacteristics .containsKey (FirmwareRevisionCharacteristic .class )) {
128
+ rawCharacteristics .put (FirmwareRevisionCharacteristic .class , new FirmwareRevisionCharacteristic (() -> {
129
+ return CompletableFuture .completedFuture ("none" );
130
+ }));
131
+ }
132
+
133
+ var service = new AccessoryInformationService (getCharacteristic (IdentifyCharacteristic .class ).get (),
134
+ getCharacteristic (ManufacturerCharacteristic .class ).get (),
135
+ getCharacteristic (ModelCharacteristic .class ).get (),
136
+ getCharacteristic (NameCharacteristic .class ).get (),
137
+ getCharacteristic (SerialNumberCharacteristic .class ).get (),
138
+ getCharacteristic (FirmwareRevisionCharacteristic .class ).get ());
139
+
140
+ getCharacteristic (HardwareRevisionCharacteristic .class )
141
+ .ifPresent (c -> service .addOptionalCharacteristic (c ));
142
+
143
+ // make sure this is the first service
144
+ services .add (0 , service );
145
+ }
91
146
}
92
147
93
148
/**
@@ -99,6 +154,20 @@ public boolean isLinkable(HomekitAccessory parentAccessory) {
99
154
return false ;
100
155
}
101
156
157
+ /**
158
+ * Sets if this accessory is being used as a linked service.
159
+ */
160
+ public void setIsLinkedService (boolean value ) {
161
+ isLinkedService = value ;
162
+ }
163
+
164
+ /**
165
+ * @return If this accessory is being used as a linked service.
166
+ */
167
+ public boolean isLinkedService () {
168
+ return isLinkedService ;
169
+ }
170
+
102
171
/**
103
172
* @return If this accessory is only valid as a linked service, not as a standalone accessory.
104
173
*/
@@ -118,32 +187,36 @@ public int getId() {
118
187
119
188
@ Override
120
189
public CompletableFuture <String > getName () {
121
- return CompletableFuture . completedFuture ( accessory . getItem (). getLabel () );
190
+ return getCharacteristic ( NameCharacteristic . class ). get (). getValue ( );
122
191
}
123
192
124
193
@ Override
125
194
public CompletableFuture <String > getManufacturer () {
126
- return CompletableFuture . completedFuture ( "none" );
195
+ return getCharacteristic ( ManufacturerCharacteristic . class ). get (). getValue ( );
127
196
}
128
197
129
198
@ Override
130
199
public CompletableFuture <String > getModel () {
131
- return CompletableFuture . completedFuture ( "none" );
200
+ return getCharacteristic ( ModelCharacteristic . class ). get (). getValue ( );
132
201
}
133
202
134
203
@ Override
135
204
public CompletableFuture <String > getSerialNumber () {
136
- return CompletableFuture . completedFuture ( accessory . getItem (). getName () );
205
+ return getCharacteristic ( SerialNumberCharacteristic . class ). get (). getValue ( );
137
206
}
138
207
139
208
@ Override
140
209
public CompletableFuture <String > getFirmwareRevision () {
141
- return CompletableFuture . completedFuture ( "none" );
210
+ return getCharacteristic ( FirmwareRevisionCharacteristic . class ). get (). getValue ( );
142
211
}
143
212
144
213
@ Override
145
214
public void identify () {
146
- // We're not going to support this for now
215
+ try {
216
+ getCharacteristic (IdentifyCharacteristic .class ).get ().setValue (true );
217
+ } catch (Exception e ) {
218
+ // ignore
219
+ }
147
220
}
148
221
149
222
public HomekitTaggedItem getRootAccessory () {
@@ -356,6 +429,31 @@ public void addCharacteristic(Characteristic characteristic)
356
429
}
357
430
}
358
431
432
+ /**
433
+ * Takes the NameCharacteristic that normally exists on the AccessoryInformationService,
434
+ * and puts it on the primary service.
435
+ */
436
+ public void promoteNameCharacteristic () {
437
+ var characteristic = getCharacteristic (NameCharacteristic .class );
438
+ if (!characteristic .isPresent ()) {
439
+ return ;
440
+ }
441
+
442
+ var service = getPrimaryService ();
443
+ if (service != null ) {
444
+ try {
445
+ // find the corresponding add method at service and call it.
446
+ service .getClass ().getMethod ("addOptionalCharacteristic" , NameCharacteristic .class ).invoke (service ,
447
+ characteristic .get ());
448
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e ) {
449
+ // This should never happen; all services should support NameCharacteristic as an optional
450
+ // Characteristic.
451
+ // If HAP-Java defined a service that doesn't support addOptionalCharacteristic(NameCharacteristic),
452
+ // Then it's a bug there, and we're just going to ignore the exception here.
453
+ }
454
+ }
455
+ }
456
+
359
457
@ NonNullByDefault
360
458
public <T > Optional <T > getCharacteristic (Class <? extends T > klazz ) {
361
459
return Optional .ofNullable ((T ) rawCharacteristics .get (klazz ));
0 commit comments