@@ -37,6 +37,7 @@ final class DeviceManagerImpl extends IDeviceManager {
3737
3838 // event subscriptions
3939 late final StreamSubscription <UnboundDeviceDiscoveredEvent > _unboundDeviceDiscoveredEventSub;
40+ late final StreamSubscription <KnownDeviceDiscoveryUpdatedEvent > _knownDeviceDiscoveryUpdatedEventSub;
4041 late final StreamSubscription <CurrentSceneChangedEvent > _currentSceneChangedEventSub;
4142
4243 // WotThing management
@@ -58,6 +59,9 @@ final class DeviceManagerImpl extends IDeviceManager {
5859 _unboundDeviceDiscoveredEventSub = allDeviceEvents.on < UnboundDeviceDiscoveredEvent > ().listen (
5960 _onUnboundDeviceDiscovered,
6061 );
62+ _knownDeviceDiscoveryUpdatedEventSub = allDeviceEvents.on < KnownDeviceDiscoveryUpdatedEvent > ().listen (
63+ _onKnownDeviceDiscoveryUpdated,
64+ );
6165
6266 // Listen for scene changes to manage WotThing lifecycle
6367 _currentSceneChangedEventSub = _globalBus.on < CurrentSceneChangedEvent > ().listen (_onCurrentSceneChanged);
@@ -105,6 +109,7 @@ final class DeviceManagerImpl extends IDeviceManager {
105109 void dispose () {
106110 if (! _isDisposed) {
107111 _unboundDeviceDiscoveredEventSub.cancel ();
112+ _knownDeviceDiscoveryUpdatedEventSub.cancel ();
108113 _currentSceneChangedEventSub.cancel ();
109114
110115 _disposeAllWotThings ();
@@ -191,13 +196,29 @@ final class DeviceManagerImpl extends IDeviceManager {
191196 @override
192197 Future <void > update (String id, {Transaction ? tx, String ? name, String ? groupID}) async {
193198 if (tx == null ) {
194- return await _db.transaction ((tx) => _update (id, tx: tx, name: name, groupID: groupID));
199+ await _db.transaction ((tx) async {
200+ await _update (id, tx: tx, name: name, groupID: groupID);
201+ });
195202 } else {
196203 await _update (id, tx: tx, name: name, groupID: groupID);
197204 }
198205 }
199206
200- Future <void > _update (String id, {required Transaction tx, String ? name, String ? groupID}) async {
207+ @override
208+ Future <void > updateAddress (String id, Uri address, {CancellationToken ? cancelToken}) async {
209+ final updatedEntity = await _db
210+ .transaction ((tx) => _update (id, tx: tx, address: address))
211+ .asCancellable (cancelToken);
212+ await _refreshKernelRegistration (updatedEntity, cancelToken: cancelToken);
213+ }
214+
215+ Future <DeviceEntity > _update (
216+ String id, {
217+ required Transaction tx,
218+ String ? name,
219+ String ? groupID,
220+ Uri ? address,
221+ }) async {
201222 final store = stringMapStoreFactory.store (StoreNames .devices);
202223 final originalRecord = await store.record (id).get (tx);
203224 if (originalRecord == null ) {
@@ -212,10 +233,14 @@ final class DeviceManagerImpl extends IDeviceManager {
212233 if (groupID != null ) {
213234 fieldsToUpdate[DeviceEntity .kGroupIDFieldName] = groupID;
214235 }
236+ if (address != null ) {
237+ fieldsToUpdate[DeviceEntity .kAddressFieldName] = address.toString ();
238+ }
215239
216240 final updatedRecord = await store.record (id).update (tx, fieldsToUpdate);
217241 final updatedEntity = DeviceEntity .fromMap (id, updatedRecord! );
218242 allDeviceEvents.fire (DeviceEntityUpdatedEvent (oldEntity, updatedEntity));
243+ return updatedEntity;
219244 }
220245
221246 Future <bool > _groupExists (Transaction tx, String groupID) async {
@@ -226,15 +251,15 @@ final class DeviceManagerImpl extends IDeviceManager {
226251
227252 @override
228253 Future <void > moveToGroup (String id, String newGroupID) async {
229- return await _db.transaction ((tx) async {
254+ await _db.transaction ((tx) async {
230255 // Allow empty string for ungrouped devices
231256 if (newGroupID.isNotEmpty) {
232257 final exists = await _groupExists (tx, newGroupID);
233258 if (! exists) {
234259 throw KeyNotFoundException (message: 'Cannot find group with ID `$newGroupID `' );
235260 }
236261 }
237- return await _update (id, tx: tx, groupID: newGroupID);
262+ await _update (id, tx: tx, groupID: newGroupID);
238263 });
239264 }
240265
@@ -367,22 +392,47 @@ final class DeviceManagerImpl extends IDeviceManager {
367392
368393 return await _db.transaction ((tx) async {
369394 final existed = await singleOrDefaultByFingerprint (event.matched.fingerprint, tx: tx);
370- if (existed != null ) {
371- final updates = < String , dynamic > {};
372- if (event.matched.address != existed.address) {
373- updates[DeviceEntity .kAddressFieldName] = event.matched.address.toString ();
374- }
375- if (updates.isNotEmpty) {
376- final store = stringMapStoreFactory.store (StoreNames .devices);
377- final record = store.record (existed.id);
378- await record.update (tx, updates);
379- }
380- } else {
395+ if (existed == null ) {
381396 allDeviceEvents.fire (NewDeviceFoundEvent (event.matched));
382397 }
383398 });
384399 }
385400
401+ Future <void > _onKnownDeviceDiscoveryUpdated (KnownDeviceDiscoveryUpdatedEvent event) async {
402+ logger? .i ('Known device discovery updated: ${event .device .id } -> ${event .matched .address }' );
403+ assert (isInitialized);
404+
405+ if (event.device.address == event.matched.address) {
406+ return ;
407+ }
408+
409+ await updateAddress (event.device.id, event.matched.address);
410+ }
411+
412+ Future <void > _refreshKernelRegistration (DeviceEntity updatedEntity, {CancellationToken ? cancelToken}) async {
413+ final wasBound = _kernel.boundDevices.any ((bound) => bound.device.id == updatedEntity.id);
414+
415+ _kernel.enterHeartbeatBatch ();
416+ try {
417+ await _deviceOperLock
418+ .synchronized (() async {
419+ if (wasBound) {
420+ await _kernel.unbind (updatedEntity.id, cancelToken: cancelToken);
421+ }
422+
423+ _kernel.unregisterDevice (updatedEntity.id);
424+ _kernel.registerDevice (BoundDeviceDescriptor (device: updatedEntity, driverID: updatedEntity.driverID));
425+
426+ if (wasBound) {
427+ await _kernel.tryBind (updatedEntity, updatedEntity.driverID, cancelToken: cancelToken);
428+ }
429+ })
430+ .asCancellable (cancelToken);
431+ } finally {
432+ _kernel.exitHeartbeatBatch ();
433+ }
434+ }
435+
386436 @override
387437 WotThing getWotThing (String deviceID) {
388438 // Only return WotThings for devices that are already loaded (current scene)
0 commit comments