@@ -36,6 +36,8 @@ public class HomekitRoot {
36
36
private final SubscriptionManager subscriptions = new SubscriptionManager ();
37
37
private boolean started = false ;
38
38
private int configurationIndex = 1 ;
39
+ private int nestedBatches = 0 ;
40
+ private boolean madeChanges = false ;
39
41
40
42
HomekitRoot (
41
43
String label , HomekitWebHandler webHandler , InetAddress host , HomekitAuthInfo authInfo )
@@ -65,7 +67,7 @@ public class HomekitRoot {
65
67
this .authInfo = authInfo ;
66
68
this .label = label ;
67
69
this .category = category ;
68
- this .registry = new HomekitRegistry (label );
70
+ this .registry = new HomekitRegistry (label , subscriptions );
69
71
}
70
72
71
73
HomekitRoot (
@@ -83,11 +85,27 @@ public class HomekitRoot {
83
85
this (
84
86
label , DEFAULT_ACCESSORY_CATEGORY , webHandler , authInfo , new JmdnsHomekitAdvertiser (jmdns ));
85
87
}
88
+
86
89
/**
87
- * Add an accessory to be handled and advertised by this root. Any existing HomeKit connections
88
- * will be terminated to allow the clients to reconnect and see the updated accessory list. When
89
- * using this for a bridge, the ID of the accessory must be greater than 1, as that ID is reserved
90
- * for the Bridge itself.
90
+ * Begin a batch update of accessories.
91
+ *
92
+ * <p>After calling this, you can call addAccessory() and removeAccessory() multiple times without
93
+ * causing HAP-Java to re-publishing the metadata to HomeKit. You'll need to call
94
+ * completeUpdateBatch in order to publish all accumulated changes.
95
+ */
96
+ public synchronized void batchUpdate () {
97
+ if (this .nestedBatches == 0 ) madeChanges = false ;
98
+ ++this .nestedBatches ;
99
+ }
100
+
101
+ /** Publish accumulated accessory changes since batchUpdate() was called. */
102
+ public synchronized void completeUpdateBatch () {
103
+ if (--this .nestedBatches == 0 && madeChanges ) registry .reset ();
104
+ }
105
+
106
+ /**
107
+ * Add an accessory to be handled and advertised by this root. When using this for a bridge, the
108
+ * ID of the accessory must be greater than 1, as that ID is reserved for the Bridge itself.
91
109
*
92
110
* @param accessory to advertise and handle.
93
111
*/
@@ -110,25 +128,28 @@ void addAccessorySkipRangeCheck(HomekitAccessory accessory) {
110
128
if (logger .isTraceEnabled ()) {
111
129
accessory .getName ().thenAccept (name -> logger .trace ("Added accessory {}" , name ));
112
130
}
113
- if (started ) {
131
+ madeChanges = true ;
132
+ if (started && nestedBatches == 0 ) {
114
133
registry .reset ();
115
134
}
116
135
}
117
136
118
137
/**
119
- * Removes an accessory from being handled or advertised by this root. Any existing HomeKit
120
- * connections will be terminated to allow the clients to reconnect and see the updated accessory
121
- * list.
138
+ * Removes an accessory from being handled or advertised by this root.
122
139
*
123
140
* @param accessory accessory to cease advertising and handling
124
141
*/
125
142
public void removeAccessory (HomekitAccessory accessory ) {
126
- this .registry .remove (accessory );
127
- if (logger .isTraceEnabled ()) {
128
- accessory .getName ().thenAccept (name -> logger .trace ("Removed accessory {}" , name ));
129
- }
130
- if (started ) {
131
- registry .reset ();
143
+ if (this .registry .remove (accessory )) {
144
+ if (logger .isTraceEnabled ()) {
145
+ accessory .getName ().thenAccept (name -> logger .trace ("Removed accessory {}" , name ));
146
+ }
147
+ madeChanges = true ;
148
+ if (started && nestedBatches == 0 ) {
149
+ registry .reset ();
150
+ }
151
+ } else {
152
+ accessory .getName ().thenAccept (name -> logger .warn ("Could not remove accessory {}" , name ));
132
153
}
133
154
}
134
155
@@ -140,6 +161,7 @@ public void removeAccessory(HomekitAccessory accessory) {
140
161
*/
141
162
public void start () {
142
163
started = true ;
164
+ madeChanges = false ;
143
165
registry .reset ();
144
166
webHandler
145
167
.start (
0 commit comments